summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorgshapiro <gshapiro@FreeBSD.org>2002-02-17 21:56:45 +0000
committergshapiro <gshapiro@FreeBSD.org>2002-02-17 21:56:45 +0000
commit8449595fe97f4474b9b9a7e4edee1ef35dcff393 (patch)
treee7a33b132264d449a512ddf4a8685df097669c1d /contrib
parent289b381b31415647269c7520d881017e2dcb27f1 (diff)
downloadFreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.zip
FreeBSD-src-8449595fe97f4474b9b9a7e4edee1ef35dcff393.tar.gz
Import sendmail 8.12.2
Diffstat (limited to 'contrib')
-rw-r--r--contrib/sendmail/INSTALL25
-rw-r--r--contrib/sendmail/KNOWNBUGS40
-rw-r--r--contrib/sendmail/LICENSE2
-rw-r--r--contrib/sendmail/Makefile14
-rw-r--r--contrib/sendmail/PGPKEYS76
-rw-r--r--contrib/sendmail/README36
-rw-r--r--contrib/sendmail/RELEASE_NOTES914
-rw-r--r--contrib/sendmail/cf/README1470
-rw-r--r--contrib/sendmail/cf/cf/Makefile54
-rw-r--r--contrib/sendmail/cf/cf/README34
-rw-r--r--contrib/sendmail/cf/cf/generic-hpux10.mc2
-rw-r--r--contrib/sendmail/cf/cf/generic-mpeix.mc25
-rw-r--r--contrib/sendmail/cf/cf/generic-solaris.mc29
-rw-r--r--contrib/sendmail/cf/cf/knecht.mc144
-rw-r--r--contrib/sendmail/cf/cf/submit.cf1369
-rw-r--r--contrib/sendmail/cf/cf/submit.mc22
-rw-r--r--contrib/sendmail/cf/cf/tcpproto.mc2
-rw-r--r--contrib/sendmail/cf/feature/access_db.m424
-rw-r--r--contrib/sendmail/cf/feature/allmasquerade.m410
-rw-r--r--contrib/sendmail/cf/feature/always_add_domain.m49
-rw-r--r--contrib/sendmail/cf/feature/authinfo.m422
-rw-r--r--contrib/sendmail/cf/feature/bestmx_is_local.m46
-rw-r--r--contrib/sendmail/cf/feature/bitdomain.m48
-rw-r--r--contrib/sendmail/cf/feature/compat_check.m433
-rw-r--r--contrib/sendmail/cf/feature/delay_checks.m45
-rw-r--r--contrib/sendmail/cf/feature/dnsbl.m415
-rw-r--r--contrib/sendmail/cf/feature/domaintable.m48
-rw-r--r--contrib/sendmail/cf/feature/enhdnsbl.m444
-rw-r--r--contrib/sendmail/cf/feature/genericstable.m48
-rw-r--r--contrib/sendmail/cf/feature/ldap_routing.m49
-rw-r--r--contrib/sendmail/cf/feature/local_lmtp.m45
-rw-r--r--contrib/sendmail/cf/feature/local_no_masquerade.m418
-rw-r--r--contrib/sendmail/cf/feature/lookupdotdomain.m422
-rw-r--r--contrib/sendmail/cf/feature/mailertable.m48
-rw-r--r--contrib/sendmail/cf/feature/msp.m476
-rw-r--r--contrib/sendmail/cf/feature/no_default_msa.m42
-rw-r--r--contrib/sendmail/cf/feature/nullclient.m42
-rw-r--r--contrib/sendmail/cf/feature/preserve_local_plus_detail.m416
-rw-r--r--contrib/sendmail/cf/feature/preserve_luser_host.m419
-rw-r--r--contrib/sendmail/cf/feature/promiscuous_relay.m47
-rw-r--r--contrib/sendmail/cf/feature/queuegroup.m427
-rw-r--r--contrib/sendmail/cf/feature/relay_local_from.m48
-rw-r--r--contrib/sendmail/cf/feature/relay_mail_from.m49
-rw-r--r--contrib/sendmail/cf/feature/use_ct_file.m49
-rw-r--r--contrib/sendmail/cf/feature/use_cw_file.m410
-rw-r--r--contrib/sendmail/cf/feature/uucpdomain.m48
-rw-r--r--contrib/sendmail/cf/feature/virtusertable.m48
-rw-r--r--contrib/sendmail/cf/m4/cfhead.m476
-rw-r--r--contrib/sendmail/cf/m4/proto.m41341
-rw-r--r--contrib/sendmail/cf/m4/version.m46
-rw-r--r--contrib/sendmail/cf/mailer/cyrus.m412
-rw-r--r--contrib/sendmail/cf/mailer/fax.m47
-rw-r--r--contrib/sendmail/cf/mailer/local.m442
-rw-r--r--contrib/sendmail/cf/mailer/mail11.m417
-rw-r--r--contrib/sendmail/cf/mailer/phquery.m410
-rw-r--r--contrib/sendmail/cf/mailer/pop.m410
-rw-r--r--contrib/sendmail/cf/mailer/procmail.m410
-rw-r--r--contrib/sendmail/cf/mailer/qpage.m47
-rw-r--r--contrib/sendmail/cf/mailer/smtp.m441
-rw-r--r--contrib/sendmail/cf/mailer/usenet.m410
-rw-r--r--contrib/sendmail/cf/mailer/uucp.m435
-rw-r--r--contrib/sendmail/cf/ostype/a-ux.m421
-rw-r--r--contrib/sendmail/cf/ostype/aix5.m42
-rw-r--r--contrib/sendmail/cf/ostype/darwin.m42
-rw-r--r--contrib/sendmail/cf/ostype/freebsd5.m420
-rw-r--r--contrib/sendmail/cf/ostype/linux.m42
-rw-r--r--contrib/sendmail/cf/ostype/mklinux.m42
-rw-r--r--contrib/sendmail/cf/ostype/mpeix.m422
-rw-r--r--contrib/sendmail/cf/ostype/solaris8.m42
-rw-r--r--contrib/sendmail/cf/sendmail.schema216
-rwxr-xr-xcontrib/sendmail/contrib/buildvirtuser2
-rw-r--r--contrib/sendmail/contrib/dnsblaccess.m494
-rw-r--r--contrib/sendmail/contrib/domainmap.m48
-rw-r--r--contrib/sendmail/contrib/link_hash.sh2
-rw-r--r--contrib/sendmail/contrib/qtool.866
-rwxr-xr-xcontrib/sendmail/contrib/qtool.pl124
-rw-r--r--contrib/sendmail/doc/op/Makefile10
-rw-r--r--contrib/sendmail/doc/op/op.me2135
-rw-r--r--contrib/sendmail/editmap/Makefile17
-rw-r--r--contrib/sendmail/editmap/Makefile.m422
-rw-r--r--contrib/sendmail/editmap/editmap.8106
-rw-r--r--contrib/sendmail/editmap/editmap.c420
-rw-r--r--contrib/sendmail/include/libmilter/mfapi.h82
-rw-r--r--contrib/sendmail/include/libmilter/mfdef.h84
-rw-r--r--contrib/sendmail/include/libmilter/milter.h60
-rw-r--r--contrib/sendmail/include/libsmdb/smdb.h135
-rw-r--r--contrib/sendmail/include/sendmail/mailstats.h11
-rw-r--r--contrib/sendmail/include/sendmail/pathnames.h64
-rw-r--r--contrib/sendmail/include/sendmail/sendmail.h103
-rw-r--r--contrib/sendmail/include/sm/assert.h113
-rw-r--r--contrib/sendmail/include/sm/bitops.h57
-rw-r--r--contrib/sendmail/include/sm/cdefs.h142
-rw-r--r--contrib/sendmail/include/sm/cf.h29
-rw-r--r--contrib/sendmail/include/sm/clock.h81
-rw-r--r--contrib/sendmail/include/sm/conf.h2803
-rw-r--r--contrib/sendmail/include/sm/config.h146
-rw-r--r--contrib/sendmail/include/sm/debug.h141
-rw-r--r--contrib/sendmail/include/sm/errstring.h79
-rw-r--r--contrib/sendmail/include/sm/exc.h186
-rw-r--r--contrib/sendmail/include/sm/fdset.h19
-rw-r--r--contrib/sendmail/include/sm/gen.h79
-rw-r--r--contrib/sendmail/include/sm/heap.h101
-rw-r--r--contrib/sendmail/include/sm/io.h382
-rw-r--r--contrib/sendmail/include/sm/ldap.h112
-rw-r--r--contrib/sendmail/include/sm/limits.h55
-rw-r--r--contrib/sendmail/include/sm/mbdb.h43
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_aix.h35
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_freebsd.h41
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_hp.h34
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_irix.h55
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_linux.h42
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_mpeix.h34
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_next.h29
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_openbsd.h30
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_openunix.h25
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_osf1.h18
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_sunos.h70
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_ultrix.h18
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_unixware.h32
-rw-r--r--contrib/sendmail/include/sm/path.h32
-rw-r--r--contrib/sendmail/include/sm/rpool.h185
-rw-r--r--contrib/sendmail/include/sm/setjmp.h46
-rw-r--r--contrib/sendmail/include/sm/shm.h42
-rw-r--r--contrib/sendmail/include/sm/signal.h81
-rw-r--r--contrib/sendmail/include/sm/string.h135
-rw-r--r--contrib/sendmail/include/sm/sysexits.h109
-rw-r--r--contrib/sendmail/include/sm/test.h46
-rw-r--r--contrib/sendmail/include/sm/types.h65
-rw-r--r--contrib/sendmail/include/sm/varargs.h45
-rw-r--r--contrib/sendmail/include/sm/xtrap.h38
-rw-r--r--contrib/sendmail/libmilter/Makefile.m422
-rw-r--r--contrib/sendmail/libmilter/README85
-rw-r--r--contrib/sendmail/libmilter/comm.c47
-rw-r--r--contrib/sendmail/libmilter/docs/api.html194
-rw-r--r--contrib/sendmail/libmilter/docs/design.html144
-rw-r--r--contrib/sendmail/libmilter/docs/figure1.fig56
-rw-r--r--contrib/sendmail/libmilter/docs/figure1.jpgbin0 -> 21406 bytes
-rw-r--r--contrib/sendmail/libmilter/docs/figure1.ps173
-rw-r--r--contrib/sendmail/libmilter/docs/figure2.fig67
-rw-r--r--contrib/sendmail/libmilter/docs/figure2.jpgbin0 -> 47947 bytes
-rw-r--r--contrib/sendmail/libmilter/docs/figure2.ps242
-rw-r--r--contrib/sendmail/libmilter/docs/index.html92
-rw-r--r--contrib/sendmail/libmilter/docs/installation.html169
-rw-r--r--contrib/sendmail/libmilter/docs/other.html15
-rw-r--r--contrib/sendmail/libmilter/docs/overview.html194
-rw-r--r--contrib/sendmail/libmilter/docs/sample.html426
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_addheader.html94
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_addrcpt.html80
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_chgheader.html96
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_delrcpt.html79
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_getpriv.html59
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_getsymval.html92
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_main.html48
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_register.html160
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_replacebody.html90
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_setconn.html77
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_setpriv.html77
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_setreply.html92
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_settimeout.html60
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_abort.html80
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_body.html80
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_close.html66
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_connect.html90
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_envfrom.html92
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_envrcpt.html94
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_eoh.html53
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_eom.html58
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_header.html74
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_helo.html59
-rw-r--r--contrib/sendmail/libmilter/engine.c153
-rw-r--r--contrib/sendmail/libmilter/handler.c9
-rw-r--r--contrib/sendmail/libmilter/libmilter.h36
-rw-r--r--contrib/sendmail/libmilter/listener.c216
-rw-r--r--contrib/sendmail/libmilter/main.c80
-rw-r--r--contrib/sendmail/libmilter/signal.c41
-rw-r--r--contrib/sendmail/libmilter/sm_gethost.c45
-rw-r--r--contrib/sendmail/libmilter/smfi.c232
-rw-r--r--contrib/sendmail/libsm/Makefile17
-rw-r--r--contrib/sendmail/libsm/Makefile.m436
-rw-r--r--contrib/sendmail/libsm/README126
-rw-r--r--contrib/sendmail/libsm/assert.c187
-rw-r--r--contrib/sendmail/libsm/assert.html359
-rw-r--r--contrib/sendmail/libsm/b-strcmp.c148
-rw-r--r--contrib/sendmail/libsm/b-strl.c202
-rw-r--r--contrib/sendmail/libsm/cdefs.html107
-rw-r--r--contrib/sendmail/libsm/cf.c100
-rw-r--r--contrib/sendmail/libsm/clock.c516
-rw-r--r--contrib/sendmail/libsm/clrerr.c39
-rw-r--r--contrib/sendmail/libsm/config.c239
-rw-r--r--contrib/sendmail/libsm/debug.c368
-rw-r--r--contrib/sendmail/libsm/debug.html276
-rw-r--r--contrib/sendmail/libsm/errstring.c206
-rw-r--r--contrib/sendmail/libsm/exc.c669
-rw-r--r--contrib/sendmail/libsm/exc.html757
-rw-r--r--contrib/sendmail/libsm/fclose.c149
-rw-r--r--contrib/sendmail/libsm/feof.c42
-rw-r--r--contrib/sendmail/libsm/ferror.c41
-rw-r--r--contrib/sendmail/libsm/fflush.c151
-rw-r--r--contrib/sendmail/libsm/fget.c110
-rw-r--r--contrib/sendmail/libsm/findfp.c428
-rw-r--r--contrib/sendmail/libsm/flags.c61
-rw-r--r--contrib/sendmail/libsm/fopen.c372
-rw-r--r--contrib/sendmail/libsm/fpos.c152
-rw-r--r--contrib/sendmail/libsm/fprintf.c55
-rw-r--r--contrib/sendmail/libsm/fpurge.c53
-rw-r--r--contrib/sendmail/libsm/fput.c52
-rw-r--r--contrib/sendmail/libsm/fread.c100
-rw-r--r--contrib/sendmail/libsm/fscanf.c55
-rw-r--r--contrib/sendmail/libsm/fseek.c335
-rw-r--r--contrib/sendmail/libsm/fvwrite.c279
-rw-r--r--contrib/sendmail/libsm/fvwrite.h30
-rw-r--r--contrib/sendmail/libsm/fwalk.c61
-rw-r--r--contrib/sendmail/libsm/fwrite.c67
-rw-r--r--contrib/sendmail/libsm/gen.html43
-rw-r--r--contrib/sendmail/libsm/get.c46
-rw-r--r--contrib/sendmail/libsm/glue.h27
-rw-r--r--contrib/sendmail/libsm/heap.c819
-rw-r--r--contrib/sendmail/libsm/heap.html424
-rw-r--r--contrib/sendmail/libsm/index.html174
-rw-r--r--contrib/sendmail/libsm/io.html745
-rw-r--r--contrib/sendmail/libsm/ldap.c961
-rw-r--r--contrib/sendmail/libsm/local.h340
-rw-r--r--contrib/sendmail/libsm/makebuf.c154
-rw-r--r--contrib/sendmail/libsm/match.c137
-rw-r--r--contrib/sendmail/libsm/mbdb.c746
-rw-r--r--contrib/sendmail/libsm/mpeix.c646
-rw-r--r--contrib/sendmail/libsm/niprop.c213
-rw-r--r--contrib/sendmail/libsm/path.c15
-rw-r--r--contrib/sendmail/libsm/put.c80
-rw-r--r--contrib/sendmail/libsm/refill.c294
-rw-r--r--contrib/sendmail/libsm/rewind.c44
-rw-r--r--contrib/sendmail/libsm/rpool.c493
-rw-r--r--contrib/sendmail/libsm/rpool.html187
-rw-r--r--contrib/sendmail/libsm/setvbuf.c190
-rw-r--r--contrib/sendmail/libsm/shm.c102
-rw-r--r--contrib/sendmail/libsm/signal.c340
-rw-r--r--contrib/sendmail/libsm/smstdio.c327
-rw-r--r--contrib/sendmail/libsm/snprintf.c86
-rw-r--r--contrib/sendmail/libsm/sscanf.c103
-rw-r--r--contrib/sendmail/libsm/stdio.c497
-rw-r--r--contrib/sendmail/libsm/strcasecmp.c106
-rw-r--r--contrib/sendmail/libsm/strdup.c72
-rw-r--r--contrib/sendmail/libsm/strerror.c60
-rw-r--r--contrib/sendmail/libsm/strexit.c127
-rw-r--r--contrib/sendmail/libsm/string.c56
-rw-r--r--contrib/sendmail/libsm/stringf.c86
-rw-r--r--contrib/sendmail/libsm/strio.c466
-rw-r--r--contrib/sendmail/libsm/strl.c321
-rw-r--r--contrib/sendmail/libsm/strrevcmp.c101
-rw-r--r--contrib/sendmail/libsm/strto.c254
-rw-r--r--contrib/sendmail/libsm/syslogio.c220
-rw-r--r--contrib/sendmail/libsm/t-cf.c46
-rw-r--r--contrib/sendmail/libsm/t-event.c85
-rw-r--r--contrib/sendmail/libsm/t-exc.c145
-rw-r--r--contrib/sendmail/libsm/t-float.c72
-rw-r--r--contrib/sendmail/libsm/t-fopen.c34
-rw-r--r--contrib/sendmail/libsm/t-heap.c64
-rw-r--r--contrib/sendmail/libsm/t-match.c47
-rw-r--r--contrib/sendmail/libsm/t-path.c35
-rw-r--r--contrib/sendmail/libsm/t-rpool.c69
-rw-r--r--contrib/sendmail/libsm/t-scanf.c59
-rw-r--r--contrib/sendmail/libsm/t-shm.c266
-rw-r--r--contrib/sendmail/libsm/t-smstdio.c75
-rw-r--r--contrib/sendmail/libsm/t-string.c46
-rw-r--r--contrib/sendmail/libsm/t-strio.c33
-rw-r--r--contrib/sendmail/libsm/t-strl.c136
-rw-r--r--contrib/sendmail/libsm/t-strrevcmp.c53
-rw-r--r--contrib/sendmail/libsm/t-types.c103
-rw-r--r--contrib/sendmail/libsm/test.c155
-rw-r--r--contrib/sendmail/libsm/ungetc.c179
-rw-r--r--contrib/sendmail/libsm/vasprintf.c115
-rw-r--r--contrib/sendmail/libsm/vfprintf.c1107
-rw-r--r--contrib/sendmail/libsm/vfscanf.c874
-rw-r--r--contrib/sendmail/libsm/vprintf.c39
-rw-r--r--contrib/sendmail/libsm/vsnprintf.c78
-rw-r--r--contrib/sendmail/libsm/vsprintf.c66
-rw-r--r--contrib/sendmail/libsm/vsscanf.c88
-rw-r--r--contrib/sendmail/libsm/wbuf.c88
-rw-r--r--contrib/sendmail/libsm/wsetup.c82
-rw-r--r--contrib/sendmail/libsm/xtrap.c21
-rw-r--r--contrib/sendmail/libsmdb/Makefile.m41
-rw-r--r--contrib/sendmail/libsmdb/smdb.c93
-rw-r--r--contrib/sendmail/libsmdb/smdb1.c74
-rw-r--r--contrib/sendmail/libsmdb/smdb2.c69
-rw-r--r--contrib/sendmail/libsmdb/smndbm.c64
-rw-r--r--contrib/sendmail/libsmutil/Makefile.m43
-rw-r--r--contrib/sendmail/libsmutil/cf.c71
-rw-r--r--contrib/sendmail/libsmutil/debug.c31
-rw-r--r--contrib/sendmail/libsmutil/err.c63
-rw-r--r--contrib/sendmail/libsmutil/lockfile.c23
-rw-r--r--contrib/sendmail/libsmutil/safefile.c245
-rw-r--r--contrib/sendmail/libsmutil/snprintf.c386
-rw-r--r--contrib/sendmail/mail.local/Makefile.m45
-rw-r--r--contrib/sendmail/mail.local/README8
-rw-r--r--contrib/sendmail/mail.local/mail.local.833
-rw-r--r--contrib/sendmail/mail.local/mail.local.c614
-rw-r--r--contrib/sendmail/mailstats/Makefile.m42
-rw-r--r--contrib/sendmail/mailstats/mailstats.813
-rw-r--r--contrib/sendmail/mailstats/mailstats.c205
-rw-r--r--contrib/sendmail/makemap/Makefile.m42
-rw-r--r--contrib/sendmail/makemap/makemap.822
-rw-r--r--contrib/sendmail/makemap/makemap.c274
-rw-r--r--contrib/sendmail/praliases/Makefile.m42
-rw-r--r--contrib/sendmail/praliases/praliases.84
-rw-r--r--contrib/sendmail/praliases/praliases.c154
-rw-r--r--contrib/sendmail/rmail/Makefile.m45
-rw-r--r--contrib/sendmail/rmail/rmail.86
-rw-r--r--contrib/sendmail/rmail/rmail.c186
-rw-r--r--contrib/sendmail/smrsh/Makefile.m43
-rw-r--r--contrib/sendmail/smrsh/README4
-rw-r--r--contrib/sendmail/smrsh/smrsh.810
-rw-r--r--contrib/sendmail/smrsh/smrsh.c141
-rw-r--r--contrib/sendmail/src/Makefile.m443
-rw-r--r--contrib/sendmail/src/README361
-rw-r--r--contrib/sendmail/src/SECURITY192
-rw-r--r--contrib/sendmail/src/TRACEFLAGS10
-rw-r--r--contrib/sendmail/src/TUNING232
-rw-r--r--contrib/sendmail/src/alias.c329
-rw-r--r--contrib/sendmail/src/aliases45
-rw-r--r--contrib/sendmail/src/aliases.54
-rw-r--r--contrib/sendmail/src/arpadate.c9
-rw-r--r--contrib/sendmail/src/bf.c846
-rw-r--r--contrib/sendmail/src/bf.h30
-rw-r--r--contrib/sendmail/src/collect.c714
-rw-r--r--contrib/sendmail/src/conf.c2518
-rw-r--r--contrib/sendmail/src/conf.h2733
-rw-r--r--contrib/sendmail/src/control.c167
-rw-r--r--contrib/sendmail/src/convtime.c43
-rw-r--r--contrib/sendmail/src/daemon.c2508
-rw-r--r--contrib/sendmail/src/deliver.c2860
-rw-r--r--contrib/sendmail/src/domain.c536
-rw-r--r--contrib/sendmail/src/envelope.c653
-rw-r--r--contrib/sendmail/src/err.c421
-rw-r--r--contrib/sendmail/src/headers.c466
-rw-r--r--contrib/sendmail/src/helpfile6
-rw-r--r--contrib/sendmail/src/macro.c350
-rw-r--r--contrib/sendmail/src/mailq.16
-rw-r--r--contrib/sendmail/src/main.c3033
-rw-r--r--contrib/sendmail/src/map.c3298
-rw-r--r--contrib/sendmail/src/mci.c522
-rw-r--r--contrib/sendmail/src/milter.c1310
-rw-r--r--contrib/sendmail/src/mime.c253
-rw-r--r--contrib/sendmail/src/newaliases.115
-rw-r--r--contrib/sendmail/src/parseaddr.c1233
-rw-r--r--contrib/sendmail/src/queue.c6910
-rw-r--r--contrib/sendmail/src/readcf.c1489
-rw-r--r--contrib/sendmail/src/recipient.c1196
-rw-r--r--contrib/sendmail/src/sasl.c208
-rw-r--r--contrib/sendmail/src/savemail.c622
-rw-r--r--contrib/sendmail/src/sendmail.878
-rw-r--r--contrib/sendmail/src/sendmail.h1415
-rw-r--r--contrib/sendmail/src/sfsasl.c827
-rw-r--r--contrib/sendmail/src/sfsasl.h49
-rw-r--r--contrib/sendmail/src/shmticklib.c18
-rw-r--r--contrib/sendmail/src/sm_resolve.c411
-rw-r--r--contrib/sendmail/src/sm_resolve.h142
-rw-r--r--contrib/sendmail/src/srvrsmtp.c4361
-rw-r--r--contrib/sendmail/src/stab.c248
-rw-r--r--contrib/sendmail/src/stats.c85
-rw-r--r--contrib/sendmail/src/statusd_shm.h13
-rw-r--r--contrib/sendmail/src/sysexits.c76
-rw-r--r--contrib/sendmail/src/timers.c23
-rw-r--r--contrib/sendmail/src/timers.h6
-rw-r--r--contrib/sendmail/src/tls.c1469
-rw-r--r--contrib/sendmail/src/trace.c210
-rw-r--r--contrib/sendmail/src/udb.c286
-rw-r--r--contrib/sendmail/src/usersmtp.c1721
-rw-r--r--contrib/sendmail/src/util.c1549
-rw-r--r--contrib/sendmail/src/version.c10
-rw-r--r--contrib/sendmail/test/Makefile17
-rw-r--r--contrib/sendmail/test/Makefile.m418
-rw-r--r--contrib/sendmail/test/README27
-rw-r--r--contrib/sendmail/test/Results40
-rw-r--r--contrib/sendmail/test/t_dropgid.c154
-rw-r--r--contrib/sendmail/test/t_exclopen.c12
-rw-r--r--contrib/sendmail/test/t_pathconf.c12
-rw-r--r--contrib/sendmail/test/t_seteuid.c24
-rw-r--r--contrib/sendmail/test/t_setgid.c119
-rw-r--r--contrib/sendmail/test/t_setreuid.c40
-rw-r--r--contrib/sendmail/test/t_setuid.c24
-rw-r--r--contrib/sendmail/test/t_snprintf.c14
-rw-r--r--contrib/sendmail/vacation/Makefile.m42
-rw-r--r--contrib/sendmail/vacation/vacation.167
-rw-r--r--contrib/sendmail/vacation/vacation.c461
384 files changed, 72206 insertions, 22730 deletions
diff --git a/contrib/sendmail/INSTALL b/contrib/sendmail/INSTALL
index 3286207..96558c5 100644
--- a/contrib/sendmail/INSTALL
+++ b/contrib/sendmail/INSTALL
@@ -1,9 +1,10 @@
Installing sendmail
-Note: as of sendmail 8.9, a new build architecture is in place that allows
-you to use the "Build" shell script in any of the program directories.
-On many environments this will do everything for you, no fuss, no muss.
+**Note**: Starting with sendmail 8.12, sendmail is no longer set-user-ID
+root by default. As a result of this, you need to install two .cf files.
+See steps 4 and 6 in this document. We also strongly recommend reading
+sendmail/SECURITY for more installation information.
1. Read all the README files noted in the INTRODUCTION section of the README
file in this top-level directory.
@@ -15,16 +16,22 @@ On many environments this will do everything for you, no fuss, no muss.
details).
4. Change to the cf/cf/ directory (that's not a typo): Copy whichever .mc
- file best matches your environment to config.mc, where config can be any
- name. Next, tailor it as explained in cf/README. Then run
- "sh Build config.cf".
+ file best matches your environment to sendmail.mc. Next, tailor it
+ as explained in cf/README. Then run
+ "sh Build sendmail.cf".
5. Back up your current /etc/mail/sendmail.cf and the sendmail binary (whose
location varies from operating system to operating system, but is usually
in /usr/sbin or /usr/lib).
-6. Install config.cf as /etc/mail/sendmail.cf and install the sendmail binary
- built in step 3 by cd-ing back to sendmail/ and running "sh Build install".
+6. Install sendmail.cf as /etc/mail/sendmail.cf and submit.cf as
+ /etc/mail/submit.cf. This can be done in the cf/cf by using
+ "sh Build install-cf".
+
+ Please read sendmail/SECURITY before continuing; you have to create a
+ new user smmsp and a new group smmsp for the default installation.
+ Then install the sendmail binary built in step 3 by cd-ing back to
+ sendmail/ and running "sh Build install".
7. For each of the associated sendmail utilities (makemap, mailstats, etc.),
read the README in the utility's directory. When you are ready to install
@@ -35,4 +42,4 @@ On many environments this will do everything for you, no fuss, no muss.
in case you are now using a different (and thereby incompatible) version
of Berkeley DB.
-$Revision: 8.3.16.2 $, Last updated $Date: 2000/12/30 06:24:03 $
+$Revision: 8.14 $, Last updated $Date: 2001/11/04 20:59:11 $
diff --git a/contrib/sendmail/KNOWNBUGS b/contrib/sendmail/KNOWNBUGS
index f3a42e7..0fa616b 100644
--- a/contrib/sendmail/KNOWNBUGS
+++ b/contrib/sendmail/KNOWNBUGS
@@ -3,7 +3,7 @@
K N O W N B U G S I N S E N D M A I L
-The following are bugs or deficiencies in sendmail that I am aware of
+The following are bugs or deficiencies in sendmail that we are aware of
but which have not been fixed in the current release. You probably
want to get the most up to date version of this from ftp.sendmail.org
in /pub/sendmail/KNOWNBUGS. For descriptions of bugs that have been
@@ -13,7 +13,6 @@ distribution).
This list is not guaranteed to be complete.
* Delivery to programs that generate too much output may cause problems
- (8.10, 8.11)
If e-mail is delivered to a program which generates too much
output, then sendmail may issue an error:
@@ -35,7 +34,7 @@ This list is not guaranteed to be complete.
restructuring of the code -- for example, almost no C library support
could be used to handle strings.
-* Header checks are not called if header value is too long.
+* Header checks are not called if header value is too long or empty.
If the value of a header is longer than 1250 (MAXNAME + MAXATOM - 6)
characters or it contains a single word longer than 256 (MAXNAME)
@@ -47,13 +46,12 @@ This list is not guaranteed to be complete.
Sometimes identical, duplicate error messages can be generated. As
near as I can tell, this is rare and relatively innocuous.
-* $c (hop count) macro improperly set.
+* Misleading error messages.
- The $c macro is supposed to contain the current hop count, for use
- when calling a mailer. This macro is initialized too early, and
- is always zero (or the value of the -c command line flag, if any).
- This macro will probably be removed entirely in a future release;
- I don't believe there are any mailers left that require it.
+ If an illegal address is specified on the command line together
+ with at least one valid address and PostmasterCopy is set, the
+ DSN does not contain the illegal address, but only the valid
+ address(es).
* \231 considered harmful.
@@ -121,6 +119,14 @@ This list is not guaranteed to be complete.
account for the SMTP on-the-wire \r\n expansion. It probably doesn't
allow for 8->7 bit MIME conversions either.
+* Client ignores SIZE parameter.
+
+ When sendmail acts as client and the server specifies a limit
+ for the mail size, sendmail will ignore this and try to send the
+ mail anyway. The server will usually reject the MAIL command
+ which specifies the size of the message and hence this problem
+ is not significant.
+
* Paths to programs being executed and the mode of program files are
not checked. Essentially, the RunProgramInUnsafeDirPath and
RunWritableProgram bits in the DontBlameSendmail option are always
@@ -150,7 +156,7 @@ This list is not guaranteed to be complete.
* MIME encoded full name phrases in the From: header
If a full name phrase includes characters from MustQuoteChars, sendmail
- will quote the entire full name phrase. If MustQuoteChars includes
+ will quote the entire full name phrase. If MustQuoteChars includes
characters which are not special characters according to STD 11 (RFC
822), this quotation can interfere with MIME encoded full name phrases.
By default, sendmail includes the single quote character (') in
@@ -200,22 +206,14 @@ This list is not guaranteed to be complete.
local mail delivery and NFS hard mounted home directories should be
avoided, as attempts to open the forward files could hang.
-* Race condition for delivery to set-user-id files
+* Race condition for delivery to set-user-ID files
Sendmail will deliver to a fail if the file is owned by the DefaultUser
- or has the set-user-id bit set. Unfortunately, some systems clear that bit
+ or has the set-user-ID bit set. Unfortunately, some systems clear that bit
when a file is modified. Sendmail compensates by resetting the file mode
back to it's original settings. Unfortunately, there's still a
permission failure race as sendmail checks the permissions before locking
the file. This is unavoidable as sendmail must verify the file is safe
to open before opening it. A file can not be locked until it is open.
-* Potential denial of service attack with AutoRebuildAliases
-
- There is a potential for a denial of service attack if the
- AutoRebuildAliases option is set as a user can kill the sendmail process
- while it is rebuilding the aliases file leaving it in an inconsistent
- state. This option and it's use is deprecated and will be removed from a
- future version of sendmail.
-
-$Revision: 8.43.16.2 $, Last updated $Date: 2001/07/31 22:42:46 $
+$Revision: 8.54 $, Last updated $Date: 2001/12/17 16:07:51 $
diff --git a/contrib/sendmail/LICENSE b/contrib/sendmail/LICENSE
index 0101f48..ea4a7da 100644
--- a/contrib/sendmail/LICENSE
+++ b/contrib/sendmail/LICENSE
@@ -76,4 +76,4 @@ each of the following conditions is met:
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-$Revision: 8.9.4.1 $, Last updated $Date: 2001/02/14 04:07:19 $
+$Revision: 8.10 $, Last updated $Date: 2001/02/14 04:39:34 $
diff --git a/contrib/sendmail/Makefile b/contrib/sendmail/Makefile
index 547e46d..97b2afc 100644
--- a/contrib/sendmail/Makefile
+++ b/contrib/sendmail/Makefile
@@ -1,8 +1,9 @@
-# $Id: Makefile.dist,v 8.9 1999/09/27 21:39:11 gshapiro Exp $
+# $Id: Makefile.dist,v 8.15 2001/08/23 20:44:39 ca Exp $
SHELL= /bin/sh
-SUBDIRS= libsmutil libsmdb sendmail mail.local mailstats makemap \
- praliases rmail smrsh vacation
+SUBDIRS= libsm libsmutil libsmdb sendmail editmap mail.local \
+ mailstats makemap praliases rmail smrsh vacation
+# libmilter: requires pthread
BUILD= ./Build
OPTIONS= $(CONFIG) $(FLAGS)
@@ -27,6 +28,13 @@ install: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@); \
done
+install-docs: FRC
+ @for x in $(SUBDIRS); \
+ do \
+ (cd $$x; echo Making $@ in:; pwd; \
+ $(SHELL) $(BUILD) $(OPTIONS) $@); \
+ done
+
fresh: FRC
@for x in $(SUBDIRS); \
do \
diff --git a/contrib/sendmail/PGPKEYS b/contrib/sendmail/PGPKEYS
index f77e4a7..11654e9 100644
--- a/contrib/sendmail/PGPKEYS
+++ b/contrib/sendmail/PGPKEYS
@@ -88,6 +88,80 @@ y+PVZ1MwnEXfTQReVSla0AAOIRirHEh4YnUVZzFSNEJqoDRZQwVd7Q==
-----END PGP PUBLIC KEY BLOCK-----
Type Bits KeyID Created Expires Algorithm Use
+sec+ 1024 0x678C0A03 2001-12-18 ---------- RSA Sign & Encrypt
+f16 Fingerprint16 = 7B 02 F4 AA FC C0 22 DA 47 3E 2A 9A 9B 35 22 45
+uid Sendmail Signing Key/2002 <sendmail@Sendmail.ORG>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGPfreeware 5.0i for non-commercial use
+
+mQCNAzwfgwEAAAEEALejONfYzPrNw5IhjBfjpkj1hCwVGCa91d0Pr9SyMgFdrEam
+v4jWiz80rFoKdm3dr1bDqBhdiq4tH49Rul+RLLEXLyiPiLyRoldl54cPeOUoGafp
+PvcCihSgWM2tFO1saYtf+/oM5/9S/TA+pb4hpXAZE4CfL4e7X4lpYrhnjAoDAAUR
+tDFTZW5kbWFpbCBTaWduaW5nIEtleS8yMDAyIDxzZW5kbWFpbEBTZW5kbWFpbC5P
+Ukc+iQCVAwUQPB+DAYlpYrhnjAoDAQFKqQP/YG77bGGhCqr8PxSpWSNxDuIPAmX4
+VJdLsIQNUBqI/3noPfTec3553EsXMUvJh/4iiI/+6CYExQi4WQELZDPmfUUWQWUA
+aiv6upSOKOAmuiVO2cjZzNaETswwyabk2rOE0RzmCuzMDCrkbFugoBRofuUjXwq6
+FAnTaM5LkAgprfaJAJUDBRA8H4OufEtnbaAOFWMBAWP3A/9Y4JqmHQtcz0t/kIcE
+ZwGwYd8+kyeo0/0voW07STq/C60hX3eFiegoqO6bqILIaswZ6djnYOMdOYhMtM+f
+VzcMNTyJCRe3KcWvY4xRQMYc+zmwqqxY1cW6F1mWLT6fwZ6hlIRG/A91OfIDbnuh
+WqNFOJR3NNMmC97nB3D36e4vWYkAlQMFEDwfg/jBnB0lEtNGHQEB9+sD/R6kEta/
+JNgmBhnVRheM5+4ijQpz9csP0Y2Ccd5C2BFkURQztRxgldaTRdmzAltjG49ZmgAj
+C15v0S5CunWI2gHNvNzh0odyKD5+FEcU2arz2TEqnEIzoDdAq4B6Qwf48EVBqtOa
+rIY6LoLV2/POFqTZvP2fzdp1kju6KpfMLgeniQCVAwUQPB+EB+9YlmTUMuGdAQEp
+fQP/faSN6UtxXPrEtnqF+9V+pEc77BJO6oa9lpI9Qdbupo1wqNtFH6ZmYhnLPD65
+qAFnyKZU6VW58ulobd5nZqISdTV0CorPJ1I+7zTS4IuZkiDg6/YCTzWdcgs7M7W5
+sI4mnDt4bPdIRvz0ffM8r6WmVQISuI78+9usnZMLGoJn2P+JAJUDBRA8H4Qmb1KT
+2KObplUBAduAA/oDRlld+jlosLu1TDZD9J9srEK7mdT3+HIVohcfkqpAhXXcZrvd
+avKucihNrCa+dj1u03A0xxMPQoeuFQRlL587M1sEtowVGuyMTyiVtut7zsta/eEQ
+nkp0MYTqNftkRxoc7vMx98tqO4Xlfe2mLekV8w7TUQxGVi9JFIBx6ZATUYkAlQMF
+EDwfhDWcHL3i41xWNQEBoGED+gIvGFmUUu7fkdEmaT559dapdxCCEJkV/dUZUrbo
+EmYtllCo0yNxzfBdXVwlBlHFV7fAW+QZRhCQx9TBv0JrNf/AJp4XIo837PmKhoJr
+C5UsbT5SIypBi9Ai8AX4HQrB5SQQMd53efjmsdOITtdM0Cp+/uMUVuO+7oFeEWtW
+MvxaiQCVAwUQPB+ESDgi20fMN08tAQHyUAP/ajusqW//1Z6622HWr8GTVpTua/YG
+H3qGW0ZdXoqnzUNBIc9lksOV62JL91pzfDWaTCqMTEYzT6W94e7n8SYFtbroemxb
+kdSb8DO3C4bOa1w1dJsQfTeRYEuIMVHtjJmqw43J7pNn2HazVcnPf95YkMhGvs4b
+P2zfvyWwhgRCbWOJAJUDBRA8H4SLwCnKQBb0zOkBAddvBACYxaTZc+HsPEMLpoHW
+QIsntukJgdT/onZcTFZiVNmA6bYyQ0VPTiZ27HN7LjHkVgtdyEQceKq4T3iQ670h
+/Pp0gwk4ZDpmA/k2oqgs4aE/C6KDy6nMCGaucJhC9I0/0EFD32skvkQ5fj65oeoC
+2r/coIoA44Jp6ikzGA8i5aXuyIkAlQMFEDwfhK7W4KH+T74q3QEBwXED/1TiGmh1
+lnvOLIyn2lG+HIM4fzjlU4EmEm9we+lTi/zKOz+3w/O+jZKPEeYXvhjFjEbWIYI7
+XGtJQalipU4+Uhwv+bIliwWpYlFs0Roi6L/mN3CKXN8S62TI8RdArRKtPH9OxvGv
+1AXnEM0DRFuvcRVEBkUlnZKEit+8ttu5rIx5iQCVAwUQPB+Igs8etQMiMnoBAQE7
+hwQAtxoIqHHKs2IG8tTiNcjgfReeXovMeGttNua6rd6m2f8hA/UNt3U9houeGEsb
+62iU4ahd3zRRrQyof2ZshLZ6kSNM/5KrRSP2YlpzLSGbXJjuQQdc6rbQItOxo2rz
+lkQ4IlBj1XgYqO67GimlXk5GxpsTLhCFh2dfONxcgj3/P2OJAJUDBRA8H44OI+Ri
+1L97pCEBARSeA/9Ep+EhBQUhnr0lq5PX/35uSfyaSFYVNnJ6KQqgoGJXIsktW47a
+CIlGNireedg6t1TpjC6O4mWLZbromFYX6tq3ItNJopoMEN7kQjG+joWgYeBb5e3u
+qDCThHonW552ev9HNGtCROG6Dvb8gDbjutlcKQMNygJdAdQquLdxAMWeeIkAlQMF
+EDwfjdV3HZKuiXLHwQEBe74EAI8cKrwohEOLVUNRZSCmNpttwPQ1UddzPF0JtFLy
+1CdaQWQpR85jarWCzYGioWWMpKrOHjQC2dzezaXbbaegWgC+NNylcgSuPlbAgexY
+KCHy8zARQQR87XzRFyfSgG3eJaChSpqNxZ38MS81P3BXpLoKeUA7LOyQbLOAK9Dz
+NCSqiQBGBBARAgAGBQI8H435AAoJENNJPvDSl6uOsq4AoIAKkPCRfhY4O/UMWlsC
+JqX/dY7DAJsGrYZYJAYOM2uyi7UVpNM4XrpcKYkAlQMFEDwfjpVfHshviAyeVQEB
+dNkD/2D9uVWeD9RD6eO1VLrMatDfqRrjVFa7S0tKkJSH2v2Kdes9cuFeUAXSRLOt
+u7knPiGun++AfYCWCl6rr80sCHtT2Af84C7rhKSImkeTlxUOBYid5s9GiNAJXn7b
+LZZBYylfdGrdU2wFeLULRhNvPB7hSmMSOloDulgJPk20Y7JfiQCVAwUQPB+PPKVT
+ksHk9ElFAQEVkAQAnE/KrfYoCMeEHvbS0MVoCuVjPvbwshWzUF3kH9hKCG+0pIRl
+mvMXLRtAx8DP2RxfCrzAMatyL80fd+vdAjh3TK+TXhJm0SK+KbYjbk8PhPxDN85l
+mJkybMnUKAirjKcdyigCAKIzvc30NyadLyq08mGaYPjrK61LuLxr91KOKSWJAEYE
+EBECAAYFAjwfkSgACgkQAm4U2qPreYqQJQCg6XPb/+6fZfkscGlAyqWICmv3Ir8A
+oMdaGZp1kH901+GqmEA9yAm8FVnziQBGBBARAgAGBQI8H5GqAAoJEKK7+yQM+Vb3
+czEAn2OCdDNEGlJt0wwUi37vvNJJXAvtAJ0SAOrKsE+jH0Hq/0Y181nCcjWafokA
+lQMFEDwfnYXh1PwU5tB0cQEBlS0D/jnLmHQtNmKxV/CXWgyHwcfHP5QcbgGYJfLE
+9SDVARN+VJnFQqXDAPI5qwcdAEOJal8AVs4cnoTwuJm5dnKSjPOPsPEVALFPyX2v
+LZv3M/QF+FMuaUowqAM4HCIqPT+ksd+j4jBSRwGvYI6BeBYIWdmHvrIVkh9Cy6Mz
+z8+sAZ4WiQBGBBARAgAGBQI8H55mAAoJEHAt5Vm009ew6SoAoPQHwI0VMEouunZD
+kM/iWMdKPOLqAJ9+xhZHRCDTqaqrOcUV6LkvKAzvxYkAlQMFEDwgMQAA8tkJ67sb
+QQEBEUcD/ROzXCXemtAui6WTjRKXbw0amx7XTxvbRWmhF9Q3d1OOgWMWQ4LAs4JG
+irFdCjPn1sl/oDTLvU5YAUpRj/Eu9XGxqTlvJXoOE4Gfh1UMPoSxK7CIeuzQUgJ8
+8JCRGmytKngupzQ1o0agAOsB96bM8H9UJiB/mo8iqHijotVbagntiQBGBBARAgAG
+BQI8IIEQAAoJENvMSAFp0LW+8/oAoIgGzgkjm5zeOlHCl3vdeH7IMKC4AJ9Dg2VP
+k0ouvT33gc0C1lvqHOuWMw==
+=Yoii
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits KeyID Created Expires Algorithm Use
pub 1024 0xCC374F2D 2000-12-14 ---------- RSA Sign & Encrypt
f16 Fingerprint16 = 59 AF DC 3E A2 7D 29 56 89 FA 25 70 90 0D 7E C1
uid Sendmail Signing Key/2001 <sendmail@Sendmail.ORG>
@@ -830,4 +904,4 @@ SIXqPke2iCW6+zdG1T/gS5T9T9/Lf2c9FQf0FjURAi3ynDA2RBLA5FDsI8v3
=dbDm
-----END PGP PUBLIC KEY BLOCK-----
-$Revision: 8.5.16.4 $, Last updated $Date: 2001/07/31 22:36:18 $
+$Revision: 8.13 $, Last updated $Date: 2001/12/19 19:10:01 $
diff --git a/contrib/sendmail/README b/contrib/sendmail/README
index 4188f9d..715f34f 100644
--- a/contrib/sendmail/README
+++ b/contrib/sendmail/README
@@ -27,10 +27,12 @@ the latest updates.
You may also find these useful:
- d. devtools/README
- e. devtools/Site/README
- f. mail.local/README
- g. smrsh/README
+ d. sendmail/SECURITY
+ e. devtools/README
+ f. devtools/Site/README
+ g. libmilter/README
+ h. mail.local/README
+ i. smrsh/README
4. Read cf/README.
@@ -93,7 +95,7 @@ the items in the file to be marked as safe for file and program
delivery.
Other files affected by this strengthened security include class
-files (i.e. Fw /etc/mail/local-host-names), persistent host status files,
+files (i.e., Fw /etc/mail/local-host-names), persistent host status files,
and the files specified by the ErrorHeader and HelpFile options. Similar
DontBlameSendmail flags are available for the class, ErrorHeader, and
HelpFile files.
@@ -174,15 +176,13 @@ Important RFCs for electronic mail are:
RFC974 MX routing
RFC976 UUCP mail format
RFC1123 Host requirements (modifies 821, 822, and 974)
- RFC1413 Identification server
- RFC1869 SMTP Service Extensions (ESMTP spec)
- RFC1652 SMTP Service Extension for 8bit-MIMEtransport
- RFC1870 SMTP Service Extension for Message Size Declaration
- RFC2045 Multipurpose Internet Mail Extensions (MIME) Part One:
- Format of Internet Message Bodies
RFC1344 Implications of MIME for Internet Mail Gateways
+ RFC1413 Identification server
RFC1428 Transition of Internet Mail from Just-Send-8 to
8-bit SMTP/MIME
+ RFC1652 SMTP Service Extension for 8bit-MIMEtransport
+ RFC1869 SMTP Service Extensions (ESMTP spec)
+ RFC1870 SMTP Service Extension for Message Size Declaration
RFC1891 SMTP Service Extension for Delivery Status Notifications
RFC1892 Multipart/Report Content Type for the Reporting of
Mail System Administrative Messages
@@ -192,9 +192,15 @@ Important RFCs for electronic mail are:
RFC1985 SMTP Service Extension for Remote Message Queue Starting
RFC2033 Local Mail Transfer Protocol (LMTP)
RFC2034 SMTP Service Extension for Returning Enhanced Error Codes
+ RFC2045 Multipurpose Internet Mail Extensions (MIME) Part One:
+ Format of Internet Message Bodies
RFC2476 Message Submission
RFC2487 SMTP Service Extension for Secure SMTP over TLS
RFC2554 SMTP Service Extension for Authentication
+ RFC2821 Simple Mail Transfer Protocol
+ RFC2822 Internet Message Format
+ RFC2852 Deliver By SMTP Service Extension
+ RFC2920 SMTP Service Extension for Command Pipelining
Other standards that may be of interest (but which are less directly
relevant to sendmail) are:
@@ -221,8 +227,8 @@ PARTS OF THE WORLD. SO, WHEN YOU IMPORT THIS PACKAGE TO YOUR
COUNTRY, RE-DISTRIBUTE IT FROM THERE OR EVEN JUST EMAIL TECHNICAL
SUGGESTIONS OR EVEN SOURCE PATCHES TO THE AUTHOR OR OTHER PEOPLE
YOU ARE STRONGLY ADVISED TO PAY CLOSE ATTENTION TO ANY EXPORT/IMPORT
-AND/OR USE LAWS WHICH APPLY TO YOU. THE AUTHORS ARE NOT LIABLE FOR
-ANY VIOLATIONS YOU MAKE HERE. SO BE CAREFUL, IT IS YOUR RESPONSIBILITY.
+AND/OR USE LAWS WHICH APPLY TO YOU. THE AUTHORS ARE NOT LIABLE FOR
+ANY VIOLATIONS YOU MAKE HERE. SO BE CAREFUL, IT IS YOUR RESPONSIBILITY.
If you use OpenSSL then make sure you read their README file which
contains information about patents etc.
@@ -360,6 +366,8 @@ contrib Some contributed tools to help with sendmail. THESE
devtools Build environment. See devtools/README.
doc Documentation. If you are getting source, read
op.me -- it's long, but worth it.
+editmap A program to edit and query maps that have been created
+ with makemap, e.g., adding and deleting entries.
include Include files used by multiple programs in the distribution.
libsmdb sendmail database library with support for Berkeley DB 1.X,
Berkeley DB 2.X, Berkeley DB 3.X, and NDBM.
@@ -392,4 +400,4 @@ sendmail Source for the sendmail program itself.
test Some test scripts (currently only for compilation aids).
vacation Source for the vacation program. NOT PART OF SENDMAIL!
-$Revision: 8.71.4.8 $, Last updated $Date: 2001/07/31 22:42:46 $
+$Revision: 8.81 $, Last updated $Date: 2001/09/26 16:22:19 $
diff --git a/contrib/sendmail/RELEASE_NOTES b/contrib/sendmail/RELEASE_NOTES
index ad6aecf..f0d9d4d 100644
--- a/contrib/sendmail/RELEASE_NOTES
+++ b/contrib/sendmail/RELEASE_NOTES
@@ -1,11 +1,907 @@
SENDMAIL RELEASE NOTES
- $Id: RELEASE_NOTES,v 8.561.2.5.2.261 2001/08/20 14:45:32 gshapiro Exp $
+ $Id: RELEASE_NOTES,v 8.1218 2002/01/13 18:24:15 ca Exp $
This listing shows the version of the sendmail binary, the version
of the sendmail configuration files, the date of release, and a
summary of the changes in that release.
+8.12.2/8.12.2 2002/01/13
+ Don't complain too much if stdin, stdout, or stderr are missing
+ at startup, only log an error message.
+ Fix potential problem if an unknown operation mode (character
+ following -b) has been specified.
+ Prevent purgestat from looping even if someone changes the
+ permissions or owner of hoststatus files. Problem noted
+ by Kari Hurtta of the Finnish Meteorological Institute.
+ Properly record dropped connections in persistent host status.
+ Problem noted by Ulrich Windl of the Universitat
+ Regensburg.
+ Remove newlines from recipients read via sendmail -t to prevent
+ SMTP protocol errors when sending the RCPT command.
+ Problem noted by William D. Colburn of the New Mexico
+ Institute of Mining and Technology.
+ Only log milter body replacements once instead of for each body
+ chunk sent by a filter. Problem noted by Kari Hurtta of
+ the Finnish Meteorological Institute.
+ In 8.12.0 and 8.12.1, the headers were mistakenly not included in
+ the message size calculation. Problem noted by Kari Hurtta
+ of the Finnish Meteorological Institute.
+ Since 8.12 no longer forks at the SMTP MAIL command, the daemon
+ needs to collect children status to avoid zombie processes.
+ Problem noted by Chris Adams of HiWAAY Informations Services.
+ Shut down "nullserver" and ETRN-only connections after 25 bad
+ commands are issued. This makes it consistent with normal
+ SMTP connections.
+ Avoid duplicate logging of milter rejections. Problem noted by
+ William D. Colburn of the New Mexico Institute of Mining
+ and Technology.
+ Error and delay DSNs were being sent to postmaster instead of the
+ message sender if the sender had used a deprecated RFC822
+ source route. Problem noted by Kari Hurtta of the Finnish
+ Meteorological Institute.
+ Fix FallbackMXhost behavior for temporary errors during address
+ parsing. Problem noted by Jorg Bielak from Coastal Web
+ Online.
+ For systems on which stat(2) does not return a value for st_blksize
+ that is the "optimal blocksize for I/O" three new compile
+ time flags are available: SM_IO_MAX_BUF_FILE, SM_IO_MIN_BUF,
+ and SM_IO_MAX_BUF, which define an upper limit for
+ regular files, and a lower and upper limit for other file
+ types, respectively.
+ Fix a potential deadlock if two events are supposed to occur at
+ exactly the same time. Problem noted by Valdis Kletnieks
+ of Virginia Tech.
+ Perform envelope splitting for aliases listed directly in the
+ alias file, not just for include/.forward files.
+ Problem noted by John Beck of Sun Microsystems.
+ Allow selection of queue group for mailq using -qGgroup.
+ Based on patch by John Beck of Sun Microsystems.
+ Make sure cached LDAP connections used my multiple maps in the same
+ process are closed. Patch from Taso N. Devetzis.
+ If running as root, allow reading of class files in protected
+ directories. Patch from Alexander Talos of the University
+ of Vienna.
+ Correct a few LDAP related memory leaks. Patch from David Powell
+ of Sun Microsystems.
+ Allow specification of an empty realm via the authinfo ruleset.
+ This is necessary to interoperate as an SMTP AUTH client
+ with servers that do not support realms when using
+ CRAM-MD5. Problem noted by Bjoern Voigt of TU Berlin.
+ Avoid a potential information leak if AUTH PLAIN is used and the
+ server gets stuck while processing that command. Problem
+ noted by Chris Adams from HiWAAY Informations Services.
+ In addition to printing errors when parsing recipients during
+ command line invocations log them to make it simpler
+ to understand possible DSNs to postmaster.
+ Do not use FallbackMXhost on mailers which have the F=0 flag set.
+ Allow local mailers (F=l) to specify a host for TCP connections
+ instead of forcing localhost.
+ Obey ${DESTDIR} for installation of the client mail queue and
+ submit.cf. Patch from Peter 'Luna' Runestig.
+ Re-enable support for -M option which was broken in 8.12.1. Problem
+ noted by Neil Rickert of Northern Illinois University.
+ If a remote server violates the SMTP standard by unexpectedly
+ dropping the connection during an SMTP transaction, stop
+ sending commands. This prevents bogus "Bad file number"
+ recipient status. Problem noted by Allan E Johannesen of
+ Worcester Polytechnic Institute.
+ Do not use a size estimate of 100 for postmaster bounces, it's
+ almost always too small; do not guess the size at all.
+ New VENDOR_DEC for Compaq/DEC. Requested by James Seagraves of
+ Compaq Computer Corp.
+ Fix DaemonPortOptions IPv6 address parsing such that ::1 works
+ properly. Problem noted by Valdis Kletnieks of Virginia
+ Tech.
+ Portability:
+ Fix IPv6 network interface probing on HP-UX 11.X. Based on
+ patch provided by HP.
+ Mac OS X (aka Darwin) has a broken setreuid() call, but a
+ working seteuid() call. From Daniel J. Luke.
+ Use proper type for a 32-bit integer on SINIX. From Ganu
+ Sachin of Siemens.
+ Set SM_IO_MIN_BUF (4K) and SM_IO_MAX_BUF (8K) for HP-UX.
+ Reduce optimization from +O3 to +O2 on HP-UX 11. This
+ fixes a problem that caused additional bogus
+ characters to be written to the qf file. Problem
+ noted by Tapani Tarvainen.
+ Set LDA_USE_LOCKF by default for UnixWare. Problem noted
+ by Boyd Lynn Gerber.
+ Add support for HP MPE/iX. See sendmail/README for port
+ information. From Mark Bixby of Hewlett-Packard.
+ New portability defines HASNICE, HASRRESVPORT, USE_ENVIRON,
+ USE_DOUBLE_FORK, and NEEDLINK. See sendmail/README
+ for more information. From Mark Bixby of
+ Hewlett-Packard.
+ If an OS doesn't have a method of finding free disk space
+ (SFS_NONE), lie and say there is plenty of space.
+ From Mark Bixby of Hewlett-Packard.
+ Add support for AIX 5.1. From Valdis Kletnieks of
+ Virginia Tech.
+ Fix man page location for NeXTSTEP. From Hisanori Gogota
+ of the NTT/InterCommunication Center.
+ Do not assume that strerror() always returns a string.
+ Problem noted by John Beck of Sun Microsystems.
+ CONFIG: Add OSTYPE(freebsd5) for FreeBSD 5.X, which has removed
+ UUCP from the base operating system. From Mark Murray of
+ FreeBSD Services, Ltd.
+ CONFIG: Add OSTYPE(mpeix) and a generic .mc file for HP MPE/iX
+ systems. From Mark Bixby of Hewlett-Packard.
+ CONFIG: Add support for selecting a queue group for all mailers.
+ Based on proposal by Stephen L. Ulmer of the University of
+ Florida.
+ CONFIG: Fix error reporting for compat_check.m4. Problem noted by
+ Altin Waldmann.
+ CONFIG: Do not override user selections for confRUN_AS_USER and
+ confTRUSTED_USER in FEATURE(msp). From Mark Bixby of
+ Hewlett-Packard.
+ LIBMILTER: Fix bug that prevented the removal of a socket after
+ libmilter terminated. Problem reported by Andrey V. Pevnev
+ of MSFU.
+ LIBMILTER: Fix configuration error that required libsm for linking.
+ Problem noted by Kari Hurtta of the Finnish Meteorological
+ Institute.
+ LIBMILTER: Portability fix for OpenUNIX. Patch from Larry Rosenman.
+ LIBMILTER: Fix a theoretical memory leak and a possible attempt
+ to free memory twice.
+ LIBSM: Fix a potential segmentation violation in the I/O library.
+ Problem found and analyzed by John Beck and Tim Haley
+ of Sun Microsystems.
+ LIBSM: Do not clear the LDAP configuration information when
+ terminating the mailbox database connection in the LDAP
+ example code. Problem noted by Nikos Voutsinas of the
+ University of Athens.
+ New Files:
+ cf/cf/generic-mpeix.cf
+ cf/cf/generic-mpeix.mc
+ cf/ostype/freebsd5.m4
+ cf/ostype/mpeix.m4
+ devtools/OS/AIX.5.1
+ devtools/OS/MPE-iX
+ include/sm/os/sm_os_mpeix.h
+ libsm/mpeix.c
+
+8.12.1/8.12.1 2001/10/01
+ SECURITY: Check whether dropping group privileges actually succeeded
+ to avoid possible compromises of the mail system by
+ supplying bogus data. Add configuration options for
+ different set*gid() calls to reset saved gid. Problem
+ found by Michal Zalewski.
+ PRIVACY: Prevent information leakage when sendmail has extra
+ privileges by disabling debugging (command line -d flag)
+ during queue runs and disabling ETRN when sendmail -bs is
+ used. Suggested by Michal Zalewski.
+ Avoid memory corruption problems resulting from bogus .cf files.
+ Problem found by Michal Zalewski.
+ Set the ${server_addr} macro to name of mailer when doing LMTP
+ delivery. LMTP systems may offer SMTP Authentication or
+ STARTTLS causing sendmail to use this macro in rulesets.
+ If debugging is turned on (-d0.10) print not just the default
+ values for configuration file and pid file but also the
+ selected values. Problem noted by Brad Chapman.
+ Continue dealing with broken nameservers by ignoring SERVFAIL
+ errors returned on T_AAAA (IPv6) lookups at delivery time
+ if ResolverOptions=WorkAroundBrokenAAAA is set. Previously
+ this only applied to hostname canonification. Problem
+ noted by Bill Fenner of AT&T Research.
+ Ignore comments in NIS host records when trying to find the
+ canonical name for a host.
+ When sendmail has extra privileges, limit mail submission command
+ line flags (i.e., -G, -h, -F, etc.) to mail submission
+ operating modes (i.e., -bm, -bs, -bv, etc.). Idea based on
+ suggestion from Michal Zalewski.
+ Portability:
+ AIX: Use `oslevel` if available to determine OS version.
+ `uname` does not given complete information.
+ Problem noted by Keith Neufeld of the Cessna
+ Aircraft Company.
+ OpenUNIX: Use lockf() for LDA delivery (affects mail.local).
+ Problem noticed by Boyd Lynn Gerber of ZENEX.
+ Avoid compiler warnings by not using pointers to pass
+ integers. Problem noted by Todd C. Miller of
+ Courtesan Consulting.
+ CONFIG: Add restrictqrun to PrivacyOptions for the MSP to minimize
+ problems with potential misconfigurations.
+ CONFIG: Fix comment showing default value of MaxHopCount. Problem
+ noted by Greg Robinson of the Defence Science and
+ Technology Organisation of Australia.
+ CONFIG: dnsbl: If an argument specifies an error message in case
+ of temporary lookup failures for DNS based blacklists
+ then use it.
+ LIBMILTER: Install mfdef.h, required by mfapi.h. Problem noted by
+ Richard A. Nelson of Debian.
+ LIBMILTER: Add __P definition for OS that lack it. Problem noted
+ by Chris Adams from HiWAAY Informations Services.
+ LIBSMDB: Fix a lock race condition that affects makemap, praliases,
+ and vacation.
+ MAKEMAP: Avoid going beyond the end of an input line if it does
+ not contain a value for a key. Based on patch from
+ Mark Bixby from Hewlett-Packard.
+ New Files:
+ test/Build
+ test/Makefile
+ test/Makefile.m4
+ test/README
+ test/t_dropgid.c
+ test/t_setgid.c
+ Deleted Files:
+ include/sm/stdio.h
+ include/sm/sysstat.h
+
+8.12.0/8.12.0 2001/09/08
+ *NOTICE*: The default installation of sendmail does not use
+ set-user-ID root anymore. You need to create a new user and
+ a new group before installing sendmail (both called smmsp by
+ default). The installation process tries to install
+ /etc/mail/submit.cf and creates /var/spool/clientmqueue by
+ default. Please see sendmail/SECURITY for details.
+ SECURITY: Check for group and world writable forward and :include:
+ files. These checks can be turned off if absolutely
+ necessary using the DontBlameSendmail option and the new
+ flags:
+ GroupWritableForwardFile
+ WorldWritableForwardFile
+ GroupWritableIncludeFile
+ WorldWritableIncludeFile
+ Problem noted by Slawek Zak of Politechnika Warszawska,
+ SECURITY: Drop privileges when using address test mode. Suggested
+ by Michal Zalewski of the "Internet for Schools" project
+ (IdS).
+ Fixed problem of a global variable being used for a timeout jump
+ point where the variable could become overused for more than
+ one timeout concurrently. This erroneous behavior resulted in
+ a corrupted stack causing a core dump. The timeout is now
+ handled via libsm. Problem noted by Michael Shapiro,
+ John Beck, and Carl Smith of Sun Microsystems.
+ If sendmail is set-group-ID then that group ID is used for permission
+ checks (group ID of RunAsUser). This allows use of a
+ set-group-ID sendmail binary for initial message submission
+ and no set-user-ID root sendmail is needed. For details
+ see sendmail/SECURITY.
+ Log a warning if a non-trusted user changes the syslog label.
+ Based on notice from Bryan Costales of SL3D, Inc.
+ If sendmail is called for initial delivery, try to use submit.cf
+ with a fallback of sendmail.cf as configuration file. See
+ sendmail/SECURITY.
+ New configuration file option UseMSP to allow group writable queue
+ files if the group is the same as that of a set-group-ID
+ sendmail binary. See sendmail/SECURITY.
+ The .cf file is chosen based on the operation mode. For -bm (default),
+ -bs, and -t it is submit.cf if it exists for all others it
+ is sendmail.cf (to be backward compatible). This selection
+ can be changed by the new option -Ac or -Am (alternative .cf
+ file: client or mta). See sendmail/SECURITY.
+ The SMTP server no longer forks on each MAIL command. The ONEX
+ command has been removed.
+ Implement SMTP PIPELINING per RFC 2920. It can be turned off
+ at compile time or per host (ruleset).
+ New option MailboxDatabase specifies the type of mailbox database
+ used to look up local mail recipients; the default value
+ is "pw", which means to use getpwnam(). New mailbox database
+ types can be added by adding custom code to libsm/mbdb.c.
+ Queue file names are now 15 characters long, rather than 14 characters
+ long, to accomodate envelope splitting. File systems with
+ a 14 character file name length limit are no longer
+ supported.
+ Recipient list used for delivery now gets internally ordered by
+ hostsignature (character string version of MX RR). This orders
+ recipients for the same MX RR's together meaning smaller
+ portions of the list need to be scanned (instead of the whole
+ list) each delivery() pass to determine piggybacking. The
+ significance of the change is better the larger the recipient
+ list. Hostsignature is now created during recipient list
+ creation rather than just before delivery.
+ Enhancements for more opportunistic piggybacking. Previous
+ piggybacking (called coincidental) extended to coattail
+ piggybacking. Rather than complete MX RR matching
+ (coincidental) piggybacking is done if just the lowest value
+ preference matches (coattail).
+ If sendmail receives a temporary error on a RCPT TO: command, it will
+ try other MX hosts if available.
+ DefaultAuthInfo can contain a list of mechanisms to be used for
+ outgoing (client-side) SMTP Authentication.
+ New modifier 'A' for DaemonPortOptions/ClientPortOptions to disable
+ AUTH (overrides 'a' modifier in DaemonPortOptions). Based
+ on patch from Lyndon Nerenberg of Messaging Direct.
+ Enable AUTH mechanism EXTERNAL if STARTTLS is used.
+ A new ruleset authinfo can be used to return client side
+ authentication information for AUTH instead of DefaultAuthInfo.
+ Therefore the DefaultAuthInfo option is deprecated and will be
+ removed in future versions.
+ Accept any SMTP continuation code 3xy for AUTH even though RFC 2554
+ requires 334. Mercury 1.48 is a known offender.
+ Add new option AuthMaxBits to limit the overall encryption strength
+ for the security layer in SMTP AUTH (SASL). See
+ doc/op/op.me for details.
+ Introduce new STARTTLS related macros {cn_issuer}, {cn_subject},
+ {cert_md5} which hold the CN (common name) of the CA that
+ signed the presented certificate, the CN and the MD5 hash
+ of the presented certificate, respectively.
+ New ruleset try_tls to decide whether to try (as client) STARTTLS.
+ New ruleset srv_features to enable/disable certain features in the
+ server per connection. See doc/op/op.me for details.
+ New ruleset tls_rcpt to decide whether to send e-mail to a particular
+ recipient; useful to decide whether a conection is secure
+ enough on a per recipient basis.
+ New option TLSSrvOptions to modify some aspects of the server
+ for STARTTLS.
+ If no certificate has been requested, the macro {verify} has the
+ value "NOT".
+ New M=S modifier for ClientPortOptions/DaemonPortOptions to turn off
+ using/offering STARTTLS when delivering/receiving e-mail.
+ Macro expand filenames/directories for certs and keys in the .cf file.
+ Proposed by Neil Rickert of Northern Illinois University.
+ Generate an ephemeral RSA key for a STARTTLS connection only if
+ really required. This change results in a noticable
+ performance gains on most machines. Moreover, if shared
+ memory is in use, reuse the key several times.
+ Add queue groups which can be used to group queue directories with
+ the same behavior together. See doc/op/op.me for details.
+ If the new option FastSplit (defaults to one) has a value greater
+ than zero, it suppresses the MX lookups on addresses when they
+ are initially sorted which may result in faster envelope
+ splitting. If the mail is submitted directly from the
+ command line, then the value also limits the number of
+ processes to deliver the envelopes; if more envelopes are
+ created they are only queued up and must be taken care of
+ by a queue run.
+ The check for 'enough disk space' now pays attention to which file
+ system each queue directory resides in.
+ All queue runners can be cleanly terminated via SIGTERM to parent.
+ New option QueueFileMode for the default permissions of queue files.
+ Add parallel queue runner code. Allows multiple queue runners per work
+ group (one or more queues in a multi-queue environment
+ collected together) to process the same work list at the
+ same time.
+ Option MaxQueueChildren added to limit the number of concurrently
+ active queue runner processes.
+ New option MaxRunnersPerQueue to specify the maximum number of queue
+ runners per queue group.
+ Queue member selection by substring pattern matching now allows
+ the pattern to be negated. For -qI, -qR and -qS it is
+ permissible for -q!I, -q!R and -q!S to mean remove members
+ of the queue that match during processing.
+ New -qp[time] option is similar to -qtime, except that instead of
+ periodically forking a child to process the queue, a single
+ child is forked for each queue that sleeps between queue
+ runs. A SIGHUP signal can be sent to restart this
+ persistent queue runner.
+ The SIGHUP signal now restarts a timed queue run process (i.e., a
+ sendmail process which only runs the queue at an interval:
+ sendmail -q15m).
+ New option NiceQueueRun to set the priority of queue runners.
+ Proposed by Thom O'Connor.
+ sendmail will run the queue(s) in the background when invoked with -q
+ unless the new -qf option or -v is used.
+ QueueSortOrder=Random sorts the queue randomly, which is useful if
+ several queue runners are started by hand to avoid contention.
+ QueueSortOrder=Modification sorts the queue by the modification time
+ of the qf file (older entries first).
+ Support Deliver By SMTP Service Extension (RFC 2852) which allows
+ a client to specify an amount of time within which an e-mail
+ should be delivered. New option DeliverByMin added to set the
+ minimum amount of time or disable the extension.
+ Non-printable characters (ASCII: 0-31, 127) in mailbox addresses are
+ not allowed unless escaped or quoted.
+ Add support for a generic DNS map. Based on a patch contributed
+ by Leif Johansson of Stockholm University, which was based on
+ work by Assar Westerlund of Swedish Institute of Computer
+ Science, Kista, and Johan Danielsson of Royal Institute of
+ Technology, Stockholm, Sweden.
+ MX records will be looked up for FallBackMXhost. To use the old
+ behavior (no MX lookups), put the name in square brackets.
+ Proposed by Thom O'Connor.
+ Use shared memory to store free space of filesystems that are used
+ for queues, if shared memory is available and if a key is set
+ via SharedMemoryKey. This minimizes the number of system
+ calls to check the available space. See doc/op/op.me for
+ details.
+ If shared memory is compiled in the option -bP can be used to print
+ the number of entries in the queue(s).
+ Enable generic mail filter API (milter). See libmilter/README
+ and the usual documentation for details.
+ Remove AutoRebuildAliases option, deprecated since 8.10.
+ Remove '-U' (initial user submission) command line option as
+ announced in 8.10.
+ Remove support for non-standard SMTP command XUSR. Use an MSA instead.
+ New macro {addr_type} which contains whether the current address is
+ an envelope sender or recipient address. Suggested by
+ Neil Rickert of Northern Illinois University.
+ Two new options for host maps: -d (retransmission timeout),
+ -r (number of retries).
+ New option for LDAP maps: the -V<sep> allows you to specify a
+ separator such that a lookup can return both an attribute
+ and value separated by the given separator.
+ Add new operators '%', '|', '&' (modulo, binary or, binary and)
+ to map class arith.
+ If DoubleBounceAddress expands to an empty string, ``double bounces''
+ (errors that occur when sending an error message) are dropped.
+ New DontBlameSendmail options GroupReadableSASLDBFile and
+ GroupWritableSASLDBFile to relax requirements for sasldb files.
+ New DontBlameSendmail options GroupReadableKeyFile to relax
+ requirements for files containing secret keys. This is
+ necessary for the MSP if client authentification is used.
+ Properly handle quoted filenames for class files (to allow for
+ filenames with spaces).
+ Honor the resolver option RES_NOALIASES when canonifying hostnames.
+ Add macros to avoid the reuse of {if_addr} etc:
+ {if_name_out} hostname of interface of outgoing connection.
+ {if_addr_out} address of interface of outgoing connection.
+ {if_family_out} family of interface of outgoing connection.
+ The latter two are only set if the interface does not belong
+ to the loopback net.
+ Add macro {nrcpts} which holds the number of (validated) recipients.
+ DialDelay option applies only to mailers with flag 'Z'. Patch from
+ Juergen Georgi of RUS University of Stuttgart.
+ New Timeout.lhlo,auth,starttls options to limit the time waiting for
+ an answer to the LMTP LHLO, SMTP AUTH or STARTTLS command.
+ New Timeout.aconnect option to limit the overall waiting time for
+ all connections for a single delivery attempt to succeed.
+ Limit the rate recipients in the SMTP envelope are accepted once
+ a threshold number of recipients has been rejected (option
+ BadRcptThrottle). From Gregory A Lundberg of the WU-FTPD
+ Development Group.
+ New option DelayLA to delay connections if the load averages
+ exceeds the specified value. The default of 0 does not
+ change the previous behavior. A value greater than 0
+ will cause sendmail to sleep for one second on most
+ SMTP commands and before accepting connections if that
+ load average is exceeded.
+ Use a dynamic (instead of fixed-size) buffer for the list of
+ recipients that are sent during a connection to a mailer.
+ This also introduces a new mailer field 'r' which defines
+ the maximum number of recipients (defaults to 100).
+ Based on patch by Motonori Nakamura of Kyoto University.
+ Add new F=1 mailer flag to disable sending of null characters ('\0').
+ Add new F=2 mailer flag to disable use of ESMTP, using SMTP instead.
+ The deprecated [TCP] builtin mailer pathname (P=) is gone. Use [IPC]
+ instead.
+ IPC is no longer available as first mailer argument (A=) for [IPC]
+ builtin mailer pathnames. Use TCP instead.
+ PH map code updated to use the new libphclient API instead of the
+ old libqiapi library. Contributed by Mark Roth of the
+ University of Illinois at Urbana-Champaign.
+ New option DirectSubmissionModifiers to define {daemon_flags}
+ for direct (command line) submissions.
+ New M=O modifier for DaemonPortOptions to ignore the socket in
+ case of failures. Based on patch by Jun-ichiro itojun
+ Hagino of the KAME Project.
+ Add Disposition-Notification-To: (RFC 2298) to the list of headers
+ whose content is rewritten similar to Reply-To:.
+ Proposed by Andrzej Filip.
+ Use STARTTLS/AUTH=server/client for logging incoming/outgoing
+ STARTTLS/AUTH connections; log incoming connections at level
+ 9 or higher. Use AUTH/STARTTLS instead of SASL/TLS for SMTP
+ AUTH/STARTTLS related logfile entries.
+ Convert unprintable characters (and backslash) into octal or C format
+ before logging.
+ Log recipients if no message is transferred but QUIT/RSET is given
+ (at LogLevel 9/10 or higher).
+ Log discarded recipients at LogLevel 10 or higher.
+ Do not log "did not issue MAIL/EXPN/VRFY/ETRN" for connections
+ in which most commands are rejected due to check_relay or
+ TCP Wrappers if the host tries one of those commands anyway.
+ Change logging format for cloned envelopes to be similar to that for
+ DSNs ("old id: new id: clone"). Suggested by Ulrich Windl
+ of the Universitat Regensburg.
+ Added libsm, a C library of general purpose abstractions including
+ assertions, tracing and debugging with named debug categories,
+ exception handling, malloc debugging, resource pools,
+ portability abstractions, and an extensible buffered I/O
+ package. It will at some point replace libsmutil.
+ See libsm/index.html for details.
+ Fixed most memory leaks in sendmail which were previously taken
+ care of by fork() and exit().
+ Use new sm_io*() functions in place of stdio calls. Allows for
+ more consistent portablity amongst different platforms
+ new and old (from new libsm).
+ Common I/O pkg means just one buffering method needed instead of two
+ ('bf_portable' and 'bf_torek' now just 'bf').
+ Sfio no longer needed as SASL/TLS code uses sm_io*() API's.
+ New possible value 'interactive' for SuperSafe which can be used
+ together with DeliveryMode=interactive is to avoid some disk
+ synchronizations calls.
+ Add per-recipient status information to mailq -v output.
+ T_ANY queries are no longer used by sendmail.
+ When compiling with "gcc -O -Wall" specify "-DSM_OMIT_BOGUS_WARNINGS"
+ too (see include/sm/cdefs.h for more info).
+ sendmail -d now has general support for named debug categories.
+ See libsm/debug.html and section 3.4 of doc/op/op.me
+ for details.
+ Eliminate the "postmaster warning" DSNs on address parsing errors
+ such as unbalanced angle brackets or parentheses. The DSNs
+ generated by this condition were illegal (not RFC conform).
+ Problem noted by Ulrich Windl of the Universitaet Regensburg.
+ Do not issue a DSN if the ruleset localaddr resolves to the $#error
+ mailer and the recipient has hence been rejected during the
+ SMTP dialogue. Problem reported by Larry Greenfield of CMU.
+ Deal with a case of multiple deliveries on misconfigured systems
+ that do not have postmaster defined. If an email was sent
+ from an address to which a DSN cannot be returned and
+ in which at least one recipient address is non-deliverable,
+ then that email had been delivered in each queue run.
+ Problem reported by Matteo HCE Valsasna of Universita
+ degli Studi dell'Insubria.
+ The compilation options SMTP, DAEMON, and QUEUE have been removed,
+ i.e., the corresponding code is always compiled in now.
+ Log the command line in daemon/queue-run mode at LogLevel 10 and
+ higher. Suggested by Robert Harker of Harker Systems.
+ New ResolverOptions setting: WorkAroundBrokenAAAA. When
+ attempting to canonify a hostname, some broken nameservers
+ will return SERVFAIL (a temporary failure) on T_AAAA (IPv6)
+ lookups. If you want to excuse this behavior, use this new
+ flag. Suggested by Chris Foote of SE Network Access and
+ Mark Roth of the University of Illinois at
+ Urbana-Champaign.
+ Free the memory allocated by getipnodeby{addr,name}(). Problem
+ noted by Joy Latten of IBM.
+ ConnectionRateThrottle limits the number of connections per second
+ to each daemon individually, not the overall number of
+ connections.
+ Specifying only "ldap:" as an AliasFile specification will force
+ sendmail to use a default alias schema as outlined in the
+ ``USING LDAP FOR ALIASES, MAPS, and CLASSES'' section of
+ cf/README.
+ Add a new syntax for the 'F' (file class) sendmail.cf command. If
+ the first character after the class name is not a '/' or a
+ '|' and it contains an '@' (e.g., F{X}key@class:spec), the
+ rest of the line will be parsed as a map lookup. This
+ allows classes to be filled via a map lookup. See op.me
+ for more syntax information. Specifically, this can be
+ used for commands such as VIRTUSER_DOMAIN_FILE() to read
+ the list of domains via LDAP (see the ``USING LDAP FOR
+ ALIASES, MAPS, and CLASSES'' section of cf/README for an
+ example).
+ The new macro ${sendmailMTACluster} determines the LDAP cluster for
+ the default schema used in the above two items.
+ Unless DontBlameSendmail=RunProgramInUnsafeDirPath is set, log a
+ warning if a program being run from a mailer or file class
+ (e.g., F|/path/to/prog) is in an unsafe directory path.
+ Unless DontBlameSendmail=RunWritableProgram is set, log a warning
+ if a program being run from a mailer or file class
+ (e.g., F|/path/to/prog) is group or world writable.
+ Loopback interfaces (e.g., "lo0") are now probed for class {w}
+ hostnames. Setting DontProbeInterfaces to "loopback"
+ (without quotes) will disable this and return to the
+ pre-8.12 behavior of only probing non-loopback interfaces.
+ Suggested by Bryan Stansell of GNAC.
+ In accordance with RFC 2821 section 4.1.4, accept multiple
+ HELO/EHLO commands.
+ Multiple ClientPortOptions settings are now allowed, one for each
+ possible protocol family which may be used for outgoing
+ connections. Restrictions placed on one family only affect
+ outgoing connections on that particular family. Because of
+ this change, the ${client_flags} macro is not set until the
+ connection is established. Based on patch from Motonori
+ Nakamura of Kyoto University.
+ PrivacyOptions=restrictexpand instructs sendmail to drop privileges
+ when the -bv option is given by users who are neither root
+ nor the TrustedUser so users can not read private aliases,
+ forwards, or :include: files. It also will override the -v
+ (verbose) command line option.
+ If the M=b modifier is set in DaemonPortOptions and the interface
+ address can't be used for the outgoing connection, fall
+ back to the settings in ClientPortOptions (if set).
+ Problem noted by John Beck of Sun Microsystems.
+ New named config file rule check_data for DATA command (input:
+ number of recipients). Based on patch from Mark Roth of
+ the University of Illinois at Urbana-Champaign.
+ Add support for ETRN queue selection per RFC 1985. The queue group
+ can be specified using the '#' option character. For
+ example, 'ETRN #queuegroup'.
+ If an LDAP server times out or becomes unavailable, close the
+ current connection and reopen to get to one of the fallback
+ servers. Patch from Paul Hilchey of the University of
+ British Columbia.
+ Make default error number on $#error messages 550 instead of 501
+ because 501 is not allowed on all commands.
+ The .cf file option UnsafeGroupWrites is deprecated, it should be
+ replaced with the settings GroupWritableForwardFileSafe
+ and GroupWritableIncludeFileSafe in DontBlameSendmail
+ if required.
+ The deprecated ldapx map class has been removed. Use the ldap map
+ class instead.
+ Any IPv6 addresses used in configuration should be prefixed by the
+ "IPv6:" tag to identify the address properly. For example,
+ if you want to add the IPv6 address [2002:c0a8:51d2::23f4] to
+ class {w}, you would need to add [IPv6:2002:c0a8:51d2::23f4].
+ Change the $&{opMode} macro if the operation mode changes while the
+ MTA is running. For example, during a queue run.
+ Add "use_inet6" as a new ResolverOptions flag to control the
+ RES_USE_INET6 resolver option. Based on patch from Rick
+ Nelson of IBM.
+ The maximum number of commands before the MTA slows down when too
+ many "light weight" commands have been received are now
+ configurable during compile time. The current values and
+ their defaults are:
+ MAXBADCOMMANDS 25 unknown commands
+ MAXNOOPCOMMANDS 20 NOOP, VERB, ONEX, XUSR
+ MAXHELOCOMMANDS 3 HELO, EHLO
+ MAXVRFYCOMMANDS 6 VRFY, EXPN
+ MAXETRNCOMMANDS 8 ETRN
+ Setting a value to 0 disables the check. Patch from Bryan
+ Costales of SL3D, Inc.
+ The header syntax H?${MyMacro}?X-My-Header: now not only checks if
+ ${MyMacro} is defined but also that it is not empty.
+ Properly quote usernames with special characters if they are used
+ in headers. Problem noted by Kari Hurtta of the Finnish
+ Meteorological Institute.
+ Be sure to include the proper Final-Recipient: DSN header in bounce
+ messages for messages for mailing list expanded addresses
+ which are not delivered on the initial attempt.
+ Do not treat errors as sticky when doing delivery via LMTP after
+ the final dot has been sent to avoid affecting future
+ deliveries. Problem reported by Larry Greenfield of CMU.
+ New compile time flag REQUIRES_DIR_FSYNC which turns on support for
+ file systems that require to call fsync() for a directory
+ if the meta-data in it has been changed. This should be
+ set at least for ReiserFS; it is enabled by default for Linux.
+ See sendmail/README for further information.
+ Avoid file locking deadlock when updating the statistics file if
+ sendmail is signaled to terminate. Problem noted by
+ Christophe Wolfhugel of France Telecom.
+ Set the $c macro (hop count) as it is being set instead of when the
+ envelope is initialized. Problem noted by Kari Hurtta of
+ the Finnish Meteorological Institute.
+ Properly count recipients for DeliveryMode defer and queue. Fix
+ from Peter A. Friend of EarthLink.
+ Treat invalid hesiod lookups as permanent errors instead of
+ temporary errors. Problem noted by Russell McOrmond of
+ flora.ca.
+ Portability:
+ Remove support for AIX 2, which supports only 14 character
+ filenames and is outdated anyway. Suggested by
+ Valdis Kletnieks of Virginia Tech.
+ Change several settings for Irix 6: remove confSBINDIR,
+ i.e., use default /usr/sbin, change owner/group
+ of man pages and user-executable to root/sys, set
+ optimization limit to 0 (unlimited). Based on patch
+ from Ayamura Kikuchi, M.D, and proposal from Kari
+ Hurtta of the Finnish Meteorological Institute.
+ Do not assume LDAP support is installed by default under
+ Solaris 8 and later.
+ Add support for OpenUNIX.
+ CONFIG: Increment version number of config file to 10.
+ CONFIG: Add an install target and a README file in cf/cf.
+ CONFIG: Don't accept addresses of the form a@b@, a@b@c, a@[b]c, etc.
+ CONFIG: Reject empty recipient addresses (in check_rcpt).
+ CONFIG: The access map uses an option of -T<TMPF> to deal with
+ temporary lookup failures.
+ CONFIG: New value for access map: SKIP, which causes the default
+ action to be taken by aborting the search for domain names
+ or IP nets.
+ CONFIG: check_rcpt can deal with TEMPFAIL for either recipient or
+ relay address as long as the other part allows the email
+ to get through.
+ CONFIG: Entries for virtusertable can make use of a third parameter
+ "%3" which contains "+detail" of a wildcard match, i.e., an
+ entry like user+*@domain. This allows handling of details by
+ using %1%3 as the RHS. Additionally, a "+" wildcard has been
+ introduced to match only non-empty details of addresses.
+ CONFIG: Numbers for rulesets used by MAILERs have been removed
+ and hence there is no required order within the MAILER
+ section anymore except for MAILER(`uucp') which must come
+ after MAILER(`smtp') if uucp-dom and uucp-uudom are used.
+ CONFIG: Hosts listed in the generics domain class {G}
+ (GENERICS_DOMAIN() and GENERICS_DOMAIN_FILE()) are treated
+ as canonical. Suggested by Per Hedeland of Ericsson.
+ CONFIG: If FEATURE(`delay_checks') is used, make sure that a lookup
+ in the access map which returns OK or RELAY actually
+ terminates check_* ruleset checking.
+ CONFIG: New tag TLS_Rcpt: for access map to be used by ruleset
+ tls_rcpt, see cf/README for details.
+ CONFIG: Change format of Received: header line which reveals whether
+ STARTTLS has been used to "(version=${tls_version}
+ cipher=${cipher} bits=${cipher_bits} verify=${verify})".
+ CONFIG: Use "Spam:" as tag for lookups for FEATURE(`delay_checks')
+ options friends/haters instead of "To:" and enable
+ specification of whole domains instead of just users.
+ Notice: this change is not backward compatible.
+ Suggested by Chris Adams from HiWAAY Informations Services.
+ CONFIG: Allow for local extensions for most new rulesets, see
+ cf/README for details.
+ CONFIG: New FEATURE(`lookupdotdomain') to lookup also .domain in
+ the access map. Proposed by Randall Winchester of the
+ University of Maryland.
+ CONFIG: New FEATURE(`local_no_masquerade') to avoid masquerading for
+ the local mailer. Proposed by Ingo Brueckl of Wupper Online.
+ CONFIG: confRELAY_MSG/confREJECT_MSG can override the default
+ messages for an unauthorized relaying attempt/for access
+ map entries with RHS REJECT, respectively.
+ CONFIG: FEATURE(`always_add_domain') takes an optional argument
+ to specify another domain to be added instead of the local one.
+ Suggested by Richard H. Gumpertz of Computer Problem
+ Solving.
+ CONFIG: confAUTH_OPTIONS allows setting of Cyrus-SASL specific
+ options, see doc/op/op.me for details.
+ CONFIG: confAUTH_MAX_BITS sets the maximum encryption strength for
+ the security layer in SMTP AUTH (SASL).
+ CONFIG: If Local_localaddr resolves to $#ok, localaddr is terminated
+ immediately.
+ CONFIG: FEATURE(`enhdnsbl') is an enhanced version of dnsbl which
+ allows checking of the return values of the DNS lookups.
+ See cf/README for details.
+ CONFIG: FEATURE(`dnsbl') allows now to specify the behavior for
+ temporary lookup failures.
+ CONFIG: New option confDELIVER_BY_MIN to specify minimum time for
+ Deliver By (RFC 2852) or to turn off the extension.
+ CONFIG: New option confSHARED_MEMORY_KEY to set the key for shared
+ memory use.
+ CONFIG: New FEATURE(`compat_check') to look up a key consisting
+ of the sender and the recipient address delimited by the
+ string "<@>", e.g., sender@sdomain<@>recipient@rdomain,
+ in the access map. Based on code contributed by Mathias
+ Koerber of Singapore Telecommunications Ltd.
+ CONFIG: Add EXPOSED_USER_FILE() command to allow an exposed user
+ file. Suggested by John Beck of Sun Microsystems.
+ CONFIG: Don't use MAILER-DAEMON for error messages delivered
+ via LMTP. Problem reported by Larry Greenfield of CMU.
+ CONFIG: New FEATURE(`preserve_luser_host') to preserve the name of
+ the recipient host if LUSER_RELAY is used.
+ CONFIG: New FEATURE(`preserve_local_plus_detail') to preserve the
+ +detail portion of the address when passing address to
+ local delivery agent. Disables alias and .forward +detail
+ stripping. Only use if LDA supports this.
+ CONFIG: Removed deprecated FEATURE(`rbl').
+ CONFIG: Add LDAPROUTE_EQUIVALENT() and LDAPROUTE_EQUIVALENT_FILE()
+ which allow you to specify 'equivalent' hosts for LDAP
+ Routing lookups. Equivalent hostnames are replaced by the
+ masquerade domain name for lookups. See cf/README for
+ additional details.
+ CONFIG: Add a fourth argument to FEATURE(`ldap_routing') which
+ instructs the rulesets on what to do if the address being
+ looked up has +detail information. See cf/README for more
+ information.
+ CONFIG: When chosing a new destination via LDAP Routing, also look
+ up the new routing address/host in the mailertable. Based
+ on patch from Don Badrak of the United States Census Bureau.
+ CONFIG: Do not reject the SMTP Mail from: command if LDAP Routing
+ is in use and the bounce option is enabled. Only reject
+ recipients as user unknown.
+ CONFIG: Provide LDAP support for the remaining database map
+ features. See the ``USING LDAP FOR ALIASES AND MAPS''
+ section of cf/README for more information.
+ CONFIG: Add confLDAP_CLUSTER which defines the ${sendmailMTACluster}
+ macro used for LDAP searches as described above in ``USING
+ LDAP FOR ALIASES, MAPS, AND CLASSES''.
+ CONFIG: confCLIENT_OPTIONS has been replaced by CLIENT_OPTIONS(),
+ which takes the options as argument and can be used
+ multiple times; see cf/README for details.
+ CONFIG: Add configuration macros for new options:
+ confBAD_RCPT_THROTTLE BadRcptThrottle
+ confDIRECT_SUBMISSION_MODIFIERS DirectSubmissionModifiers
+ confMAILBOX_DATABASE MailboxDatabase
+ confMAX_QUEUE_CHILDREN MaxQueueChildren
+ confMAX_RUNNERS_PER_QUEUE MaxRunnersPerQueue
+ confNICE_QUEUE_RUN NiceQueueRun
+ confQUEUE_FILE_MODE QueueFileMode
+ confFAST_SPLIT FastSplit
+ confTLS_SRV_OPTIONS TLSSrvOptions
+ See above (and related documentation) for further information.
+ CONFIG: Add configuration variables for new timeout options:
+ confTO_ACONNECT Timeout.aconnect
+ confTO_AUTH Timeout.auth
+ confTO_LHLO Timeout.lhlo
+ confTO_STARTTLS Timeout.starttls
+ CONFIG: Add configuration macros for mail filter API:
+ confINPUT_MAIL_FILTERS InputMailFilters
+ confMILTER_LOG_LEVEL Milter.LogLevel
+ confMILTER_MACROS_CONNECT Milter.macros.connect
+ confMILTER_MACROS_HELO Milter.macros.helo
+ confMILTER_MACROS_ENVFROM Milter.macros.envfrom
+ confMILTER_MACROS_ENVRCPT Milter.macros.envrcpt
+ Mail filters can be defined via INPUT_MAIL_FILTER() and
+ MAIL_FILTER(). See libmilter/README, cf/README, and
+ doc/op/op.me for details.
+ CONFIG: Add support for accepting temporarily unresolvable domains.
+ See cf/README for details. Based on patch by Motonori
+ Nakamura of Kyoto University.
+ CONFIG: confDEQUOTE_OPTS can be used to specify options for the
+ dequote map.
+ CONFIG: New macro QUEUE_GROUP() to define queue groups.
+ CONFIG: New FEATURE(`queuegroup') to select a queue group based
+ on the full e-mail address or the domain of the recipient.
+ CONFIG: Any IPv6 addresses used in configuration should be prefixed
+ by the "IPv6:" tag to identify the address properly. For
+ example, if you want to use the IPv6 address
+ 2002:c0a8:51d2::23f4 in the access database, you would need
+ to use IPv6:2002:c0a8:51d2::23f4 on the left hand side.
+ This affects the access database as well as the
+ relay-domains and local-host-names files.
+ CONFIG: OSTYPE(aux) has been renamed to OSTYPE(a-ux).
+ CONFIG: Avoid expansion of m4 keywords in SMART_HOST.
+ CONFIG: Add MASQUERADE_EXCEPTION_FILE() for reading masquerading
+ exceptions from a file. Suggested by Trey Breckenridge of
+ Mississippi State University.
+ CONFIG: Add LOCAL_USER_FILE() for reading local users
+ (LOCAL_USER() -- $={L}) entries from a file.
+ CONTRIB: dnsblaccess.m4 is a further enhanced version of enhdnsbl.m4
+ which allows to lookup error codes in the access map.
+ Contributed by Neil Rickert of Northern Illinois University.
+ DEVTOOLS: Add new options for installation of include and library
+ files: confINCGRP, confINCMODE, confINCOWN, confLIBGRP,
+ confLIBMODE, confLIBOWN.
+ DEVTOOLS: Add new option confDONT_INSTALL_CATMAN to turn off
+ installation of the the formatted man pages on operating
+ systems which don't include cat directories.
+ EDITMAP: New program for editing maps as supplement to makemap.
+ MAIL.LOCAL: Mail.local now uses the libsm mbdb package to look up
+ local mail recipients. New option -D mbdb specifies the
+ mailbox database type.
+ MAIL.LOCAL: New option "-h filename" which instructs mail.local to
+ deliver the mail to the named file in the user's home
+ directory instead of the system mail spool area. Based on
+ patch from Doug Hardie of the Los Angeles Free-Net.
+ MAILSTATS: New command line option -P which acts the same as -p but
+ doesn't truncate the statistics file.
+ MAKEMAP: Add new option -t to specify a different delimiter
+ instead of white space.
+ RMAIL: Invoke sendmail with '-G' to indicate this is a gateway
+ submission. Problem noted by Kari Hurtta of the Finnish
+ Meteorological Institute.
+ SMRSH: Use the vendor supplied directory on FreeBSD 3.3 and later.
+ VACATION: Change Auto-Submitted: header value from auto-generated to
+ auto-replied. From Kenneth Murchison of Oceana Matrix Ltd.
+ VACATION: New option -d to send error/debug messages to stdout
+ instead of syslog.
+ VACATION: New option -U which prevents the attempt to lookup login
+ in the password file. The -f and -m options must be used
+ to specify the database and message file since there is no
+ home directory for the default settings for these options.
+ VACATION: Vacation now uses the libsm mbdb package to look up
+ local mail recipients; it reads the MailboxDatabase option
+ from the sendmail.cf file. New option -C cffile which
+ specifies the path of the sendmail.cf file.
+ New Directories:
+ libmilter/docs
+ New Files:
+ cf/cf/README
+ cf/cf/submit.cf
+ cf/cf/submit.mc
+ cf/feature/authinfo.m4
+ cf/feature/compat_check.m4
+ cf/feature/enhdnsbl.m4
+ cf/feature/msp.m4
+ cf/feature/local_no_masquerade.m4
+ cf/feature/lookupdotdomain.m4
+ cf/feature/preserve_luser_host.m4
+ cf/feature/preserve_local_plus_detail.m4
+ cf/feature/queuegroup.m4
+ cf/sendmail.schema
+ contrib/dnsblaccess.m4
+ devtools/M4/UNIX/sm-test.m4
+ devtools/OS/OpenUNIX.5.i386
+ editmap/*
+ include/sm/*
+ libsm/*
+ libsmutil/cf.c
+ libsmutil/err.c
+ sendmail/SECURITY
+ sendmail/TUNING
+ sendmail/bf.c
+ sendmail/bf.h
+ sendmail/sasl.c
+ sendmail/sm_resolve.c
+ sendmail/sm_resolve.h
+ sendmail/tls.c
+ Deleted Files:
+ cf/feature/rbl.m4
+ cf/ostype/aix2.m4
+ devtools/OS/AIX.2
+ include/sendmail/cdefs.h
+ include/sendmail/errstring.h
+ include/sendmail/useful.h
+ libsmutil/errstring.c
+ sendmail/bf_portable.c
+ sendmail/bf_portable.h
+ sendmail/bf_torek.c
+ sendmail/bf_torek.h
+ sendmail/clock.c
+ Renamed Files:
+ cf/cf/generic-solaris2.mc => cf/cf/generic-solaris.mc
+ cf/cf/generic-solaris2.cf => cf/cf/generic-solaris.cf
+ cf/ostype/aux.m4 => cf/ostype/a-ux.m4
+
8.11.6/8.11.6 2001/08/20
SECURITY: Fix a possible memory access violation when specifying
out-of-bounds debug parameters. Problem detected by
@@ -1643,7 +2539,7 @@ summary of the changes in that release.
CONFIG: OSTYPE(`bsdi1.0') and OSTYPE(`bsdi2.0') have been
deprecated and may be removed from a future release.
BSD/OS users should begin using OSTYPE(`bsdi').
- CONFIG: OpenBSD 2.4 installs mail.local non-set-user-id root. This
+ CONFIG: OpenBSD 2.4 installs mail.local non-set-user-ID root. This
requires a new OSTYPE(`openbsd'). From Todd C. Miller of
Courtesan Consulting.
CONFIG: New OSTYPE(`hpux11') for HP/UX 11.X.
@@ -1903,7 +2799,7 @@ summary of the changes in that release.
the others (if it exists).
DEVTOOLS: Change order of LIBS: first product specific libraries
then the default ones.
- MAIL.LOCAL: Will not be installed set-user-id root. To use mail.local
+ MAIL.LOCAL: Will not be installed set-user-ID root. To use mail.local
as local delivery agent without LMTP mode, use
MODIFY_MAILER_FLAGS(`LOCAL', `+S')
to set the S flag.
@@ -2458,7 +3354,7 @@ summary of the changes in that release.
uid and gid for user bin instead of daemon. If DefaultUser
is set in the configuration file, that value overrides this
default.
- SECURITY: Since 8.8.7, the check for non-set-user-id binaries
+ SECURITY: Since 8.8.7, the check for non-set-user-ID binaries
interfered with setting an alternate group id for the
RunAsUser option. Problem noted by Randall Winchester of
the University of Maryland.
@@ -3126,7 +4022,7 @@ summary of the changes in that release.
In some cases, errors during an SMTP session could leave files
open or locked.
Better handling of missing file descriptors (0, 1, 2) on startup.
- Better handling of non-set-user-id binaries -- avoids certain obnoxious
+ Better handling of non-set-user-ID binaries -- avoids certain obnoxious
errors during testing.
Errors in file locking of NEWDB maps had the incorrect file name
printed in the error message.
@@ -3518,7 +4414,7 @@ summary of the changes in that release.
change to the sendmail map code was made in 8.8.3. Problem
noted by Gregory Neil Shapiro.
MAKEMAP: Give warnings on file problems such as map files that are
- symbolic links; although makemap is not set-user-id root, it is
+ symbolic links; although makemap is not set-user-ID root, it is
often run as root and hence has the potential for the same
sorts of problems as alias rebuilds.
MAKEMAP: Change compilation so that it will link properly on
@@ -4304,7 +5200,7 @@ summary of the changes in that release.
Fix problem finding network interface addresses. Patch from
Motonori Nakamura.
Don't reject qf entries that are not owned by your effective uid if
- you are not running set-user-id; this makes management of
+ you are not running set-user-ID; this makes management of
certain kinds of firewall setups difficult. Patch
suggested by Eamonn Coleman of Qualcomm.
Add persistent host status. This keeps the information normally
@@ -4674,7 +5570,7 @@ summary of the changes in that release.
failure in the hosts.files map. This error caused hard
bounces when it should have requeued.
Aliases to files such as /users/bar/foo/inbox, with /users/bar/foo
- owned by bar mode 700 and inbox being set-user-id bar stopped
+ owned by bar mode 700 and inbox being set-user-ID bar stopped
working properly due to excessive paranoia. Pointed out by
John Hawkinson of Panix.
An SMTP RCPT command referencing a host that gave a nameserver
@@ -5348,7 +6244,7 @@ summary of the changes in that release.
the aliases file: use the default uid/gid instead of the
real uid/gid. This allows you to create a file owned by
and writable only by the default uid/gid that will work
- all the time (without having the set-user-id bit set). Change
+ all the time (without having the set-user-ID bit set). Change
suggested by Shau-Ping Lo and Andrew Cheng of Sun
Microsystems.
Add "DialDelay" option (no short name) to provide an "extra"
diff --git a/contrib/sendmail/cf/README b/contrib/sendmail/cf/README
index 820c609..d8d4fa2 100644
--- a/contrib/sendmail/cf/README
+++ b/contrib/sendmail/cf/README
@@ -1,28 +1,50 @@
SENDMAIL CONFIGURATION FILES
-This document describes the sendmail configuration files. This package
-requires a post-V7 version of m4; if you are running the 4.2bsd, SysV.2, or
-7th Edition version. SunOS's /usr/5bin/m4 or BSD-Net/2's m4 both work.
-GNU m4 version 1.1 or later also works. Unfortunately, the M4 on BSDI 1.0
-doesn't work -- you'll have to use a Net/2 or GNU version. GNU m4 is
-available from ftp://ftp.gnu.org/pub/gnu/m4/m4-1.4.tar.gz (check for the
-latest version). EXCEPTIONS: DEC's m4 on Digital UNIX 4.x is broken (3.x
-is fine). Use GNU m4 on this platform.
-
-To get started, you may want to look at tcpproto.mc (for TCP-only sites),
-uucpproto.mc (for UUCP-only sites), and clientproto.mc (for clusters of
-clients using a single mail host). Others are versions previously used at
-Berkeley. For example, ucbvax has gone away, but ucbvax.mc demonstrates
-some interesting techniques.
-
-*******************************************************************
-*** BE SURE YOU CUSTOMIZE THESE FILES! They have some ***
-*** Berkeley-specific assumptions built in, such as the name ***
-*** of their UUCP-relay. You'll want to create your own ***
-*** domain description, and use that in place of ***
-*** domain/Berkeley.EDU.m4. ***
-*******************************************************************
+This document describes the sendmail configuration files. It
+explains how to create a sendmail.cf file for use with sendmail.
+It also describes how to set options for sendmail which are explained
+in the Sendmail Installation and Operation guide (doc/op/op.me).
+
+To get started, you may want to look at tcpproto.mc (for TCP-only
+sites) and clientproto.mc (for clusters of clients using a single
+mail host), or the generic-*.mc files as operating system-specific
+examples.
+
+Table of Content:
+
+INTRODUCTION AND EXAMPLE
+A BRIEF INTRODUCTION TO M4
+FILE LOCATIONS
+OSTYPE
+DOMAINS
+MAILERS
+FEATURES
+HACKS
+SITE CONFIGURATION
+USING UUCP MAILERS
+TWEAKING RULESETS
+MASQUERADING AND RELAYING
+USING LDAP FOR ALIASES, MAPS, AND CLASSES
+LDAP ROUTING
+ANTI-SPAM CONFIGURATION CONTROL
+STARTTLS
+SMTP AUTHENTICATION
+ADDING NEW MAILERS OR RULESETS
+ADDING NEW MAIL FILTERS
+QUEUE GROUP DEFINITIONS
+NON-SMTP BASED CONFIGURATIONS
+WHO AM I?
+ACCEPTING MAIL FOR MULTIPLE NAMES
+USING MAILERTABLES
+USING USERDB TO MAP FULL NAMES
+MISCELLANEOUS SPECIAL FEATURES
+SECURITY NOTES
+TWEAKING CONFIGURATION OPTIONS
+MESSAGE SUBMISSION PROGRAM
+FORMAT OF FILES AND MAPS
+DIRECTORY LAYOUT
+ADMINISTRATIVE DETAILS
+--------------------------+
@@ -54,7 +76,7 @@ Let's examine a typical .mc file:
divert(-1)
#
- # Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ # Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -106,11 +128,10 @@ definition appropriate for your environment.
MAILER(`local')
MAILER(`smtp')
-These describe the mailers used at the default CS site. The
-local mailer is always included automatically. Beware: MAILER
-declarations should always be at the end of the configuration file,
-and MAILER(`smtp') should always precede MAILER(`procmail'), and
-MAILER(`uucp'). The general rules are that the order should be:
+These describe the mailers used at the default CS site. The local
+mailer is always included automatically. Beware: MAILER declarations
+should always be at the end of the configuration file. The general
+rules are that the order should be:
VERSIONID
OSTYPE
@@ -118,6 +139,7 @@ MAILER(`uucp'). The general rules are that the order should be:
FEATURE
local macro definitions
MAILER
+ LOCAL_CONFIG
LOCAL_RULE_*
LOCAL_RULESETS
@@ -126,6 +148,14 @@ influence a FEATURE() should be done before that feature. For example,
a define(`PROCMAIL_MAILER_PATH', ...) should be done before
FEATURE(`local_procmail').
+*******************************************************************
+*** BE SURE YOU CUSTOMIZE THESE FILES! They have some ***
+*** Berkeley-specific assumptions built in, such as the name ***
+*** of their UUCP-relay. You'll want to create your own ***
+*** domain description, and use that in place of ***
+*** domain/Berkeley.EDU.m4. ***
+*******************************************************************
+
+----------------------------+
| A BRIEF INTRODUCTION TO M4 |
@@ -159,6 +189,20 @@ expanded. This also applies to
because ``define'' is an M4 keyword. If you want to use them, surround
them with directed quotes, `like this'.
+
+Notice:
+-------
+
+This package requires a post-V7 version of m4; if you are running the
+4.2bsd, SysV.2, or 7th Edition version. SunOS's /usr/5bin/m4 or
+BSD-Net/2's m4 both work. GNU m4 version 1.1 or later also works.
+Unfortunately, the M4 on BSDI 1.0 doesn't work -- you'll have to use a
+Net/2 or GNU version. GNU m4 is available from
+ftp://ftp.gnu.org/pub/gnu/m4/m4-1.4.tar.gz (check for the latest version).
+EXCEPTIONS: DEC's m4 on Digital UNIX 4.x is broken (3.x is fine). Use GNU
+m4 on this platform.
+
+
+----------------+
| FILE LOCATIONS |
+----------------+
@@ -265,7 +309,10 @@ QUEUE_DIR [/var/spool/mqueue] The directory containing
directories. The names 'qf', 'df', and 'xf' are
reserved as specific subdirectories for the
corresponding queue file types as explained in
- doc/op/op.me.
+ doc/op/op.me. See also QUEUE GROUP DEFINITIONS.
+MSP_QUEUE_DIR [/var/spool/clientmqueue] The directory containing
+ queue files for the MSP (Mail Submission Program,
+ see sendmail/SECURITY).
STATUS_FILE [/etc/mail/statistics] The file containing status
information.
LOCAL_MAILER_PATH [/bin/mail] The program used to deliver local mail.
@@ -294,13 +341,18 @@ LOCAL_SHELL_ARGS [sh -c $u] The arguments passed to deliver "prog"
mail.
LOCAL_SHELL_DIR [$z:/] The directory search path in which the
shell should run.
+LOCAL_MAILER_QGRP [undefined] The queue group for the local mailer.
USENET_MAILER_PATH [/usr/lib/news/inews] The name of the program
used to submit news.
USENET_MAILER_FLAGS [rsDFMmn] The mailer flags for the usenet mailer.
USENET_MAILER_ARGS [-m -h -n] The command line arguments for the
- usenet mailer.
+ usenet mailer. NOTE: Some versions of inews
+ (such as those shipped with newer versions of INN)
+ use different flags. Double check the defaults
+ against the inews man page.
USENET_MAILER_MAX [100000] The maximum size of messages that will
be accepted by the usenet mailer.
+USENET_MAILER_QGRP [undefined] The queue group for the usenet mailer.
SMTP_MAILER_FLAGS [undefined] Flags added to SMTP mailer. Default
flags are `mDFMuX' for all SMTP-based mailers; the
"esmtp" mailer adds `a'; "smtp8" adds `8'; and
@@ -322,6 +374,11 @@ ESMTP_MAILER_ARGS [TCP $h] The arguments passed to the esmtp mailer.
SMTP8_MAILER_ARGS [TCP $h] The arguments passed to the smtp8 mailer.
DSMTP_MAILER_ARGS [TCP $h] The arguments passed to the dsmtp mailer.
RELAY_MAILER_ARGS [TCP $h] The arguments passed to the relay mailer.
+SMTP_MAILER_QGRP [undefined] The queue group for the smtp mailer.
+ESMTP_MAILER_QGRP [undefined] The queue group for the esmtp mailer.
+SMTP8_MAILER_QGRP [undefined] The queue group for the smtp8 mailer.
+DSMTP_MAILER_QGRP [undefined] The queue group for the dsmtp mailer.
+RELAY_MAILER_QGRP [undefined] The queue group for the relay mailer.
RELAY_MAILER_MAXMSGS [undefined] If defined, the maximum number of
messages to deliver in a single connection for the
relay mailer.
@@ -341,6 +398,7 @@ UUCP_MAILER_CHARSET [undefined] If defined, messages containing 8-bit data
that ARRIVE from an address that resolves to one of
the UUCP mailers and which are converted to MIME will
be labeled with this character set.
+UUCP_MAILER_QGRP [undefined] The queue group for the UUCP mailers.
FAX_MAILER_PATH [/usr/local/lib/fax/mailfax] The program used to
submit FAX messages.
FAX_MAILER_ARGS [mailfax $u $h $f] The arguments passed to the FAX
@@ -351,6 +409,7 @@ POP_MAILER_PATH [/usr/lib/mh/spop] The pathname of the POP mailer.
POP_MAILER_FLAGS [Penu] Flags added to POP mailer. Flags lsDFMq
are always added.
POP_MAILER_ARGS [pop $u] The arguments passed to the POP mailer.
+POP_MAILER_QGRP [undefined] The queue group for the pop mailer.
PROCMAIL_MAILER_PATH [/usr/local/bin/procmail] The path to the procmail
program. This is also used by
FEATURE(`local_procmail').
@@ -364,15 +423,18 @@ PROCMAIL_MAILER_ARGS [procmail -Y -m $h $f $u] The arguments passed to
instead.
PROCMAIL_MAILER_MAX [undefined] If set, the maximum size message that
will be accepted by the procmail mailer.
+PROCMAIL_MAILER_QGRP [undefined] The queue group for the procmail mailer.
MAIL11_MAILER_PATH [/usr/etc/mail11] The path to the mail11 mailer.
MAIL11_MAILER_FLAGS [nsFx] Flags for the mail11 mailer.
MAIL11_MAILER_ARGS [mail11 $g $x $h $u] Arguments passed to the mail11
mailer.
+MAIL11_MAILER_QGRP [undefined] The queue group for the mail11 mailer.
PH_MAILER_PATH [/usr/local/etc/phquery] The path to the phquery
program.
PH_MAILER_FLAGS [ehmu] Flags for the phquery mailer. Flags nrDFM
are always set.
PH_MAILER_ARGS [phquery -- $u] -- arguments to the phquery mailer.
+PH_MAILER_QGRP [undefined] The queue group for the ph mailer.
CYRUS_MAILER_FLAGS [Ah5@/:|] The flags used by the cyrus mailer. The
flags lsDFMnPq are always included.
CYRUS_MAILER_PATH [/usr/cyrus/bin/deliver] The program used to deliver
@@ -383,6 +445,7 @@ CYRUS_MAILER_MAX [undefined] If set, the maximum size message that
will be accepted by the cyrus mailer.
CYRUS_MAILER_USER [cyrus:mail] The user and group to become when
running the cyrus mailer.
+CYRUS_MAILER_QGRP [undefined] The queue group for the cyrus mailer.
CYRUS_BB_MAILER_FLAGS [u] The flags used by the cyrusbb mailer.
The flags lsDFMnP are always included.
CYRUS_BB_MAILER_ARGS [deliver -e -m $u] The arguments passed
@@ -397,6 +460,8 @@ QPAGE_MAILER_ARGS [qpage -l0 -m -P$u] The arguments passed
to deliver qpage mail.
QPAGE_MAILER_MAX [4096] If set, the maximum size message that
will be accepted by the qpage mailer.
+QPAGE_MAILER_QGRP [undefined] The queue group for the qpage mailer.
+LOCAL_PROG_QGRP [undefined] The queue group for the prog mailer.
Note: to tweak Name_MAILER_FLAGS use the macro MODIFY_MAILER_FLAGS:
MODIFY_MAILER_FLAGS(`Name', `change') where Name is the first part of
@@ -407,7 +472,9 @@ the default value. Example:
MODIFY_MAILER_FLAGS(`LOCAL', `+e')
-will add the flag `e' to LOCAL_MAILER_FLAGS.
+will add the flag `e' to LOCAL_MAILER_FLAGS. Notice: there are
+several smtp mailers all of which are manipulated individually.
+See the section MAILERS for the available mailer names.
WARNING: The FEATUREs local_lmtp and local_procmail set LOCAL_MAILER_FLAGS
unconditionally, i.e., without respecting any definitions in an
OSTYPE setting.
@@ -436,7 +503,7 @@ LOCAL_RELAY The site that will handle unqualified names -- that
is, names without an @domain extension.
Normally MAIL_HUB is preferred for this function.
LOCAL_RELAY is mostly useful in conjunction with
- FEATURE(stickyhost) -- see the discussion of
+ FEATURE(`stickyhost') -- see the discussion of
stickyhost below. If not set, they are assumed to
belong on this machine. This allows you to have a
central site to store a company- or department-wide
@@ -466,18 +533,14 @@ single machine sitting off somewhere, it is probably more work than
it's worth. This is just a mechanism for combining "domain dependent
knowledge" into one place.
+
+---------+
| MAILERS |
+---------+
There are fewer mailers supported in this version than the previous
version, owing mostly to a simpler world. As a general rule, put the
-MAILER definitions last in your .mc file, and always put MAILER(`smtp')
-before MAILER(`uucp') and MAILER(`procmail') -- several features and
-definitions will modify the definition of mailers, and the smtp mailer
-modifies the UUCP mailer. Moreover, MAILER(`cyrus'), MAILER(`pop'),
-MAILER(`phquery'), and MAILER(`usenet') must be defined after
-MAILER(`local').
+MAILER definitions last in your .mc file.
local The local and prog mailers. You will almost always
need these; the only exception is if you relay ALL
@@ -502,9 +565,9 @@ uucp The UNIX-to-UNIX Copy Program mailer. Actually, this
"uucp-new" (a.k.a. "suucp"). The latter is for when you
know that the UUCP mailer at the other end can handle
multiple recipients in one transfer. If the smtp mailer
- is also included in your configuration, two other mailers
- ("uucp-dom" and "uucp-uudom") are also defined [warning:
- you MUST specify MAILER(smtp) before MAILER(uucp)]. When you
+ is included in your configuration, two other mailers
+ ("uucp-dom" and "uucp-uudom") are also defined [warning: you
+ MUST specify MAILER(`smtp') before MAILER(`uucp')]. When you
include the uucp mailer, sendmail looks for all names in
class {U} and sends them to the uucp-old mailer; all
names in class {Y} are sent to uucp-new; and all
@@ -545,6 +608,9 @@ procmail An interface to procmail (does not come with sendmail).
If you use this with FEATURE(`local_procmail'), the FEATURE
should be listed first.
+ Of course there are other ways to solve this particular
+ problem, e.g., a catch-all entry in a virtusertable.
+
mail11 The DECnet mail11 mailer, useful only if you have the mail11
program from gatekeeper.dec.com:/pub/DEC/gwtools (and
DECnet, of course). This is for Phase IV DECnet support;
@@ -558,11 +624,12 @@ phquery The phquery program. This is somewhat counterintuitively
cyrus The cyrus and cyrusbb mailers. The cyrus mailer delivers to
a local cyrus user. this mailer can make use of the
- "user+detail@local.host" syntax; it will deliver the mail to
- the user's "detail" mailbox if the mailbox's ACL permits.
- The cyrusbb mailer delivers to a system-wide cyrus mailbox
- if the mailbox's ACL permits. The cyrus mailer must be
- defined after the local mailer.
+ "user+detail@local.host" syntax (see
+ FEATURE(`preserve_local_plus_detail')); it will deliver the
+ mail to the user's "detail" mailbox if the mailbox's ACL
+ permits. The cyrusbb mailer delivers to a system-wide
+ cyrus mailbox if the mailbox's ACL permits. The cyrus
+ mailer must be defined after the local mailer.
qpage A mailer for QuickPage, a pager interface. See
http://www.qpage.org/ for further information.
@@ -585,7 +652,7 @@ example, the .mc line:
FEATURE(`use_cw_file')
tells sendmail that you want to have it read an /etc/mail/local-host-names
-file to get values for class {w}. The FEATURE may contain up to 9
+file to get values for class {w}. A FEATURE may contain up to 9
optional parameters -- for example:
FEATURE(`mailertable', `dbm /usr/lib/mailertable')
@@ -600,6 +667,11 @@ if you specify an argument to a FEATURE. DATABASE_MAP_TYPE is only used
if no argument is given for the FEATURE. It must be specified before any
feature that uses a map.
+Also, features which can take a map definition as an argument can also take
+the special keyword `LDAP'. If that keyword is used, the map will use the
+LDAP definition described in the ``USING LDAP FOR ALIASES, MAPS, AND
+CLASSES'' section below.
+
Available features are:
use_cw_file Read the file /etc/mail/local-host-names file to get
@@ -627,7 +699,7 @@ nouucp Don't route UUCP addresses. This feature takes one
part unless it originates from a system
that is allowed to relay.
`nospecial': don't do anything special with "!".
- Warnings: 1. See the NOTICE in the ANTI-SPAM section.
+ Warnings: 1. See the notice in the anti-spam section.
2. don't remove "!" from OperatorChars if `reject' is
given as parameter.
@@ -752,7 +824,8 @@ always_add_domain
mail. Normally it is not added on unqualified names.
However, if you use a shared message store but do not use
the same user name space everywhere, you may need the host
- name on local names.
+ name on local names. An optional argument specifies
+ another domain to be added than the local.
allmasquerade If masquerading is enabled (using MASQUERADE_AS), this
feature will cause recipient addresses to also masquerade
@@ -793,18 +866,26 @@ masquerade_entire_domain
NOTE: only domains within your jurisdiction and
current hierarchy should be masqueraded using this.
+local_no_masquerade
+ This feature prevents the local mailer from masquerading even
+ if MASQUERADE_AS is used. MASQUERADE_AS will only have effect
+ on addresses of mail going outside the local domain.
+
genericstable This feature will cause unqualified addresses (i.e., without
a domain) and addresses with a domain listed in class {G}
to be looked up in a map and turned into another ("generic")
form, which can change both the domain name and the user name.
- This is similar to the userdb functionality. The same types of
- addresses as for masquerading are looked up, i.e., only header
- sender addresses unless the allmasquerade and/or
- masquerade_envelope features are given. Qualified addresses
- must have the domain part in class {G}; entries can
- be added to this class by the macros GENERICS_DOMAIN or
- GENERICS_DOMAIN_FILE (analogously to MASQUERADE_DOMAIN and
- MASQUERADE_DOMAIN_FILE, see below).
+ Notice: if you use an MSP (as it is default starting with
+ 8.12), the MTA will only receive qualified addresses from the
+ MSP (as required by the RFCs). Hence you need to add your
+ domain to class {G}. This feature is similar to the userdb
+ functionality. The same types of addresses as for
+ masquerading are looked up, i.e., only header sender
+ addresses unless the allmasquerade and/or masquerade_envelope
+ features are given. Qualified addresses must have the domain
+ part in class {G}; entries can be added to this class by the
+ macros GENERICS_DOMAIN or GENERICS_DOMAIN_FILE (analogously
+ to MASQUERADE_DOMAIN and MASQUERADE_DOMAIN_FILE, see below).
The argument of FEATURE(`genericstable') may be the map
definition; the default map definition is:
@@ -839,8 +920,8 @@ virtusertable A domain-specific form of aliasing, allowing multiple
info@foo.com foo-info
info@bar.com bar-info
- joe@bar.com error:nouser No such user here
- jax@bar.com error:D.S.N:unavailable Address invalid
+ joe@bar.com error:nouser 550 No such user here
+ jax@bar.com error:5.7.0:550 Address invalid
@baz.org jane@example.net
then mail addressed to info@foo.com will be sent to the
@@ -849,7 +930,7 @@ virtusertable A domain-specific form of aliasing, allowing multiple
will be sent to jane@example.net, mail to joe@bar.com will
be rejected with the specified error message, and mail to
jax@bar.com will also have a RFC 1893 compliant error code
- D.S.N.
+ 5.7.0.
The username from the original address is passed
as %1 allowing:
@@ -858,19 +939,24 @@ virtusertable A domain-specific form of aliasing, allowing multiple
meaning someone@foo.org will be sent to someone@example.com.
Additionally, if the local part consists of "user+detail"
- then "detail" is passed as %2 when a match against user+*
- is attempted, so entries like
+ then "detail" is passed as %2 and "+detail" is passed as %3
+ when a match against user+* is attempted, so entries like
old+*@foo.org new+%2@example.com
gen+*@foo.org %2@example.com
- +*@foo.org %1+%2@example.com
+ +*@foo.org %1%3@example.com
+ X++@foo.org Z%3@example.com
+ @bar.org %1%3
and other forms are possible. Note: to preserve "+detail"
- for a default case (@domain) +*@domain must be used as
- exemplified above.
+ for a default case (@domain) %1%3 must be used as RHS.
+ There are two wildcards after "+": "+" matches only a non-empty
+ detail, "*" matches also empty details, e.g., user+@foo.org
+ matches +*@foo.org but not ++@foo.org. This can be used
+ to ensure that the parameters %2 and %3 are not empty.
All the host names on the left hand side (foo.com, bar.com,
- and baz.org) must be in class {w} or class {VirtHost}, the
+ and baz.org) must be in class {w} or class {VirtHost}. The
latter can be defined by the macros VIRTUSER_DOMAIN or
VIRTUSER_DOMAIN_FILE (analogously to MASQUERADE_DOMAIN and
MASQUERADE_DOMAIN_FILE, see below). If VIRTUSER_DOMAIN or
@@ -1025,13 +1111,13 @@ relay_based_on_MX
relay_mail_from
Allows relaying if the mail sender is listed as RELAY in
the access map. If an optional argument `domain' is given,
- the domain portion of the mail sender is checked too.
- This should only be used if absolutely necessary as the
- sender address can be easily forged. Use of this feature
- requires the "From:" tag be prepended to the key in the
- access map; see the discussion of tags and
- FEATURE(`relay_mail_from') in the section on ANTI-SPAM
- CONFIGURATION CONTROL.
+ relaying can be allowed just based on the domain portion
+ of the sender address. This feature should only be used if
+ absolutely necessary as the sender address can be easily
+ forged. Use of this feature requires the "From:" tag be
+ prepended to the key in the access map; see the discussion
+ of tags and FEATURE(`relay_mail_from') in the section on
+ anti-spam configuration control.
relay_local_from
Allows relaying if the domain portion of the mail sender
@@ -1066,13 +1152,15 @@ accept_unresolvable_domains
access_db Turns on the access database feature. The access db gives
you the ability to allow or refuse to accept mail from
- specified domains for administrative reasons. By default,
- the access database specification is:
+ specified domains for administrative reasons. Moreover,
+ it can control the behavior of sendmail in various situations.
+ By default, the access database specification is:
- hash /etc/mail/access
+ hash -T<TMPF> /etc/mail/access
- The format of the database is described in the anti-spam
- configuration control section later in this document.
+ See the anti-spam configuration control section for further
+ important information about this feature. Notice:
+ "-T<TMPF>" is meant literal, do not replace it by anything.
blacklist_recipients
Turns on the ability to block incoming mail for certain
@@ -1087,25 +1175,27 @@ delay_checks The rulesets check_mail and check_relay will not be called
when a client connects or issues a MAIL command, respectively.
Instead, those rulesets will be called by the check_rcpt
ruleset; they will be skipped under certain circumstances.
- See "Delay all checks" in "ANTI-SPAM CONFIGURATION CONTROL".
-
-rbl This feature is deprecated! Please use dnsbl instead.
- Turns on rejection of hosts found in the Realtime Blackhole
- List. If an argument is provided it is used as the domain
- in which blocked hosts are listed; otherwise, the main RBL
- domain rbl.maps.vix.com is used (see NOTE below). For
- details, see http://maps.vix.com/rbl/.
+ See "Delay all checks" in the anti-spam configuration control
+ section. Note: this feature is incompatible to the versions
+ in 8.10 and 8.11.
dnsbl Turns on rejection of hosts found in an DNS based rejection
list. If an argument is provided it is used as the domain
in which blocked hosts are listed; otherwise it defaults to
blackholes.mail-abuse.org. An explanation for an DNS based
- rejection list can be found http://mail-abuse.org/rbl/. A
- second argument can be used to change the default error
- message of Mail from $&{client_addr} refused by blackhole site
- SERVER where SERVER is replaced by the first argument. This
- feature can be included several times to query different DNS
- based rejection lists.
+ rejection list can be found at http://mail-abuse.org/rbl/.
+ A second argument can be used to change the default error
+ message. Without that second argument, the error message
+ will be
+ Mail from IP-ADDRESS refused by blackhole site SERVER
+ where IP-ADDRESS and SERVER are replaced by the appropriate
+ information. By default, temporary lookup failures are
+ ignored. This behavior can be changed by specifying a
+ third argument, which must be either `t' or a full error
+ message. See the anti-spam configuration control section for
+ an example. The dnsbl feature can be included several times
+ to query different DNS based rejection lists. See also
+ enhdnsbl for an enhanced version.
NOTE: The default DNS blacklist, blackholes.mail-abuse.org,
is a service offered by the Mail Abuse Prevention System
@@ -1114,6 +1204,30 @@ dnsbl Turns on rejection of hosts found in an DNS based rejection
haven't subscribed. Contact MAPS to subscribe
(http://mail-abuse.org/).
+enhdnsbl Enhanced version of dnsbl (see above). Further arguments
+ (up to 5) can be used to specify specific return values
+ from lookups. Temporary lookup failures are ignored unless
+ a third argument is given, which must be either `t' or a full
+ error message. By default, any successful lookup will
+ generate an error. Otherwise the result of the lookup is
+ compared with the supplied argument(s), and only if a match
+ occurs an error is generated. For example,
+
+ FEATURE(`enhdnsbl', `dnsbl.example.com', `', `t', `127.0.0.2.')
+
+ will reject the e-mail if the lookup returns the value
+ ``127.0.0.2.'', or generate a 451 response if the lookup
+ temporarily failed. The arguments can contain metasymbols
+ as they are allowed in the LHS of rules. As the example
+ shows, the default values are also used if an empty argument,
+ i.e., `', is specified. This feature requires that sendmail
+ has been compiled with the flag DNSMAP (see sendmail/README).
+
+lookupdotdomain Look up also .domain in the access map. This allows to
+ match only subdomains. It does not work well with
+ FEATURE(`relay_hosts_only'), because most lookups for
+ subdomains are suppressed by the latter feature.
+
loose_relay_check
Normally, if % addressing is used for a recipient, e.g.
user%site@othersite, and othersite is in class {R}, the
@@ -1121,11 +1235,69 @@ loose_relay_check
user@site for relaying. This feature changes that
behavior. It should not be needed for most installations.
+authinfo Provide a separate map for client side authentication
+ information. See SMTP AUTHENTICATION for details.
+ By default, the authinfo database specification is:
+
+ hash /etc/mail/authinfo
+
+preserve_luser_host
+ Preserve the name of the recipient host if LUSER_RELAY is
+ used. Without this option, the domain part of the
+ recipient address will be replaced by the host specified as
+ LUSER_RELAY. This feature only works if the hostname is
+ passed to the mailer (see mailer triple in op.me). Note
+ that in the default configuration the local mailer does not
+ receive the hostname, i.e., the mailer triple has an empty
+ hostname.
+
+preserve_local_plus_detail
+ Preserve the +detail portion of the address when passing
+ address to local delivery agent. Disables alias and
+ .forward +detail stripping (e.g., given user+detail, only
+ that address will be looked up in the alias file; user+* and
+ user will not be looked up). Only use if the local
+ delivery agent in use supports +detail addressing.
+
+compat_check Enable ruleset check_compat to look up pairs of addresses
+ with the Compat: tag -- Compat:sender<@>recipient -- in the
+ access map. Valid values for the RHS include
+ DISCARD silently discard recipient
+ TEMP: return a temporary error
+ ERROR: return a permanent error
+ In the last two cases, a 4xy/5xy SMTP reply code should
+ follow the colon.
+
no_default_msa Don't generate the default MSA daemon, i.e.,
DAEMON_OPTIONS(`Port=587,Name=MSA,M=E')
To define a MSA daemon with other parameters, use this
FEATURE and introduce new settings via DAEMON_OPTIONS().
+msp Defines config file for Message Submission Program.
+ See sendmail/SECURITY for details and cf/cf/submit.mc
+ how to use it. An optional argument can be used to
+ override the default of `localhost' to use as host to send
+ all e-mails to. If `MSA' is specified as second argument
+ then port 587 is used to contact the server. Example:
+
+ FEATURE(`msp', `', `MSA')
+
+ Some more hints about possible changes can be found below
+ in the section MESSAGE SUBMISSION PROGRAM.
+
+queuegroup A simple example how to select a queue group based
+ on the full e-mail address or the domain of the
+ recipient. Selection is done via entries in the
+ access map using the tag QGRP:, for example:
+
+ QGRP:example.com main
+ QGRP:friend@some.org others
+ QGRP:my.domain local
+
+ where "main", "others", and "local" are names of
+ queue groups. If an argument is specified, it is used
+ as default queue group.
+
+-------+
| HACKS |
+-------+
@@ -1146,7 +1318,7 @@ subdomains.
*****************************************************
* This section is really obsolete, and is preserved *
* only for back compatibility. You should plan on *
- * using mailertables for new installations. In *
+ * using mailertables for new installations. In *
* particular, it doesn't work for the newer forms *
* of UUCP mailers, such as uucp-uudom. *
*****************************************************
@@ -1237,7 +1409,8 @@ The four mailers are:
uucp-dom
This UUCP mailer keeps everything as domain addresses.
Basically, it uses the SMTP mailer rewriting rules. This mailer
- is only included if MAILER(`smtp') is also specified.
+ is only included if MAILER(`smtp') is specified before
+ MAILER(`uucp').
Unfortunately, a lot of UUCP mailer transport agents require
bangified addresses in the envelope, although you can use
@@ -1252,7 +1425,7 @@ The four mailers are:
at all (e.g., "wolf") or the host component is a UUCP host name
instead of a domain name ("somehost!wolf" instead of
"some.dom.ain!wolf"). This is also included only if MAILER(`smtp')
- is also specified.
+ is also specified earlier.
Examples:
@@ -1378,7 +1551,10 @@ To exempt hosts or subdomains from being masqueraded, you can use
MASQUERADE_EXCEPTION(`host.domain')
This can come handy if you want to masquerade a whole domain
-except for one (or a few) host(s).
+except for one (or a few) host(s). If these names are in a file,
+you can use
+
+ MASQUERADE_EXCEPTION_FILE(`filename')
Normally only header addresses are masqueraded. If you want to
masquerade the envelope as well, use
@@ -1392,9 +1568,9 @@ You can add users to this list using
EXPOSED_USER(`usernames')
-This adds users to class {E}; you could also use something like
+This adds users to class {E}; you could also use
- FE/etc/mail/exposed-users
+ EXPOSED_USER_FILE(`filename')
You can also arrange to relay all unqualified names (that is, names
without @host) to a relay host. For example, if you have a central
@@ -1410,9 +1586,9 @@ locally aliased. You can add entries to this list using
LOCAL_USER(`usernames')
-This adds users to class {L}; you could also use something like
+This adds users to class {L}; you could also use
- FL/etc/mail/local-users
+ LOCAL_USER_FILE(`filename')
If you want all incoming mail sent to a centralized hub, as for a
shared /var/spool/mail scheme, use
@@ -1468,6 +1644,290 @@ specified with a terminal dot:
note the trailing dot ---^
++-------------------------------------------+
+| USING LDAP FOR ALIASES, MAPS, AND CLASSES |
++-------------------------------------------+
+
+LDAP can be used for aliases, maps, and classes by either specifying your
+own LDAP map specification or using the built-in default LDAP map
+specification. The built-in default specifications all provide lookups
+which match against either the machine's fully qualified hostname (${j}) or
+a "cluster". The cluster allows you to share LDAP entries among a large
+number of machines without having to enter each of the machine names into
+each LDAP entry. To set the LDAP cluster name to use for a particular
+machine or set of machines, set the confLDAP_CLUSTER m4 variable to a
+unique name. For example:
+
+ define(`confLDAP_CLUSTER', `Servers')
+
+Here, the word `Servers' will be the cluster name. As an example, assume
+that smtp.sendmail.org, etrn.sendmail.org, and mx.sendmail.org all belong
+to the Servers cluster.
+
+Some of the LDAP LDIF examples below show use of the Servers cluster.
+Every entry must have either a sendmailMTAHost or sendmailMTACluster
+attribute or it will be ignored. Be careful as mixing clusters and
+individual host records can have surprising results (see the CAUTION
+sections below).
+
+See the file cf/sendmail.schema for the actual LDAP schemas. Note that
+this schema (and therefore the lookups and examples below) is experimental
+at this point as it has had little public review. Therefore, it may change
+in future versions. Feedback via sendmail@sendmail.org is encouraged.
+
+-------
+Aliases
+-------
+
+The ALIAS_FILE (O AliasFile) option can be set to use LDAP for alias
+lookups. To use the default schema, simply use:
+
+ define(`ALIAS_FILE', `ldap:')
+
+By doing so, you will use the default schema which expands to a map
+declared as follows:
+
+ ldap -k (&(objectClass=sendmailMTAAliasObject)
+ (sendmailMTAAliasGrouping=aliases)
+ (|(sendmailMTACluster=${sendmailMTACluster})
+ (sendmailMTAHost=$j))
+ (sendmailMTAKey=%0))
+ -v sendmailMTAAliasValue
+
+NOTE: The macros shown above ${sendmailMTACluster} and $j are not actually
+used when the binary expands the `ldap:' token as the AliasFile option is
+not actually macro-expanded when read from the sendmail.cf file.
+
+Example LDAP LDIF entries might be:
+
+ dn: sendmailMTAKey=sendmail-list, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAAlias
+ objectClass: sendmailMTAAliasObject
+ sendmailMTAAliasGrouping: aliases
+ sendmailMTAHost: etrn.sendmail.org
+ sendmailMTAKey: sendmail-list
+ sendmailMTAAliasValue: ca@example.org
+ sendmailMTAAliasValue: eric
+ sendmailMTAAliasValue: gshapiro@example.com
+
+ dn: sendmailMTAKey=owner-sendmail-list, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAAlias
+ objectClass: sendmailMTAAliasObject
+ sendmailMTAAliasGrouping: aliases
+ sendmailMTAHost: etrn.sendmail.org
+ sendmailMTAKey: owner-sendmail-list
+ sendmailMTAAliasValue: eric
+
+ dn: sendmailMTAKey=postmaster, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAAlias
+ objectClass: sendmailMTAAliasObject
+ sendmailMTAAliasGrouping: aliases
+ sendmailMTACluster: Servers
+ sendmailMTAKey: postmaster
+ sendmailMTAAliasValue: eric
+
+Here, the aliases sendmail-list and owner-sendmail-list will be available
+only on etrn.sendmail.org but the postmaster alias will be available on
+every machine in the Servers cluster (including etrn.sendmail.org).
+
+CAUTION: aliases are additive so that entries like these:
+
+ dn: sendmailMTAKey=bob, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAAlias
+ objectClass: sendmailMTAAliasObject
+ sendmailMTAAliasGrouping: aliases
+ sendmailMTACluster: Servers
+ sendmailMTAKey: bob
+ sendmailMTAAliasValue: eric
+
+ dn: sendmailMTAKey=bob, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAAlias
+ objectClass: sendmailMTAAliasObject
+ sendmailMTAAliasGrouping: aliases
+ sendmailMTAHost: etrn.sendmail.org
+ sendmailMTAKey: bob
+ sendmailMTAAliasValue: gshapiro
+
+would mean that on all of the hosts in the cluster, mail to bob would go to
+eric EXCEPT on etrn.sendmail.org in which case it would go to BOTH eric and
+gshapiro.
+
+If you prefer not to use the default LDAP schema for your aliases, you can
+specify the map parameters when setting ALIAS_FILE. For example:
+
+ define(`ALIAS_FILE', `ldap:-k (&(objectClass=mailGroup)(mail=%0)) -v mgrpRFC822MailMember')
+
+----
+Maps
+----
+
+FEATURE()'s which take an optional map definition argument (e.g., access,
+mailertable, virtusertable, etc.) can instead take the special keyword
+`LDAP', e.g.:
+
+ FEATURE(`access_db', `LDAP')
+ FEATURE(`virtusertable', `LDAP')
+
+When this keyword is given, that map will use LDAP lookups consisting of
+the objectClass sendmailMTAClassObject, the attribute sendmailMTAMapName
+with the map name, a search attribute of sendmailMTAKey, and the value
+attribute sendmailMTAMapValue.
+
+The values for sendmailMTAMapName are:
+
+ FEATURE() sendmailMTAMapName
+ --------- ------------------
+ access_db access
+ authinfo authinfo
+ bitdomain bitdomain
+ domaintable domain
+ genericstable generics
+ mailertable mailer
+ uucpdomain uucpdomain
+ virtusertable virtuser
+
+For example, FEATURE(`mailertable', `LDAP') would use the map definition:
+
+ Kmailertable ldap -k (&(objectClass=sendmailMTAMapObject)
+ (sendmailMTAMapName=mailer)
+ (|(sendmailMTACluster=${sendmailMTACluster})
+ (sendmailMTAHost=$j))
+ (sendmailMTAKey=%0))
+ -1 -v sendmailMTAMapValue
+
+An example LDAP LDIF entry using this map might be:
+
+ dn: sendmailMTAMapName=mailer, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAMap
+ sendmailMTACluster: Servers
+ sendmailMTAMapName: mailer
+
+ dn: sendmailMTAKey=example.com, sendmailMTAMapName=mailer, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAMap
+ objectClass: sendmailMTAMapObject
+ sendmailMTAMapName: mailer
+ sendmailMTACluster: Servers
+ sendmailMTAKey: example.com
+ sendmailMTAMapValue: relay:[smtp.example.com]
+
+CAUTION: If your LDAP database contains the record above and *ALSO* a host
+specific record such as:
+
+ dn: sendmailMTAKey=example.com@etrn, sendmailMTAMapName=mailer, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAMap
+ objectClass: sendmailMTAMapObject
+ sendmailMTAMapName: mailer
+ sendmailMTAHost: etrn.sendmail.org
+ sendmailMTAKey: example.com
+ sendmailMTAMapValue: relay:[mx.example.com]
+
+then these entries will give unexpected results. When the lookup is done
+on etrn.sendmail.org, the effect is that there is *NO* match at all as maps
+require a single match. Since the host etrn.sendmail.org is also in the
+Servers cluster, LDAP would return two answers for the example.com map key
+in which case sendmail would treat this as no match at all.
+
+If you prefer not to use the default LDAP schema for your maps, you can
+specify the map parameters when using the FEATURE(). For example:
+
+ FEATURE(`access_db', `ldap:-1 -k (&(objectClass=mapDatabase)(key=%0)) -v value')
+
+-------
+Classes
+-------
+
+Normally, classes can be filled via files or programs. As of 8.12, they
+can also be filled via map lookups using a new syntax:
+
+ F{ClassName}mapkey@mapclass:mapspec
+
+mapkey is optional and if not provided the map key will be empty. This can
+be used with LDAP to read classes from LDAP. Note that the lookup is only
+done when sendmail is initially started. Use the special value `@LDAP' to
+use the default LDAP schema. For example:
+
+ RELAY_DOMAIN_FILE(`@LDAP')
+
+would put all of the attribute sendmailMTAClassValue values of LDAP records
+with objectClass sendmailMTAClass and an attribute sendmailMTAClassName of
+'R' into class $={R}. In other words, it is equivalent to the LDAP map
+specification:
+
+ F{R}@ldap:-k (&(objectClass=sendmailMTAClass)
+ (sendmailMTAClassName=R)
+ (|(sendmailMTACluster=${sendmailMTACluster})
+ (sendmailMTAHost=$j)))
+ -v sendmailMTAClassValue
+
+NOTE: The macros shown above ${sendmailMTACluster} and $j are not actually
+used when the binary expands the `@LDAP' token as class declarations are
+not actually macro-expanded when read from the sendmail.cf file.
+
+This can be used with class related commands such as RELAY_DOMAIN_FILE(),
+MASQUERADE_DOMAIN_FILE(), etc:
+
+ Command sendmailMTAClassName
+ ------- --------------------
+ CANONIFY_DOMAIN_FILE() Canonify
+ EXPOSED_USER_FILE() E
+ GENERICS_DOMAIN_FILE() G
+ LDAPROUTE_DOMAIN_FILE() LDAPRoute
+ LDAPROUTE_EQUIVALENT_FILE() LDAPRouteEquiv
+ LOCAL_USER_FILE() L
+ MASQUERADE_DOMAIN_FILE() M
+ MASQUERADE_EXCEPTION_FILE() N
+ RELAY_DOMAIN_FILE() R
+ VIRTUSER_DOMAIN_FILE() VirtHost
+
+You can also add your own as any 'F'ile class of the form:
+
+ F{ClassName}@LDAP
+ ^^^^^^^^^
+will use "ClassName" for the sendmailMTAClassName.
+
+An example LDAP LDIF entry would look like:
+
+ dn: sendmailMTAClassName=R, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAClass
+ sendmailMTACluster: Servers
+ sendmailMTAClassName: R
+ sendmailMTAClassValue: sendmail.org
+ sendmailMTAClassValue: example.com
+ sendmailMTAClassValue: 10.56.23
+
+CAUTION: If your LDAP database contains the record above and *ALSO* a host
+specific record such as:
+
+ dn: sendmailMTAClassName=R@etrn.sendmail.org, dc=sendmail, dc=org
+ objectClass: sendmailMTA
+ objectClass: sendmailMTAClass
+ sendmailMTAHost: etrn.sendmail.org
+ sendmailMTAClassName: R
+ sendmailMTAClassValue: example.com
+
+the result will be similar to the aliases caution above. When the lookup
+is done on etrn.sendmail.org, $={R} would contain all of the entries (from
+both the cluster match and the host match). In other words, the effective
+is additive.
+
+If you prefer not to use the default LDAP schema for your classes, you can
+specify the map parameters when using the class command. For example:
+
+ VIRTUSER_DOMAIN_FILE(`@ldap:-k (&(objectClass=virtHosts)(host=*)) -v host')
+
+Remember, macros can not be used in a class declaration as the binary does
+not expand them.
+
+
+--------------+
| LDAP ROUTING |
+--------------+
@@ -1483,19 +1943,33 @@ LDAPROUTE_DOMAIN(), e.g.:
LDAPROUTE_DOMAIN(`example.com')
+Additionally, you can specify equivalent domains for LDAP routing using
+LDAPROUTE_EQUIVALENT() and LDAPROUTE_EQUIVALENT_FILE(). 'Equivalent'
+hostnames are mapped to $M (the masqueraded hostname for the server) before
+the LDAP query. For example, if the mail is addressed to
+user@host1.example.com, normally the LDAP lookup would only be done for
+'user@host1.example.com' and '@host1.example.com'. However, if
+LDAPROUTE_EQUIVALENT(`host1.example.com') is used, the lookups would also be
+done on 'user@example.com' and '@example.com' after attempting the
+host1.example.com lookups.
+
By default, the feature will use the schemas as specified in the draft
and will not reject addresses not found by the LDAP lookup. However,
this behavior can be changed by giving additional arguments to the FEATURE()
command:
- FEATURE(`ldap_routing', <mailHost>, <mailRoutingAddress>, <bounce>)
+ FEATURE(`ldap_routing', <mailHost>, <mailRoutingAddress>, <bounce>, <detail>)
where <mailHost> is a map definition describing how to lookup an alternative
mail host for a particular address; <mailRoutingAddress> is a map definition
-describing how to lookup an alternative address for a particular address; and
+describing how to lookup an alternative address for a particular address;
the <bounce> argument, if present and not the word "passthru", dictates
that mail should be bounced if neither a mailHost nor mailRoutingAddress
-is found.
+is found; and <detail> indicates what actions to take if the address
+contains +detail information -- `strip' tries the lookup with the +detail
+and if no matches are found, strips the +detail and tries the lookup again;
+`preserve', does the same as `strip' but if a mailRoutingAddress match is
+found, the +detail information is copied to the new address.
The default <mailHost> map definition is:
@@ -1537,7 +2011,10 @@ address:
original address *OR*
bounced as unknown user
-The term "local" host above means the host specified is in class {w}.
+The term "local" host above means the host specified is in class {w}. If
+the result would mean sending the mail to a different host, that host is
+looked up in the mailertable before delivery.
+
Note that the last case depends on whether the third argument is given
to the FEATURE() command. The default is to deliver the message to the
original address.
@@ -1547,7 +2024,7 @@ inetLocalMailRecipient and the address be listed in a mailLocalAddress
attribute. If present, there must be only one mailHost attribute and it
must contain a fully qualified host name as its value. Similarly, if
present, there must be only one mailRoutingAddress attribute and it must
-contain an RFC 822 compliant address. Some example LDAP records (in ldif
+contain an RFC 822 compliant address. Some example LDAP records (in LDIF
format):
dn: uid=tom, o=example.com, c=US
@@ -1563,7 +2040,8 @@ This would deliver mail for tom@example.com to thomas@mailhost.example.com.
mailHost: eng.example.com
This would relay mail for dick@example.com to the same address but redirect
-the mail to MX records listed for the host eng.example.com.
+the mail to MX records listed for the host eng.example.com (unless the
+mailertable overrides).
dn: uid=harry, o=example.com, c=US
objectClass: inetLocalMailRecipient
@@ -1604,13 +2082,22 @@ If you really want to revert to the old behaviour, you will need to use
FEATURE(`promiscuous_relay'). You can allow certain domains to relay
through your server by adding their domain name or IP address to class
{R} using RELAY_DOMAIN() and RELAY_DOMAIN_FILE() or via the access database
-(described below). The file consists (like any other file based class)
-of entries listed on separate lines, e.g.,
+(described below). Note that IPv6 addresses must be prefaced with "IPv6:".
+The file consists (like any other file based class) of entries listed on
+separate lines, e.g.,
sendmail.org
128.32
- 1:2:3:4:5:6:7
+ IPv6:2002:c0a8:02c7
+ IPv6:2002:c0a8:51d2::23f4
host.mydomain.com
+ [UNIX:localhost]
+
+Notice: the last entry allows relaying for connections via a UNIX
+socket to the MTA/MSP. This might be necessary if your configuration
+doesn't allow relaying by other means in that case, e.g., by having
+localhost.$m in class {R} (make sure $m is not just a top level
+domain).
If you use
@@ -1627,16 +2114,20 @@ portion of an incoming recipient address by using
For example, if your server receives a recipient of user@domain.com
and domain.com lists your server in its MX records, the mail will be
-accepted for relay to domain.com. Note that this will stop spammers
-from using your host to relay spam but it will not stop outsiders from
-using your server as a relay for their site (that is, they set up an
-MX record pointing to your mail server, and you will relay mail addressed
-to them without any prior arrangement). Along the same lines,
+accepted for relay to domain.com. This feature may cause problems
+if MX lookups for the recipient domain are slow or time out. In that
+case, mail will be temporarily rejected. It is usually better to
+maintain a list of hosts/domains for which the server acts as relay.
+Note also that this feature will stop spammers from using your host
+to relay spam but it will not stop outsiders from using your server
+as a relay for their site (that is, they set up an MX record pointing
+to your mail server, and you will relay mail addressed to them
+without any prior arrangement). Along the same lines,
FEATURE(`relay_local_from')
will allow relaying if the sender specifies a return path (i.e.
-MAIL FROM: <user@domain>) domain which is a local domain. This a
+MAIL FROM: <user@domain>) domain which is a local domain. This is a
dangerous feature as it will allow spammers to spam using your mail
server by simply specifying a return address of user@your.domain.com.
It should not be used unless absolutely necessary.
@@ -1648,10 +2139,15 @@ which allows relaying if the mail sender is listed as RELAY in the
access map. If an optional argument `domain' is given, the domain
portion of the mail sender is also checked to allowing relaying.
This option only works together with the tag From: for the LHS of
-the access map entries (see below: Finer control...).
+the access map entries (see below: Finer control...). This feature
+allows spammers to abuse your mail server by specifying a return
+address that you enabled in your access file. This may be harder
+to figure out for spammers, but it should not be used unless
+necessary. Instead use SMTP AUTH or STARTTLS to allow relaying
+for roaming users.
-If source routing is used in the recipient address (i.e.
+If source routing is used in the recipient address (e.g.,
RCPT TO: <user%site.com@othersite.com>), sendmail will check
user@site.com for relaying if othersite.com is an allowed relay host
in either class {R}, class {m} if FEATURE(`relay_entire_domain') is used,
@@ -1679,14 +2175,30 @@ or reject those addresses.
As of 8.9, sendmail will refuse mail if the MAIL FROM: parameter has
an unresolvable domain (i.e., one that DNS, your local name service,
-or special case rules in ruleset 3 cannot locate). If you want to
-continue to accept such domains, e.g., because you are inside a
-firewall that has only a limited view of the Internet host name space
-(note that you will not be able to return mail to them unless you have
-some "smart host" forwarder), use
+or special case rules in ruleset 3 cannot locate). This also applies
+to addresses that use domain literals, e.g., <user@[1.2.3.4]>, if the
+IP address can't be mapped to a host name. If you want to continue
+to accept such domains, e.g., because you are inside a firewall that
+has only a limited view of the Internet host name space (note that you
+will not be able to return mail to them unless you have some "smart
+host" forwarder), use
FEATURE(`accept_unresolvable_domains')
+Alternatively, you can allow specific addresses by adding them to
+the access map, e.g.,
+
+ From:unresolvable.domain OK
+ From:[1.2.3.4] OK
+ From:[1.2.4] OK
+
+Notice: domains which are temporarily unresolvable are (temporarily)
+rejected with a 451 reply code. If those domains should be accepted
+(which is discouraged) then you can use
+
+ LOCAL_CONFIG
+ C{ResOk}TEMP
+
sendmail will also refuse mail if the MAIL FROM: parameter is not
fully qualified (i.e., contains a domain as well as a user). If you
want to continue to accept such senders, use
@@ -1696,7 +2208,7 @@ want to continue to accept such senders, use
Setting the DaemonPortOptions modifier 'u' overrides the default behavior,
i.e., unqualified addresses are accepted even without this FEATURE. If
this FEATURE is not used, the DaemonPortOptions modifier 'f' can be used
-to enforce fully qualified addresses.
+to enforce fully qualified domain names.
An ``access'' database can be created to accept or reject mail from
selected domains. For example, you may choose to reject all mail
@@ -1704,10 +2216,19 @@ originating from known spammers. To enable such a database, use
FEATURE(`access_db')
-The FEATURE macro can accept a second parameter giving the key file
+Notice: the access database is applied to the envelope addresses
+and the connection information, not to the header.
+
+The FEATURE macro can accept as second parameter the key file
definition for the database; for example
- FEATURE(`access_db', `hash /etc/mail/access')
+ FEATURE(`access_db', `hash -T<TMPF> /etc/mail/access_map')
+
+Notice: If a second argument is specified it must contain the option
+`-T<TMPF>' as shown above. The optional third and fourth parameters
+may be `skip' or `lookupdotdomain'. The former enables SKIP as
+value part (see below), the latter is another way to enable the
+feature of the same name (see above).
Remember, since /etc/mail/access is a database, after creating the text
file as described below, you must use makemap to create the database
@@ -1716,21 +2237,27 @@ map. For example:
makemap hash /etc/mail/access < /etc/mail/access
The table itself uses e-mail addresses, domain names, and network
-numbers as keys. For example,
+numbers as keys. Note that IPv6 addresses must be prefaced with "IPv6:".
+For example,
- spammer@aol.com REJECT
- cyberspammer.com REJECT
- 192.168.212 REJECT
+ spammer@aol.com REJECT
+ cyberspammer.com REJECT
+ 192.168.212 REJECT
+ IPv6:2002:c0a8:02c7 RELAY
+ IPv6:2002:c0a8:51d2::23f4 REJECT
would refuse mail from spammer@aol.com, any user from cyberspammer.com
-(or any host within the cyberspammer.com domain), and any host on the
-192.168.212.* network.
+(or any host within the cyberspammer.com domain), any host on the
+192.168.212.* network, and the IPv6 address 2002:c0a8:51d2::23f4. It would
+allow relay for the IPv6 network 2002:c0a8:02c7::/48.
The value part of the map can contain:
- OK Accept mail even if other rules in the
- running ruleset would reject it, for example,
- if the domain name is unresolvable.
+ OK Accept mail even if other rules in the running
+ ruleset would reject it, for example, if the domain
+ name is unresolvable. "Accept" does not mean
+ "relay", but at most acceptance for local
+ recipients. That is, OK allows less than RELAY.
RELAY Accept mail addressed to the indicated domain or
received from the indicated domain for relaying
through your SMTP server. RELAY also serves as
@@ -1742,10 +2269,16 @@ The value part of the map can contain:
it affects only the designated recipient, not
the whole message as it does in all other cases.
This should only be used if really necessary.
+ SKIP This can only be used for host/domain names
+ and IP addresses/nets. It will abort the current
+ search for this entry without accepting or rejecting
+ it but causing the default action.
### any text where ### is an RFC 821 compliant error code and
"any text" is a message to return for the command.
The string should be quoted to avoid surprises,
e.g., sendmail may remove spaces otherwise.
+ This type is deprecated, use one the two
+ ERROR: entries below instead.
ERROR:### any text
as above, but useful to mark error messages as such.
ERROR:D.S.N:### any text
@@ -1754,13 +2287,13 @@ The value part of the map can contain:
For example:
- cyberspammer.com ERROR:"550 We don't accept mail from spammers"
+ cyberspammer.com ERROR:550 "We don't accept mail from spammers"
okay.cyberspammer.com OK
sendmail.org RELAY
128.32 RELAY
- 1:2:3:4:5:6:7 RELAY
+ IPv6:1:2:3:4:5:6:7 RELAY
[127.0.0.3] OK
- [1:2:3:4:5:6:7:8] OK
+ [IPv6:1:2:3:4:5:6:7:8] OK
would accept mail from okay.cyberspammer.com, but would reject mail from
all other hosts at cyberspammer.com with the indicated message. It would
@@ -1768,20 +2301,22 @@ allow relaying mail from and to any hosts in the sendmail.org domain, and
allow relaying from the 128.32.*.* network and the IPv6 1:2:3:4:5:6:7:*
network. The latter two entries are for checks against ${client_name} if
the IP address doesn't resolve to a hostname (or is considered as "may be
-forged").
+forged"). That is, using square brackets means these are host names,
+not network numbers.
Warning: if you change the RFC 821 compliant error code from the default
value of 550, then you should probably also change the RFC 1893 compliant
error code to match it. For example, if you use
- user@example.com 450 mailbox full
+ user@example.com ERROR:450 mailbox full
-the error returned would be "450 4.0.0 mailbox full" which is wrong.
-Use "450 4.2.2 mailbox full" or "ERROR:4.2.2:450 mailbox full"
-instead.
+the error returned would be "450 5.0.0 mailbox full" which is wrong.
+Use "ERROR:4.2.2:450 mailbox full" instead.
Note, UUCP users may need to add hostname.UUCP to the access database
-or class {R}. If you also use:
+or class {R}.
+
+If you also use:
FEATURE(`relay_hosts_only')
@@ -1824,13 +2359,14 @@ the example from above:
Mail can't be sent to spammer@aol.com or anyone at cyberspammer.com.
-There is also a ``Realtime Blackhole List'' run by the MAPS project
-at http://maps.vix.com/. This is a database maintained in DNS of
-spammers. To use this database, use
+There are several DNS based blacklists, the first of which was
+the RBL (``Realtime Blackhole List'') run by the MAPS project,
+see http://mail-abuse.org/. These are databases of spammers
+maintained in DNS. To use such a database, specify
FEATURE(`dnsbl')
-This will cause sendmail to reject mail from any site in the
+This will cause sendmail to reject mail from any site in the original
Realtime Blackhole List database. This default DNS blacklist,
blackholes.mail-abuse.org, is a service offered by the Mail Abuse
Prevention System (MAPS). As of July 31, 2001, MAPS is a subscription
@@ -1840,22 +2376,46 @@ subscribed. Contact MAPS to subscribe (http://mail-abuse.org/).
You can specify an alternative RBL server to check by specifying an
argument to the FEATURE. The default error message is
-You can specify an alternative RBL domain to check by specifying an
-argument to the FEATURE. The default error message is
+ Mail from IP-ADDRESS refused by blackhole site SERVER
+
+where IP-ADDRESS and SERVER are replaced by the appropriate
+information. A second argument can be used to specify a different
+text. By default, temporary lookup failures are ignored and hence
+cause the connection not to be rejected by the DNS based rejection
+list. This behavior can be changed by specifying a third argument,
+which must be either `t' or a full error message. For example:
+
+ FEATURE(`dnsbl', `dnsbl.example.com', `',
+ `"451 Temporary lookup failure for " $&{client_addr} " in dnsbl.example.com"')
+
+If `t' is used, the error message is:
- Mail from $&{client_addr} refused by blackhole site DOMAIN
+ 451 Temporary lookup failure of IP-ADDRESS at SERVER
+
+where IP-ADDRESS and SERVER are replaced by the appropriate
+information.
+
+This FEATURE can be included several times to query different
+DNS based rejection lists, e.g., the dial-up user list (see
+http://mail-abuse.org/dul/).
+
+Notice: to avoid checking your own local domains against those
+blacklists, use the access_db feature and add:
+
+ Connect:10.1 OK
+ Connect:127.0.0.1 RELAY
+
+to the access map, where 10.1 is your local network. You may
+want to use "RELAY" instead of "OK" to allow also relaying
+instead of just disabling the DNS lookups in the backlists.
-where DOMAIN is the first argument of the feature. A second argument
-can be used to specify a different text. This FEATURE can be
-included several times to query different DNS based rejection lists,
-e.g., the dial-up user list (see http://maps.vix.com/dul/).
The features described above make use of the check_relay, check_mail,
and check_rcpt rulesets. If you wish to include your own checks,
you can put your checks in the rulesets Local_check_relay,
Local_check_mail, and Local_check_rcpt. For example if you wanted to
block senders with all numeric usernames (i.e. 2312343@bigisp.com),
-you would use Local_check_mail and the new regex map:
+you would use Local_check_mail and the regex map:
LOCAL_CONFIG
Kallnumbers regex -a@MATCH ^[0-9]+$
@@ -1875,6 +2435,7 @@ appropriate action is taken. Otherwise, the results of the local
rewriting are ignored.
Finer control by using tags for the LHS of the access map
+---------------------------------------------------------
Read this section only if the options listed so far are not sufficient
for your purposes. There is now the option to tag entries in the
@@ -1886,7 +2447,8 @@ access map according to their type. Three tags are available:
If the required item is looked up in a map, it will be tried first
with the corresponding tag in front, then (as fallback to enable
-backward compatibility) without any tag. For example,
+backward compatibility) without any tag, unless the specific feature
+requires a tag. For example,
From:spammer@some.dom REJECT
To:friend.domain RELAY
@@ -1909,6 +2471,7 @@ reject mail from all other addresses with another.dom as domain
part.
Delay all checks
+----------------
By using FEATURE(`delay_checks') the rulesets check_mail and check_relay
will not be called when a client connects or issues a MAIL command,
@@ -1943,24 +2506,33 @@ FEATURE(`delay_checks') can take an optional argument:
enables spamhater test
If such an argument is given, the recipient will be looked up in the access
-map (using the tag To:). If the argument is `friend', then the other
+map (using the tag Spam:). If the argument is `friend', then the other
rulesets will be skipped if the recipient address is found and has RHS
-spamfriend. If the argument is `hater', then the other rulesets will be
-applied if the recipient address is found and has RHS spamhater.
+friend. If the argument is `hater', then the other rulesets will be
+applied if the recipient address is found and has RHS hater.
This allows for simple exceptions from the tests, e.g., by activating
-the spamfriend option and having
+the friend option and having
- To:abuse@ SPAMFRIEND
+ Spam:abuse@ FRIEND
in the access map, mail to abuse@localdomain will get through. It is
also possible to specify a full address or an address with +detail:
- To:abuse@abuse.my.domain SPAMFRIEND
- To:me+abuse@ SPAMFRIEND
+ Spam:abuse@my.domain FRIEND
+ Spam:me+abuse@ FRIEND
+ Spam:spam.domain FRIEND
+Note: The required tag has been changed in 8.12 from To: to Spam:.
+This change is incompatible to previous versions. However, you can
+(for now) simply add the new entries to the access map, the old
+ones will be ignored. As soon as you removed the old entries from
+the access map, specify a third parameter (`n') to this feature and
+the backward compatibility rules will not be in the generated .cf
+file.
Header Checks
+-------------
You can also reject mail on the basis of the contents of headers.
This is done by adding a ruleset call to the 'H' header definition command
@@ -1987,10 +2559,14 @@ defined for them can be given by:
H*: $>CheckHdr
-Notice: All rules act on tokens as explained in doc/op/op.{me,ps,txt}.
+Notice:
+1. All rules act on tokens as explained in doc/op/op.{me,ps,txt}.
That may cause problems with simple header checks due to the
-tokenization. It might be simpler to use a regex map and apply it
+tokenization. It might be simpler to use a regex map and apply it
to $&{currHeader}.
+2. There are no default rulesets coming with this distribution of
+sendmail. You can either write your own or you can search the
+WWW for examples, e.g., http://www.digitalanswers.org/check_local/
After all of the headers are read, the check_eoh ruleset will be called for
any final header-related checks. The ruleset is called with the number of
@@ -2031,7 +2607,8 @@ probably not be used in production.
+----------+
In this text, cert will be used as an abreviation for X.509 certificate,
-DN is the distinguished name of a cert, and CA is a certification authority.
+DN (CN) is the distinguished (common) name of a cert, and CA is a
+certification authority, which signs (issues) certs.
For STARTTLS to be offered by sendmail you need to set at least
this variables (the file names and paths are just examples):
@@ -2044,53 +2621,57 @@ this variables (the file names and paths are just examples):
On systems which do not have the compile flag HASURANDOM set (see
sendmail/README) you also must set confRAND_FILE.
-See doc/op/op.{me,ps} for more information about these options,
-esp. the sections ``Certificates for STARTTLS'' and ``PRNG for
+See doc/op/op.{me,ps,txt} for more information about these options,
+especially the sections ``Certificates for STARTTLS'' and ``PRNG for
STARTTLS''.
Macros related to STARTTLS are:
${cert_issuer} holds the DN of the CA (the cert issuer).
${cert_subject} holds the DN of the cert (called the cert subject).
+${cn_issuer} holds the CN of the CA (the cert issuer).
+${cn_subject} holds the CN of the cert (called the cert subject).
${tls_version} the TLS/SSL version used for the connection, e.g., TLSv1,
- SSLv3, SSLv2.
+ TLSv1/SSLv3, SSLv3, SSLv2.
${cipher} the cipher used for the connection, e.g., EDH-DSS-DES-CBC3-SHA,
EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA.
${cipher_bits} the keylength (in bits) of the symmetric encryption algorithm
used for the connection.
-${verify} holds the result of the verification of the presented cert. Possible
- values are:
- OK verification succeeded.
- NO no cert presented.
- FAIL cert presented but could not be verified, e.g., the signing
- CA is missing.
- NONE STARTTLS has not been performed.
- TEMP temporary error occurred.
- PROTOCOL some protocol error occurred.
+${verify} holds the result of the verification of the presented cert.
+ Possible values are:
+ OK verification succeeded.
+ NO no cert presented.
+ NOT no cert requested.
+ FAIL cert presented but could not be verified,
+ e.g., the cert of the signing CA is missing.
+ NONE STARTTLS has not been performed.
+ TEMP temporary error occurred.
+ PROTOCOL protocol error occurred (SMTP level).
SOFTWARE STARTTLS handshake failed.
-${server_name} the name of the server of the current outgoing SMTP
+${server_name} the name of the server of the current outgoing SMTP
connection.
-${server_addr} the address of the server of the current outgoing SMTP
+${server_addr} the address of the server of the current outgoing SMTP
connection.
Relaying
+--------
SMTP STARTTLS can allow relaying for senders who have successfully
-authenticated themselves. This is done in the ruleset RelayAuth. If the
+authenticated themselves. This is done in the ruleset RelayAuth. If the
verification of the cert failed (${verify} != OK), relaying is subject to
-the usual rules. Otherwise the DN of the issuer is looked up in the access
-map using the tag CERTISSUER. If the resulting value is RELAY, relaying is
-allowed. If it is SUBJECT, the DN of the cert subject is looked up next in
-the access map. using the tag CERTSUBJECT. If the value is RELAY, relaying
+the usual rules. Otherwise the DN of the issuer is looked up in the access
+map using the tag CERTISSUER. If the resulting value is RELAY, relaying is
+allowed. If it is SUBJECT, the DN of the cert subject is looked up next in
+the access map using the tag CERTSUBJECT. If the value is RELAY, relaying
is allowed.
To make things a bit more flexible (or complicated), the values for
${cert_issuer} and ${cert_subject} can be optionally modified by regular
expressions defined in the m4 variables _CERT_REGEX_ISSUER_ and
-_CERT_REGEX_SUBJECT_, respectively. To avoid problems with those macros in
+_CERT_REGEX_SUBJECT_, respectively. To avoid problems with those macros in
rulesets and map lookups, they are modified as follows: each non-printable
character and the characters '<', '>', '(', ')', '"', '+' are replaced by
-their HEX value with a leading '+'. For example:
+their HEX value with a leading '+'. For example:
/C=US/ST=California/O=endmail.org/OU=private/CN=Darth Mail (Cert)/Email=
darth+cert@endmail.org
@@ -2102,7 +2683,34 @@ Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org
(line breaks have been inserted for readability).
-Of course it is also possible to write a simple rulesets that allows
+Examples:
+
+To allow relaying for everyone who can present a cert signed by
+
+/C=US/ST=California/O=endmail.org/OU=private/CN=
+Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org
+
+simply use:
+
+CERTIssuer:/C=US/ST=California/O=endmail.org/OU=private/CN=
+Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org RELAY
+
+To allow relaying only for a subset of machines that have a cert signed by
+
+/C=US/ST=California/O=endmail.org/OU=private/CN=
+Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org
+
+use:
+
+CERTIssuer:/C=US/ST=California/O=endmail.org/OU=private/CN=
+Darth+20Mail+20+28Cert+29/Email=darth+2Bcert@endmail.org SUBJECT
+CERTSubject:/C=US/ST=California/O=endmail.org/OU=private/CN=
+DeathStar/Email=deathstar@endmail.org RELAY
+
+Note: line breaks have been inserted after "CN=" for readability,
+each tagged entry must be one (long) line in the access map.
+
+Of course it is also possible to write a simple ruleset that allows
relaying for everyone who can present a cert that can be verified, e.g.,
LOCAL_RULESETS
@@ -2111,29 +2719,49 @@ R$* $: $&{verify}
ROK $# OK
Allowing Connections
+--------------------
-The rulesets tls_server and tls_client are used to decide whether an SMTP
-connection is accepted (or should continue).
+The rulesets tls_server, tls_client, and tls_rcpt are used to decide whether
+an SMTP connection is accepted (or should continue).
tls_server is called when sendmail acts as client after a STARTTLS command
-(should) have been issued. The parameter is the value of ${verify}.
+(should) have been issued. The parameter is the value of ${verify}.
tls_client is called when sendmail acts as server, after a STARTTLS command
-has been issued, and from check_mail. The parameter is the value of
+has been issued, and from check_mail. The parameter is the value of
${verify} and STARTTLS or MAIL, respectively.
-Both rulesets behave the same. If no access map is in use, the connection
+Both rulesets behave the same. If no access map is in use, the connection
will be accepted unless ${verify} is SOFTWARE, in which case the connection
-is always aborted. Otherwise, ${client_name} (${server_name}) is looked
-up in the access map using the tag TLS_Srv (or TLS_Clt), which is done
-with the ruleset LookUpDomain. If no entry is found, ${client_addr}
+is always aborted. For tls_server/tls_client, ${client_name}/${server_name}
+is looked up in the access map using the tag TLS_Srv/TLS_Clt, which is done
+with the ruleset LookUpDomain. If no entry is found, ${client_addr}
(${server_addr}) is looked up in the access map (same tag, ruleset
-LookUpAddr). If this doesn't result in an entry either, just the tag is
-looked up in the access map (included the trailing :). The result of the
-lookups is then used to call the ruleset tls_connection, which checks the
-requirement specified by the RHS in the access map against the actual
-parameters of the current TLS connection, esp. ${verify} and
-${cipher_bits}. Legal RHSs in the access map are:
+LookUpAddr). If this doesn't result in an entry either, just the tag is
+looked up in the access map (included the trailing colon). Notice:
+requiring that e-mail is sent to a server only encrypted, e.g., via
+
+TLS_Srv:secure.domain ENCR:112
+
+doesn't necessarily mean that e-mail sent to that domain is encrypted.
+If the domain has multiple MX servers, e.g.,
+
+secure.domain. IN MX 10 mail.secure.domain.
+secure.domain. IN MX 50 mail.other.domain.
+
+then mail to user@secure.domain may go unencrypted to mail.other.domain.
+tls_rcpt can be used to address this problem.
+
+tls_rcpt is called before a RCPT TO: command is sent. The parameter is the
+current recipient. This ruleset is only defined if FEATURE(`access_db')
+is selected. A recipient address user@domain is looked up in the access
+map in four formats: TLS_Rcpt:user@domain, TLS_Rcpt:user@, TLS_Rcpt:domain,
+and TLS_Rcpt:; the first match is taken.
+
+The result of the lookups is then used to call the ruleset TLS_connection,
+which checks the requirement specified by the RHS in the access map against
+the actual parameters of the current TLS connection, esp. ${verify} and
+${cipher_bits}. Legal RHSs in the access map are:
VERIFY verification must have succeeded
VERIFY:bits verification must have succeeded and ${cipher_bits} must
@@ -2141,39 +2769,64 @@ VERIFY:bits verification must have succeeded and ${cipher_bits} must
ENCR:bits ${cipher_bits} must be greater than or equal bits.
The RHS can optionally be prefixed by TEMP+ or PERM+ to select a temporary
-or permanent error. The default is a temporary error code (403 4.7.0)
+or permanent error. The default is a temporary error code (403 4.7.0)
unless the macro TLS_PERM_ERR is set during generation of the .cf file.
If a certain level of encryption is required, then it might also be
possible that this level is provided by the security layer from a SASL
algorithm, e.g., DIGEST-MD5.
+Furthermore, there can be a list of extensions added. Such a list
+starts with '+' and the items are separated by '++'. Allowed
+extensions are:
+
+CN:name name must match ${cn_subject}
+CN ${server_name} must match ${cn_subject}
+CS:name name must match ${cert_subject}
+CI:name name must match ${cert_issuer}
+
Example: e-mail sent to secure.example.com should only use an encrypted
-connection. e-mail received from hosts within the laptop.example.com domain
-should only be accepted if they have been authenticated.
+connection. E-mail received from hosts within the laptop.example.com domain
+should only be accepted if they have been authenticated. The host which
+receives e-mail for darth@endmail.org must present a cert that uses the
+CN smtp.endmail.org.
+
TLS_Srv:secure.example.com ENCR:112
TLS_Clt:laptop.example.com PERM+VERIFY:112
+TLS_Rcpt:darth@endmail.org ENCR:112+CN:smtp.endmail.org
-Notice: requiring that e-mail is sent to a server only encrypted,
-e.g., via
-TLS_Srv:secure.domain ENCR:112
+Disabling STARTTLS And Setting SMTP Server Features
+---------------------------------------------------
-doesn't necessarily mean that e-mail sent to that domain is encrypted.
-If the domain has multiple MX servers, e.g.,
+By default STARTTLS is used whenever possible. However, there are
+some broken MTAs that don't properly implement STARTTLS. To be able
+to send to (or receive from) those MTAs, the ruleset try_tls
+(srv_features) can be used that work together with the access map.
+Entries for the access map must be tagged with Try_TLS (Srv_Features)
+and refer to the hostname or IP address of the connecting system.
+A default case can be specified by using just the tag. For example,
+the following entries in the access map:
-secure.domain. IN MX 10 mail.secure.domain.
-secure.domain. IN MX 50 mail.other.domain.
+ Try_TLS:broken.server NO
+ Srv_Features:my.domain v
+ Srv_Features: V
-then mail to user@secure.domain may go unencrypted to mail.other.domain.
+will turn off STARTTLS when sending to broken.server (or any host
+in that domain), and request a client certificate during the TLS
+handshake only for hosts in my.domain. The valid entries on the RHS
+for Srv_Features are listed in the Sendmail Installation and
+Operations Guide.
Received: Header
+----------------
-The Received: header reveals whether STARTTLS has been used. It contains an
+The Received: header reveals whether STARTTLS has been used. It contains an
extra line:
-(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})
+(version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})
+
+---------------------+
| SMTP AUTHENTICATION |
@@ -2198,7 +2851,7 @@ RDIGEST-MD5 $| $+@$=w $# OK
to allow relaying for users that authenticated using DIGEST-MD5
and have an identity in the local domains.
-The ruleset Strust_auth is used to determine whether a given AUTH=
+The ruleset trust_auth is used to determine whether a given AUTH=
parameter (that is passed to this ruleset) should be trusted. This
ruleset may make use of the other ${auth_*} macros. Only if the
ruleset resolves to the error mailer, the AUTH= parameter is not
@@ -2216,6 +2869,48 @@ If the selected mechanism provides a security layer the number of
bits used for the key of the symmetric cipher is stored in the
macro ${auth_ssf}.
+If sendmail acts as client, it needs some information how to
+authenticate against another MTA. This information can be provided
+by the ruleset authinfo or by the option DefaultAuthInfo. The
+authinfo ruleset looks up {server_name} using the tag AuthInfo: in
+the access map. If no entry is found, {server_addr} is looked up
+in the same way and finally just the tag AuthInfo: to provide
+default values.
+
+Notice: the default configuration file causes the option DefaultAuthInfo
+to fail since the ruleset authinfo is in the .cf file. If you really
+want to use DefaultAuthInfo (it is deprecated) then you have to
+remove the ruleset.
+
+The RHS for an AuthInfo: entry in the access map should consists of a
+list of tokens, each of which has the form: "TDstring" (including
+the quotes). T is a tag which describes the item, D is a delimiter,
+either ':' for simple text or '=' for a base64 encoded string.
+Valid values for the tag are:
+
+ U user (authorization) id
+ I authentication id
+ P password
+ R realm
+ M list of mechanisms delimited by spaces
+
+Example entries are:
+
+AuthInfo:other.dom "U:user" "I:user" "P:secret" "R:other.dom" "M:DIGEST-MD5"
+AuthInfo:more.dom "U:user" "P=c2VjcmV0"
+
+User or authentication id must exist as well as the password. All
+other entries have default values. If one of user or authentication
+id is missing, the existing value is used for the missing item.
+If "R:" is not specified, realm defaults to $j. The list of mechanisms
+defaults to those specified by AuthMechanisms.
+
+Since this map contains sensitive information, either the access
+map must be unreadable by everyone but root (or the trusted user)
+or FEATURE(`authinfo') must be used which provides a separate map.
+Notice: It is not checked whether the map is actually
+group/world-unreadable, this is left to the user.
+
+--------------------------------+
| ADDING NEW MAILERS OR RULESETS |
+--------------------------------+
@@ -2232,8 +2927,19 @@ LOCAL_RULESETS respectively. For example:
Smyruleset
...
+Local additions for the rulesets srv_features, try_tls, tls_rcpt,
+tls_client, and tls_server can be made using LOCAL_SRV_FEATURES,
+LOCAL_TRY_TLS, LOCAL_TLS_RCPT, LOCAL_TLS_CLIENT, and LOCAL_TLS_SERVER,
+respectively. For example, to add a local ruleset that decides
+whether to try STARTTLS in a sendmail client, use:
+
+ LOCAL_TRY_TLS
+ R...
+
+Note: you don't need to add a name for the ruleset, it is implicitly
+defined by using the appropriate macro.
+
-#if _FFR_MILTER
+-------------------------+
| ADDING NEW MAIL FILTERS |
+-------------------------+
@@ -2275,9 +2981,21 @@ more filters than you want to use for `confINPUT_MAIL_FILTERS'.
Note that setting `confINPUT_MAIL_FILTERS' after any INPUT_MAIL_FILTER()
commands will clear the list created by the prior INPUT_MAIL_FILTER()
commands.
-#endif /* _FFR_MILTER */
++-------------------------+
+| QUEUE GROUP DEFINITIONS |
++-------------------------+
+
+In addition to the queue directory (which is the default queue group
+called "mqueue"), sendmail can deal with multiple queue groups, which
+are collections of queue directories with the same behaviour. Queue
+groups can be defined using the command:
+
+ QUEUE_GROUP(`name', `equates')
+
+For details about queue groups, please see doc/op/op.{me,ps,txt}.
+
+-------------------------------+
| NON-SMTP BASED CONFIGURATIONS |
+-------------------------------+
@@ -2391,7 +3109,7 @@ something like:
my.domain esmtp:host.my.domain
The RHS should always be a "mailer:host" pair. The mailer is the
-configuration name of a mailer (that is, an {M} line in the
+configuration name of a mailer (that is, an M line in the
sendmail.cf file). The "host" will be the hostname passed to
that mailer. In domain-based matches (that is, those with leading
dots) the "%1" may be used to interpolate the wildcarded part of
@@ -2537,6 +3255,11 @@ confDOMAIN_NAME $j macro If defined, sets $j. This should
domain name.
confCF_VERSION $Z macro If defined, this is appended to the
configuration version name.
+confLDAP_CLUSTER ${sendmailMTACluster} macro
+ If defined, this is the LDAP
+ cluster to use for LDAP searches
+ as described above in ``USING LDAP
+ FOR ALIASES, MAPS, AND CLASSES''.
confFROM_HEADER From: [$?x$x <$g>$|$g$.] The format of an
internally generated From: address.
confRECEIVED_HEADER Received:
@@ -2607,13 +3330,6 @@ confCHECKPOINT_INTERVAL CheckpointInterval
[10] Checkpoint queue files every N
recipients.
confDELIVERY_MODE DeliveryMode [background] Default delivery mode.
-confAUTO_REBUILD AutoRebuildAliases
- [False] Automatically rebuild alias
- file if needed.
- There is a potential for a denial
- of service attack if this is set.
- This option is deprecated and will
- be removed from a future version.
confERROR_MODE ErrorMode [print] Error message mode.
confERROR_MESSAGE ErrorHeader [undefined] Error message header/file.
confSAVE_FROM_LINES SaveFromLine Save extra leading From_ lines.
@@ -2671,13 +3387,15 @@ confCHECK_ALIASES CheckAliases [False] Check RHS of aliases when
considerably on large alias files.
confOLD_STYLE_HEADERS* OldStyleHeaders [True] Assume that headers without
special chars are old style.
-confCLIENT_OPTIONS ClientPortOptions
- [none] Options for outgoing SMTP client
- connections.
confPRIVACY_FLAGS PrivacyOptions [authwarnings] Privacy flags.
confCOPY_ERRORS_TO PostmasterCopy [undefined] Address for additional
copies of all error messages.
confQUEUE_FACTOR QueueFactor [600000] Slope of queue-only function.
+confQUEUE_FILE_MODE QueueFileMode [undefined] Default permissions for
+ queue files (octal). If not set,
+ sendmail uses 0600 unless its real
+ and effective uid are different in
+ which case it uses 0644.
confDONT_PRUNE_ROUTES DontPruneRoutes [False] Don't prune down route-addr
syntax addresses to the minimum
possible.
@@ -2697,6 +3415,11 @@ confTO_ICONNECT Timeout.iconnect
This allows a single very fast pass
followed by more careful delivery
attempts in the future.
+confTO_ACONNECT Timeout.aconnect
+ [0] The overall timeout waiting for
+ all connection for a single delivery
+ attempt to succeed. If 0, no overall
+ limit is applied.
confTO_HELO Timeout.helo [5m] The timeout waiting for a response
to a HELO or EHLO command.
confTO_MAIL Timeout.mail [10m] The timeout waiting for a
@@ -2726,6 +3449,13 @@ confTO_IDENT Timeout.ident [5s] The timeout waiting for a
confTO_FILEOPEN Timeout.fileopen
[60s] The timeout waiting for a file
(e.g., :include: file) to be opened.
+confTO_LHLO Timeout.lhlo [2m] The timeout waiting for a response
+ to an LMTP LHLO command.
+confTO_AUTH Timeout.auth [10m] The timeout waiting for a
+ response in an AUTH dialogue.
+confTO_STARTTLS Timeout.starttls
+ [1h] The timeout waiting for a
+ response to an SMTP STARTTLS command.
confTO_CONTROL Timeout.control
[2m] The timeout for a complete
control socket transaction to complete.
@@ -2824,6 +3554,10 @@ confREFUSE_LA RefuseLA [varies] Load average at which
numproc) where numproc is the
number of processors online (if
that can be determined).
+confDELAY_LA DelayLA [0] Load average at which sendmail
+ will sleep for one second on most
+ SMTP commands and before accepting
+ connections. 0 means no limit.
confMAX_ALIAS_RECURSION MaxAliasRecursion
[10] Maximum depth of alias recursion.
confMAX_DAEMON_CHILDREN MaxDaemonChildren
@@ -2840,11 +3574,11 @@ confMAX_MIME_HEADER_LENGTH MaxMimeHeaderLength
certain MIME header field values.
confCONNECTION_RATE_THROTTLE ConnectionRateThrottle
[undefined] The maximum number of
- connections permitted per second.
- After this many connections are
- accepted, further connections will be
- delayed. If not set or <= 0, there is
- no limit.
+ connections permitted per second per
+ daemon. After this many connections
+ are accepted, further connections
+ will be delayed. If not set or <= 0,
+ there is no limit.
confWORK_RECIPIENT_FACTOR
RecipientFactor [30000] Cost of each recipient.
confSEPARATE_PROC ForkEachJob [False] Run all deliveries in a
@@ -2852,7 +3586,8 @@ confSEPARATE_PROC ForkEachJob [False] Run all deliveries in a
confWORK_CLASS_FACTOR ClassFactor [1800] Priority multiplier for class.
confWORK_TIME_FACTOR RetryFactor [90000] Cost of each delivery attempt.
confQUEUE_SORT_ORDER QueueSortOrder [Priority] Queue sort algorithm:
- Priority, Host, Filename, or Time.
+ Priority, Host, Filename, Random,
+ Modification, or Time.
confMIN_QUEUE_AGE MinQueueAge [0] The minimum amount of time a job
must sit in the queue between queue
runs. This allows you to set the
@@ -2884,9 +3619,11 @@ confNO_RCPT_ACTION NoRecipientAction
known recipients (which may expose
blind recipients), "add-apparently-to"
to do the same but use Apparently-To:
- instead of To:, "add-bcc" to add an
- empty Bcc: header, or
- "add-to-undisclosed" to add the header
+ instead of To: (strongly discouraged
+ in accordance with IETF standards),
+ "add-bcc" to add an empty Bcc:
+ header, or "add-to-undisclosed" to
+ add the header
``To: undisclosed-recipients:;''.
confSAFE_FILE_ENV SafeFileEnvironment
[undefined] If set, sendmail will do a
@@ -2909,6 +3646,18 @@ confMAX_QUEUE_RUN_SIZE MaxQueueRunSize [0] If set, limit the maximum size of
so this should be as large as your
system can tolerate. If not set, there
is no limit.
+confMAX_QUEUE_CHILDREN MaxQueueChildren
+ [undefined] Limits the maximum number
+ of concurrent queue runners active.
+ This is to keep system resources used
+ within a reasonable limit. Relates to
+ Queue Groups and ForkAllJobs.
+confMAX_RUNNERS_PER_QUEUE MaxRunnersPerQueue
+ [1] Only active when MaxQueueChildren
+ defined. Controls the maximum number
+ of queue runners (aka queue children)
+ active at the same time in a work
+ group. See also MaxQueueChildren.
confDONT_EXPAND_CNAMES DontExpandCnames
[False] If set, $[ ... $] lookups that
do DNS based lookups do not expand
@@ -2969,7 +3718,8 @@ confDOUBLE_BOUNCE_ADDRESS DoubleBounceAddress
[postmaster] If an error occurs when
sending an error message, send that
"double bounce" error message to this
- address.
+ address. If it expands to an empty
+ string, double bounces are dropped.
confDEAD_LETTER_DROP DeadLetterDrop [undefined] Filename to save bounce
messages which could not be returned
to the user or sent to postmaster.
@@ -2993,6 +3743,11 @@ confMAX_RCPTS_PER_MESSAGE MaxRecipientsPerMessage
receive a 452 error code (i.e., they
are deferred for the next delivery
attempt).
+confBAD_RCPT_THROTTLE BadRcptThrottle [infinite] If set and more than the
+ specified number of recipients in an
+ envelope are rejected, sleep for one
+ second after each rejected RCPT
+ command.
confDONT_PROBE_INTERFACES DontProbeInterfaces
[False] If set, sendmail will _not_
insert the names and addresses of any
@@ -3003,6 +3758,9 @@ confDONT_PROBE_INTERFACES DontProbeInterfaces
in a mailertable entry) -- otherwise,
mail to addresses in this list will
bounce with a configuration error.
+ If set to "loopback" (without
+ quotes), sendmail will skip
+ loopback interfaces (e.g., "lo0").
confPID_FILE PidFile [system dependent] Location of pid
file.
confPROCESS_TITLE_PREFIX ProcessTitlePrefix
@@ -3017,6 +3775,9 @@ confDONT_BLAME_SENDMAIL DontBlameSendmail
confREJECT_MSG - [550 Access denied] The message
given if the access database contains
REJECT in the value portion.
+confRELAY_MSG - [550 Relaying denied] The message
+ given if an unauthorized relaying
+ attempt is rejected.
confDF_BUFFER_SIZE DataFileBufferSize
[4096] The maximum size of a
memory-buffered data (df) file
@@ -3036,36 +3797,40 @@ confAUTH_MECHANISMS AuthMechanisms [GSSAPI KERBEROS_V4 DIGEST-MD5
by the CYRUS SASL library.
confDEF_AUTH_INFO DefaultAuthInfo [undefined] Name of file that contains
authentication information for
- outgoing connections. This file
- must contain the user id, the
- authorization id, the password
- (plain text), and the realm to use,
- each on a separate line and must be
- readable by root (or the trusted
- user) only. If no realm is
- specified, $j is used.
-
- NOTE: Currently, AuthMechanisms is
- used to determine the list of
- mechanisms to use on an outgoing
- connection. Sites which require a
- different list of mechanisms for
- incoming connections and outgoing
- connections will have the ability
- to do this in 8.11 by specifying a
- list of mechanisms as the fifth
- line of the DefaultAuthInfo file.
- If no mechanisms are given in the
- file, AuthMechanisms is used. The
- code for doing so is included as
- in the sendmail source code but
- disabled. It can be enabled by
- recompiling sendmail with:
- -D_FFR_DEFAUTHINFO_MECHS
-confAUTH_OPTIONS AuthOptions [undefined] If this options is 'A'
+ outgoing connections. This file must
+ contain the user id, the authorization
+ id, the password (plain text), the
+ realm to use, and the list of
+ mechanisms to try, each on a separate
+ line and must be readable by root (or
+ the trusted user) only. If no realm
+ is specified, $j is used. If no
+ mechanisms are given in the file,
+ AuthMechanisms is used. Notice: this
+ option is deprecated and will be
+ removed in future versions; it doesn't
+ work for the MSP since it can't read
+ the file. Use the authinfo ruleset
+ instead. See also the section SMTP
+ AUTHENTICATION.
+confAUTH_OPTIONS AuthOptions [undefined] If this option is 'A'
then the AUTH= parameter for the
MAIL FROM command is only issued
when authentication succeeded.
+ Other values (which should be listed
+ one after the other without any
+ intervening characters except for
+ space or comma) are a, c, d, f, p,
+ and y. See doc/op/op.me for
+ details.
+confAUTH_MAX_BITS AuthMaxBits [INT_MAX] Limit the maximum encryption
+ strength for the security layer in
+ SMTP AUTH (SASL). Default is
+ essentially unlimited.
+confTLS_SRV_OPTIONS TLSSrvOptions If this option is 'V' no client
+ verification is performed, i.e.,
+ the server doesn't ask for a
+ certificate.
confLDAP_DEFAULT_SPEC LDAPDefaultSpec [undefined] Default map
specification for LDAP maps. The
value should only contain LDAP
@@ -3102,15 +3867,68 @@ confRAND_FILE RandFile [undefined] File containing random
requires this option if the compile
flag HASURANDOM is not set (see
sendmail/README).
+confNICE_QUEUE_RUN NiceQueueRun [undefined] If set, the priority of
+ queue runners is set the given value
+ (nice(3)).
+confDIRECT_SUBMISSION_MODIFIERS DirectSubmissionModifiers
+ [undefined] Defines {daemon_flags}
+ for direct submissions.
+confUSE_MSP UseMSP [false] Use as mail submission
+ program, see sendmail/SECURITY.
+confDELIVER_BY_MIN DeliverByMin [0] Minimum time for Deliver By
+ SMTP Service Extension (RFC 2852).
+confSHARED_MEMORY_KEY SharedMemoryKey [0] Key for shared memory.
+confFAST_SPLIT FastSplit [1] If set to a value greater than
+ zero, the initial MX lookups on
+ addresses is suppressed when they
+ are sorted which may result in
+ faster envelope splitting. If the
+ mail is submitted directly from the
+ command line, then the value also
+ limits the number of processes to
+ deliver the envelopes.
+confMAILBOX_DATABASE MailboxDatabase [pw] Type of lookup to find
+ information about local mailboxes.
+confDEQUOTE_OPTS - [empty] Additional options for the
+ dequote map.
+confINPUT_MAIL_FILTERS InputMailFilters
+ A comma separated list of filters
+ which determines which filters and
+ the invocation sequence are
+ contacted for incoming SMTP
+ messages. If none are set, no
+ filters will be contacted.
+confMILTER_LOG_LEVEL Milter.LogLevel [9] Log level for input mail filter
+ actions, defaults to LogLevel.
+confMILTER_MACROS_CONNECT Milter.macros.connect
+ [empty] Macros to transmit to milters
+ when a session connection starts.
+confMILTER_MACROS_HELO Milter.macros.helo
+ [empty] Macros to transmit to milters
+ after HELO command.
+confMILTER_MACROS_ENVFROM Milter.macros.envfrom
+ [empty] Macros to transmit to milters
+ after MAIL FROM command.
+confMILTER_MACROS_ENVRCPT Milter.macros.envrcpt
+ [empty] Macros to transmit to milters
+ after RCPT TO command.
+
See also the description of OSTYPE for some parameters that can be
tweaked (generally pathnames to mailers).
-DaemonPortOptions are a special case since multiple daemons can be
-defined. This can be done via
+ClientPortOptions and DaemonPortOptions are special cases since multiple
+clients/daemons can be defined. This can be done via
+ CLIENT_OPTIONS(`field1=value1,field2=value2,...')
DAEMON_OPTIONS(`field1=value1,field2=value2,...')
+Note that multiple CLIENT_OPTIONS() commands (and therefore multiple
+ClientPortOptions settings) are allowed in order to give settings for each
+protocol family (e.g., one for Family=inet and one for Family=inet6). A
+restriction placed on one family only affects outgoing connections on that
+particular family.
+
If DAEMON_OPTIONS is not used, then the default is
DAEMON_OPTIONS(`Port=smtp, Name=MTA')
@@ -3152,10 +3970,117 @@ Notice: Do NOT use the 'a' modifier on a public accessible MTA!
Finally, the M=E modifier shown above disables ETRN as required by RFC
2476.
+Mail filters can be defined using the INPUT_MAIL_FILTER() and MAIL_FILTER()
+commands:
-+-----------+
-| HIERARCHY |
-+-----------+
+ INPUT_MAIL_FILTER(`sample', `S=local:/var/run/f1.sock')
+ MAIL_FILTER(`myfilter', `S=inet:3333@localhost')
+
+The INPUT_MAIL_FILTER() command causes the filter(s) to be called in the
+same order they were specified by also setting confINPUT_MAIL_FILTERS. A
+filter can be defined without adding it to the input filter list by using
+MAIL_FILTER() instead of INPUT_MAIL_FILTER() in your .mc file.
+Alternatively, you can reset the list of filters and their order by setting
+confINPUT_MAIL_FILTERS option after all INPUT_MAIL_FILTER() commands in
+your .mc file.
+
+
++----------------------------+
+| MESSAGE SUBMISSION PROGRAM |
++----------------------------+
+
+The purpose of the message submission program (MSP) is explained
+in sendmail/SECURITY. This section contains a list of caveats and
+a few hints how for those who want to tweak the default configuration
+for it (which is installed as submit.cf).
+
+Notice: do not add options/features to submit.mc unless you are
+absolutely sure you need them. Options you may want to change
+include:
+
+- confTIME_ZONE on OS that don't use the default, e.g., Irix.
+- confDELIVERY_MODE is set to interactive in msp.m4 instead
+ of the default background mode.
+
+Some things are not intended to work with the MSP. These include
+features that influence the delivery process (e.g., mailertable,
+aliases), or those that are only important for a SMTP server (e.g.,
+virtusertable, DaemonPortOptions, multiple queues). Moreover,
+relaxing certain restrictions (RestrictQueueRun, permissions on
+queue directory) or adding features (e.g., enabling prog/file mailer)
+can cause security problems.
+
+Other things don't work well with the MSP and require tweaking or
+workarounds. For example, to allow for client authentication it
+is not just sufficient to provide a client certificate and the
+corresponding key, but it is also necessary to make the key group
+(smmsp) readable and tell sendmail not to complain about that, i.e.,
+
+ define(`confDONT_BLAME_SENDMAIL', `GroupReadableKeyFile')
+
+If the MSP should actually use AUTH then the necessary data
+should be placed in a map as explained in SMTP AUTHENTICATION:
+
+FEATURE(`authinfo', `DATABASE_MAP_TYPE /etc/mail/msp-authinfo')
+
+/etc/mail/msp-authinfo should contain an entry like:
+
+ AuthInfo:127.0.0.1 "U:smmsp" "P:secret" "M:DIGEST-MD5"
+
+The file and the map created by makemap should be owned by smmsp,
+its group should be smmsp, and it should have mode 640. The database
+used by the MTA for AUTH must have a corresponding entry.
+Additionally the MTA must trust this authentication data so the AUTH=
+part will be relayed on to the next hop. This can be achieved by
+adding the following to your sendmail.mc file:
+
+ LOCAL_RULESETS
+ SLocal_trust_auth
+ R$* $: $&{auth_authen}
+ Rsmmsp $# OK
+
+feature/msp.m4 defines almost all settings for the MSP. Most of
+those should not be changed at all. Some of the features and options
+can be overridden if really necessary. It is a bit tricky to do
+this, because it depends on the actual way the option is defined
+in feature/msp.m4. If it is directly defined (i.e., define()) then
+the modified value must be defined after
+
+ FEATURE(`msp')
+
+If it is conditionally defined (i.e., ifdef()) then the desired
+value must be defined before the FEATURE line in the .mc file.
+To see how the options are defined read feature/msp.m4.
+
+
++--------------------------+
+| FORMAT OF FILES AND MAPS |
++--------------------------+
+
+Files that define classes, i.e., F{classname}, consist of lines
+each of which contains a single element of the class. For example,
+/etc/mail/local-host-names may have the following content:
+
+my.domain
+another.domain
+
+Maps must be created using makemap(8) , e.g.,
+
+ makemap hash MAP < MAP
+
+In general, a text file from which a map is created contains lines
+of the form
+
+key value
+
+where 'key' and 'value' are also called LHS and RHS, respectively.
+By default, the delimiter between LHS and RHS is a non-empty sequence
+of white space characters.
+
+
++------------------+
+| DIRECTORY LAYOUT |
++------------------+
Within this directory are several subdirectories, to wit:
@@ -3226,7 +4151,6 @@ RULESETS (* means built in to sendmail)
96 Bottom half of Ruleset 3 (ruleset 6 in old sendmail)
97 Hook for recursive ruleset 0 call (ruleset 7 in old sendmail)
98 Local part of ruleset 0 (ruleset 8 in old sendmail)
- 99 Guaranteed null (for debugging)
MAILERS
@@ -3313,4 +4237,4 @@ M4 DIVERSIONS
8 DNS based blacklists
9 special local rulesets (1 and 2)
-$Revision: 8.383.2.1.2.49 $, Last updated $Date: 2001/08/14 15:25:36 $
+$Revision: 8.600 $, Last updated $Date: 2002/01/10 17:43:41 $
diff --git a/contrib/sendmail/cf/cf/Makefile b/contrib/sendmail/cf/cf/Makefile
index 6bc9207..9a69a18 100644
--- a/contrib/sendmail/cf/cf/Makefile
+++ b/contrib/sendmail/cf/cf/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for configuration files.
#
-# $Id: Makefile,v 8.40.8.5 2001/04/12 22:39:52 gshapiro Exp $
+# $Id: Makefile,v 8.56 2001/12/13 23:56:37 gshapiro Exp $
#
#
@@ -11,11 +11,24 @@
# /usr/5bin/m4.
#
+# name of source for sendmail.cf (without extension)
+CF= sendmail
+# name of source for submit.cf (without extension)
+SUBMIT= submit
+# directory for .cf files
+MAILDIR=/etc/mail
M4= m4
CFDIR= ..
CHMOD= chmod
ROMODE= 444
RM= rm -f
+# use our own install program; should be really confINSTALL
+INSTALL=../../devtools/bin/install.sh
+# CF file ownership/permissions
+CFOWN=root
+CFGRP=bin
+CFMODE=0444
+
.SUFFIXES: .mc .cf
@@ -25,16 +38,16 @@ RM= rm -f
$(CHMOD) $(ROMODE) $@
GENERIC=generic-bsd4.4.cf generic-hpux9.cf generic-hpux10.cf \
- generic-linux.cf generic-nextstep3.3.cf \
- generic-osf1.cf generic-solaris2.cf \
+ generic-linux.cf generic-mpeix.cf generic-nextstep3.3.cf \
+ generic-osf1.cf generic-solaris.cf \
generic-sunos4.1.cf generic-ultrix4.cf
-BERKELEY=cs-hpux9.cf cs-hpux10.cf cs-osf1.cf cs-solaris2.cf \
+BERKELEY=cs-hpux9.cf cs-hpux10.cf cs-osf1.cf cs-solaris.cf \
cs-sunos4.1.cf cs-ultrix4.cf \
s2k-osf1.cf s2k-ultrix4.cf \
chez.cs.cf huginn.cs.cf mail.cs.cf mail.eecs.cf mailspool.cs.cf \
python.cs.cf ucbarpa.cf ucbvax.cf vangogh.cs.cf
OTHER= knecht.cf
-ALL= $(GENERIC) $(BERKELEY) $(OTHER)
+ALL= submit.cf $(GENERIC) $(OTHER)
all: $(ALL)
@@ -45,7 +58,30 @@ other: $(OTHER)
clean cleandir:
$(RM) $(ALL) core
-depend install:
+install:
+ @echo "Before installing the .cf files please make sure you have read the"
+ @echo "instructions in the file ../../INSTALL. You should have prepared the"
+ @echo "files \"submit.mc\" (supplied) and \"sendmail.mc\". Then you can use"
+ @echo ""
+ @echo " make install-cf"
+ @echo ""
+ @echo "If you use a different name than \"sendmail\" for your main .mc file"
+
+ @echo "then you should use"
+ @echo ""
+ @echo " make install-cf CF=config"
+ @echo ""
+ @echo "where \"config\" is the name of your main .mc file."
+
+install-cf: install-sendmail-cf install-submit-cf
+
+install-sendmail-cf: $(CF).cf
+ $(INSTALL) -c -o $(CFOWN) -g $(CFGRP) -m $(CFMODE) $(CF).cf ${DESTDIR}$(MAILDIR)/sendmail.cf
+
+install-submit-cf: $(SUBMIT).cf
+ $(INSTALL) -c -o $(CFOWN) -g $(CFGRP) -m $(CFMODE) $(SUBMIT).cf ${DESTDIR}$(MAILDIR)/submit.cf
+
+depend:
# this is overkill, but....
M4FILES=\
@@ -82,7 +118,6 @@ M4FILES=\
${CFDIR}/feature/nouucp.m4 \
${CFDIR}/feature/nullclient.m4 \
${CFDIR}/feature/promiscuous_relay.m4 \
- ${CFDIR}/feature/rbl.m4 \
${CFDIR}/feature/redirect.m4 \
${CFDIR}/feature/relay_based_on_MX.m4 \
${CFDIR}/feature/relay_entire_domain.m4 \
@@ -112,11 +147,11 @@ M4FILES=\
${CFDIR}/mailer/smtp.m4 \
${CFDIR}/mailer/usenet.m4 \
${CFDIR}/mailer/uucp.m4 \
- ${CFDIR}/ostype/aix2.m4 \
${CFDIR}/ostype/aix3.m4 \
${CFDIR}/ostype/aix4.m4 \
${CFDIR}/ostype/altos.m4 \
${CFDIR}/ostype/amdahl-uts.m4 \
+ ${CFDIR}/ostype/a-ux.m4 \
${CFDIR}/ostype/bsd4.3.m4 \
${CFDIR}/ostype/bsd4.4.m4 \
${CFDIR}/ostype/bsdi.m4 \
@@ -125,6 +160,8 @@ M4FILES=\
${CFDIR}/ostype/dgux.m4 \
${CFDIR}/ostype/domainos.m4 \
${CFDIR}/ostype/dynix3.2.m4 \
+ ${CFDIR}/ostype/freebsd4.m4 \
+ ${CFDIR}/ostype/freebsd5.m4 \
${CFDIR}/ostype/gnu.m4 \
${CFDIR}/ostype/hpux10.m4 \
${CFDIR}/ostype/hpux11.m4 \
@@ -136,6 +173,7 @@ M4FILES=\
${CFDIR}/ostype/linux.m4 \
${CFDIR}/ostype/maxion.m4 \
${CFDIR}/ostype/mklinux.m4 \
+ ${CFDIR}/ostype/mpeix.m4 \
${CFDIR}/ostype/nextstep.m4 \
${CFDIR}/ostype/openbsd.m4 \
${CFDIR}/ostype/osf1.m4 \
diff --git a/contrib/sendmail/cf/cf/README b/contrib/sendmail/cf/cf/README
new file mode 100644
index 0000000..f3543bf
--- /dev/null
+++ b/contrib/sendmail/cf/cf/README
@@ -0,0 +1,34 @@
+
+ SENDMAIL CONFIGURATION FILES INSTALLATION
+
+This document describes how to install the sendmail configuration files.
+Please see ../README about the sendmail configuration files themselves.
+
+By default you need two .mc files: sendmail.mc and submit.mc. The
+latter is a copy of msp.mc in which OSTYPE() has been filled in
+according to the host OS. For the former see ../README.
+
+Installation of these two files can be done via:
+
+ make install-cf
+
+If you use a different name than "sendmail" for your main .mc file"
+then you should use
+
+ make install-cf CF=config
+
+where "config" is the name of your main .mc file.
+
+The default installation directory is /etc/mail and can be changed
+by specifying
+
+ MAILDIR=/other/dir
+
+The name of the source file for "submit.cf" can be overridden by
+
+ SUBMIT=msp
+
+For more details see Makefile.
+
+
+$Revision: 1.1 $, Last updated $Date: 2001/04/26 15:43:20 $
diff --git a/contrib/sendmail/cf/cf/generic-hpux10.mc b/contrib/sendmail/cf/cf/generic-hpux10.mc
index d205869..deed5f1 100644
--- a/contrib/sendmail/cf/cf/generic-hpux10.mc
+++ b/contrib/sendmail/cf/cf/generic-hpux10.mc
@@ -20,7 +20,7 @@ divert(-1)
#
divert(0)dnl
-VERSIONID(`$Id: generic-hpux10.mc,v 8.11.22.2 2001/05/29 17:30:18 ca Exp $')
+VERSIONID(`$Id: generic-hpux10.mc,v 8.13 2001/05/29 17:29:52 ca Exp $')
OSTYPE(hpux10)dnl
DOMAIN(generic)dnl
MAILER(local)dnl
diff --git a/contrib/sendmail/cf/cf/generic-mpeix.mc b/contrib/sendmail/cf/cf/generic-mpeix.mc
new file mode 100644
index 0000000..fa5c574
--- /dev/null
+++ b/contrib/sendmail/cf/cf/generic-mpeix.mc
@@ -0,0 +1,25 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+#
+# This is a generic configuration file for HP MPE/iX.
+# It has support for local and SMTP mail only. If you want to
+# customize it, copy it to a name appropriate for your environment
+# and do the modifications there.
+#
+
+divert(0)dnl
+VERSIONID(`$Id: generic-mpeix.mc,v 8.1 2001/12/13 23:56:37 gshapiro Exp $')
+OSTYPE(mpeix)dnl
+DOMAIN(generic)dnl
+define(`confFORWARD_PATH', `$z/.forward')dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/contrib/sendmail/cf/cf/generic-solaris.mc b/contrib/sendmail/cf/cf/generic-solaris.mc
new file mode 100644
index 0000000..5f82340
--- /dev/null
+++ b/contrib/sendmail/cf/cf/generic-solaris.mc
@@ -0,0 +1,29 @@
+divert(-1)
+#
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+# Copyright (c) 1983 Eric P. Allman. All rights reserved.
+# Copyright (c) 1988, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+#
+# This is a generic configuration file for SunOS 5.x (a.k.a. Solaris 2.x
+# and Solaris 7 through the present version).
+#
+# It has support for local and SMTP mail only. If you want to
+# customize it, copy it to a name appropriate for your environment
+# and do the modifications there.
+#
+
+divert(0)dnl
+VERSIONID(`$Id: generic-solaris.mc,v 8.13 2001/06/27 21:46:30 gshapiro Exp $')
+OSTYPE(solaris2)dnl
+DOMAIN(generic)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/contrib/sendmail/cf/cf/knecht.mc b/contrib/sendmail/cf/cf/knecht.mc
index 89f9c53..6c370fd 100644
--- a/contrib/sendmail/cf/cf/knecht.mc
+++ b/contrib/sendmail/cf/cf/knecht.mc
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -15,31 +15,54 @@ divert(-1)
#
# This is specific to Eric's home machine.
#
+# Run daemon with -bd -q5m
+#
+
+divert(0)
+VERSIONID(`$Id: knecht.mc,v 8.55 2001/08/01 22:20:40 eric Exp $')
+OSTYPE(bsd4.4)
+DOMAIN(generic)
+
+define(`ALIAS_FILE', ``/etc/mail/aliases, /var/listmanager/aliases'')
+define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward+$h:$z/.forward')
+define(`confDEF_USER_ID', `mailnull')
+define(`confHOST_STATUS_DIRECTORY', `.hoststat')
+define(`confTO_ICONNECT', `10s')
+define(`confCOPY_ERRORS_TO', `Postmaster')
+define(`confTO_QUEUEWARN', `8h')
+define(`confMIN_QUEUE_AGE', `27m')
+define(`confTRUSTED_USERS', ``www listmgr'')
+define(`confPRIVACY_FLAGS', ``authwarnings,noexpn,novrfy'')
+
+define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')
+define(`confCACERT_PATH', `CERT_DIR')
+define(`confCACERT', `CERT_DIR/CAcert.pem')
+define(`confSERVER_CERT', `CERT_DIR/MYcert.pem')
+define(`confSERVER_KEY', `CERT_DIR/MYkey.pem')
+define(`confCLIENT_CERT', `CERT_DIR/MYcert.pem')
+define(`confCLIENT_KEY', `CERT_DIR/MYkey.pem')
+
+FEATURE(access_db)
+FEATURE(local_lmtp)
+FEATURE(virtusertable)
+
+FEATURE(`nocanonify', `canonify_hosts')
+CANONIFY_DOMAIN(`sendmail.org')
+CANONIFY_DOMAIN_FILE(`/etc/mail/canonify-domains')
+
+dnl # at most 10 queue runners
+define(`confMAX_QUEUE_CHILDREN', `20')
+
+define(`confMAX_RUNNERS_PER_QUEUE', `5')
+
+dnl # run at most 10 concurrent processes for initial submission
+define(`confFAST_SPLIT', `10')
-divert(0)dnl
-VERSIONID(`$Id: knecht.mc,v 8.37.16.3 2001/02/22 22:38:39 ca Exp $')
-OSTYPE(bsd4.4)dnl
-DOMAIN(generic)dnl
-define(`confFORWARD_PATH', `$z/.forward.$w:$z/.forward+$h:$z/.forward')dnl
-define(`confDEF_USER_ID', `mailnull')dnl
-define(`confHOST_STATUS_DIRECTORY', `.hoststat')dnl
-define(`confTO_ICONNECT', `10s')dnl
-define(`confCOPY_ERRORS_TO', `Postmaster')dnl
-define(`confTO_QUEUEWARN', `8h')dnl
-define(`confTRUSTED_USERS', `www')dnl
-define(`confPRIVACY_FLAGS', ``authwarnings,noexpn,novrfy'')dnl
-define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')dnl
-define(`confCACERT_PATH', `CERT_DIR')dnl
-define(`confCACERT', `CERT_DIR/CAcert.pem')dnl
-define(`confSERVER_CERT', `CERT_DIR/MYcert.pem')dnl
-define(`confSERVER_KEY', `CERT_DIR/MYkey.pem')dnl
-define(`confCLIENT_CERT', `CERT_DIR/MYcert.pem')dnl
-define(`confCLIENT_KEY', `CERT_DIR/MYkey.pem')dnl
-FEATURE(virtusertable)dnl
-FEATURE(access_db)dnl
-FEATURE(local_lmtp)dnl
-MAILER(local)dnl
-MAILER(smtp)dnl
+dnl # 10 runners, split into at most 15 recipients per envelope
+QUEUE_GROUP(`mqueue', `P=/var/spool/mqueue, R=5, r=15, F=f')
+
+MAILER(local)
+MAILER(smtp)
LOCAL_CONFIG
#
@@ -69,9 +92,80 @@ SCheckMessageId
R< $+ @ $+ > $@ OK
R$* $#error $: "554 Header error"
+HReceived: $>CheckReceived
+
+SCheckReceived
+R$* ......................................................... $*
+ $#error $: "554 Header error"
+
+#
+# Reject certain senders
+# Regex match to catch things in quotes
+#
+HFrom: $>+CheckFrom
+KCheckFrom regex -a@MATCH
+ [^a-z]?(Net-Pa)[^a-z]
+
+SCheckFrom
+R$* $: $( CheckFrom $1 $)
+R@MATCH $#error $: "553 Header error"
+
LOCAL_RULESETS
SLocal_check_mail
# check address against various regex checks
R$* $: $>Parse0 $>3 $1
R$+ $: $(checkaddress $1 $)
R@MATCH $#error $: "553 Header error"
+
+#
+# Following code from Anthony Howe <achowe@snert.com>. The check
+# for the Outlook Express marker may hit some legal messages, but
+# the Content-Disposition is clearly illegal.
+#
+
+#########################################################################
+#
+# w32.sircam.worm@mm
+#
+# There are serveral patterns that appear common ONLY to SirCam worm and
+# not to Outlook Express, which claims to have sent the worm. There are
+# four headers that always appear together and in this order:
+#
+# X-MIMEOLE: Produced By Microsoft MimeOLE V5.50.4133.2400
+# X-Mailer: Microsoft Outlook Express 5.50.4133.2400
+# Content-Type: multipart/mixed; boundary="----27AA9124_Outlook_Express_message_boundary"
+# Content-Disposition: Multipart message
+#
+# Empirical study of the worm message headers vs. true Outlook Express
+# (5.50.4133.2400 & 5.50.4522.1200) messages with multipart/mixed attachments
+# shows Outlook Express does:
+#
+# a) NOT supply a Content-Disposition header for multipart/mixed messages.
+# b) NOT specify the header X-MimeOLE header name in all-caps
+# c) NOT specify boundary tag with the expression "_Outlook_Express_message_boundary"
+#
+# The solution below catches any one of this three issues. This is not an ideal
+# solution, but a temporary measure. A correct solution would be to check for
+# the presence of ALL three header attributes. Also the solution is incomplete
+# since Outlook Express 5.0 and 4.0 were not compared.
+#
+# NOTE regex keys are first dequoted and spaces removed before matching.
+# This caused me no end of grief.
+#
+#########################################################################
+
+LOCAL_RULESETS
+
+KSirCamWormMarker regex -f -aSUSPECT multipart/mixed;boundary=----.+_Outlook_Express_message_boundary
+HContent-Type: $>CheckContentType
+
+SCheckContentType
+R$+ $: $(SirCamWormMarker $1 $)
+RSUSPECT $#error $: "553 Possible virus, see http://www.symantec.com/avcenter/venc/data/w32.sircam.worm@mm.html"
+
+HContent-Disposition: $>CheckContentDisposition
+
+SCheckContentDisposition
+R$- $@ OK
+R$- ; $+ $@ OK
+R$* $#error $: "553 Illegal Content-Disposition"
diff --git a/contrib/sendmail/cf/cf/submit.cf b/contrib/sendmail/cf/cf/submit.cf
new file mode 100644
index 0000000..8897b20
--- /dev/null
+++ b/contrib/sendmail/cf/cf/submit.cf
@@ -0,0 +1,1369 @@
+#
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved.
+# Copyright (c) 1988, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+######################################################################
+######################################################################
+#####
+##### SENDMAIL CONFIGURATION FILE
+#####
+#####
+######################################################################
+#####
+##### DO NOT EDIT THIS FILE! Only edit the source .mc file.
+#####
+######################################################################
+######################################################################
+
+##### $Id: cfhead.m4,v 8.107 2001/07/22 03:25:37 ca Exp $ #####
+##### $Id: cf.m4,v 8.32 1999/02/07 07:26:14 gshapiro Exp $ #####
+##### $Id: submit.mc,v 8.5 2001/09/08 01:20:53 gshapiro Exp $ #####
+##### $Id: msp.m4,v 1.29 2001/12/13 23:56:38 gshapiro Exp $ #####
+
+##### $Id: no_default_msa.m4,v 8.2 2001/02/14 05:03:22 gshapiro Exp $ #####
+
+
+##### $Id: proto.m4,v 8.628 2001/12/28 19:02:40 ca Exp $ #####
+
+# level 10 config file format
+V10/Berkeley
+
+# override file safeties - setting this option compromises system security,
+# addressing the actual file configuration problem is preferred
+# need to set this before any file actions are encountered in the cf file
+#O DontBlameSendmail=safe
+
+# default LDAP map specification
+# need to set this now before any LDAP maps are defined
+#O LDAPDefaultSpec=-h localhost
+
+##################
+# local info #
+##################
+
+# my LDAP cluster
+# need to set this before any LDAP lookups are done (including classes)
+#D{sendmailMTACluster}$m
+
+Cwlocalhost
+
+# my official domain name
+# ... define this only if sendmail cannot automatically determine your domain
+#Dj$w.Foo.COM
+
+CP.
+
+# "Smart" relay host (may be null)
+DS
+
+
+# operators that cannot be in local usernames (i.e., network indicators)
+CO @ % !
+
+# a class with just dot (for identifying canonical names)
+C..
+
+# a class with just a left bracket (for identifying domain literals)
+C[[
+
+
+# Resolve map (to check if a host exists in check_mail)
+Kresolve host -a<OKR> -T<TEMP>
+C{ResOk}OKR
+
+
+# Hosts for which relaying is permitted ($=R)
+FR-o /etc/mail/relay-domains
+
+# arithmetic map
+Karith arith
+
+
+
+
+
+# dequoting map
+Kdequote dequote
+
+# class E: names that should be exposed as from this host, even if we masquerade
+# class L: names that should be delivered locally, even if we have a relay
+# class M: domains that should be converted to $M
+# class N: domains that should not be converted to $M
+#CL root
+
+
+
+# my name for error messages
+DnMAILER-DAEMON
+
+
+D{MTAHost}localhost
+
+
+# Configuration version number
+DZ8.12.2/Submit
+
+
+###############
+# Options #
+###############
+
+# strip message body to 7 bits on input?
+O SevenBitInput=False
+
+# 8-bit data handling
+#O EightBitMode=pass8
+
+# wait for alias file rebuild (default units: minutes)
+O AliasWait=10
+
+# location of alias file
+O AliasFile
+
+# minimum number of free blocks on filesystem
+O MinFreeBlocks=100
+
+# maximum message size
+#O MaxMessageSize=1000000
+
+# substitution for space (blank) characters
+O BlankSub=.
+
+# avoid connecting to "expensive" mailers on initial submission?
+O HoldExpensive=False
+
+# checkpoint queue runs after every N successful deliveries
+#O CheckpointInterval=10
+
+# default delivery mode
+O DeliveryMode=i
+
+# error message header/file
+#O ErrorHeader=/etc/mail/error-header
+
+# error mode
+#O ErrorMode=print
+
+# save Unix-style "From_" lines at top of header?
+#O SaveFromLine=False
+
+# queue file mode (qf files)
+O QueueFileMode=0660
+
+# temporary file mode
+O TempFileMode=0600
+
+# match recipients against GECOS field?
+#O MatchGECOS=False
+
+# maximum hop count
+#O MaxHopCount=25
+
+# location of help file
+O HelpFile=/etc/mail/helpfile
+
+# ignore dots as terminators in incoming messages?
+#O IgnoreDots=False
+
+# name resolver options
+#O ResolverOptions=+AAONLY
+
+# deliver MIME-encapsulated error messages?
+O SendMimeErrors=True
+
+# Forward file search path
+O ForwardPath
+
+# open connection cache size
+O ConnectionCacheSize=2
+
+# open connection cache timeout
+O ConnectionCacheTimeout=5m
+
+# persistent host status directory
+#O HostStatusDirectory=.hoststat
+
+# single thread deliveries (requires HostStatusDirectory)?
+#O SingleThreadDelivery=False
+
+# use Errors-To: header?
+O UseErrorsTo=False
+
+# log level
+O LogLevel=9
+
+# send to me too, even in an alias expansion?
+#O MeToo=True
+
+# verify RHS in newaliases?
+O CheckAliases=False
+
+# default messages to old style headers if no special punctuation?
+O OldStyleHeaders=True
+
+# SMTP daemon options
+
+O DaemonPortOptions=Name=NoMTA, Addr=127.0.0.1, M=E
+
+# SMTP client options
+#O ClientPortOptions=Family=inet, Address=0.0.0.0
+
+# Modifiers to define {daemon_flags} for direct submissions
+#O DirectSubmissionModifiers
+
+# Use as mail submission program? See sendmail/SECURITY
+O UseMSP=True
+
+# privacy flags
+O PrivacyOptions=goaway,noetrn,restrictqrun
+
+# who (if anyone) should get extra copies of error messages
+#O PostmasterCopy=Postmaster
+
+# slope of queue-only function
+#O QueueFactor=600000
+
+# limit on number of concurrent queue runners
+#O MaxQueueChildren
+
+# maximum number of queue-runners per queue-grouping with multiple queues
+#O MaxRunnersPerQueue=1
+
+# priority of queue runners (nice(3))
+#O NiceQueueRun
+
+# shall we sort the queue by hostname first?
+#O QueueSortOrder=priority
+
+# minimum time in queue before retry
+#O MinQueueAge=30m
+
+# how many jobs can you process in the queue?
+#O MaxQueueRunSize=10000
+
+# perform initial split of envelope without checking MX records
+#O FastSplit=1
+
+# queue directory
+O QueueDirectory=/var/spool/clientmqueue
+
+# key for shared memory; 0 to turn off
+#O SharedMemoryKey=0
+
+# timeouts (many of these)
+#O Timeout.initial=5m
+#O Timeout.connect=5m
+#O Timeout.aconnect=0s
+#O Timeout.iconnect=5m
+#O Timeout.helo=5m
+#O Timeout.mail=10m
+#O Timeout.rcpt=1h
+#O Timeout.datainit=5m
+#O Timeout.datablock=1h
+#O Timeout.datafinal=1h
+#O Timeout.rset=5m
+#O Timeout.quit=2m
+#O Timeout.misc=2m
+#O Timeout.command=1h
+#O Timeout.ident=5s
+#O Timeout.fileopen=60s
+#O Timeout.control=2m
+O Timeout.queuereturn=5d
+#O Timeout.queuereturn.normal=5d
+#O Timeout.queuereturn.urgent=2d
+#O Timeout.queuereturn.non-urgent=7d
+O Timeout.queuewarn=4h
+#O Timeout.queuewarn.normal=4h
+#O Timeout.queuewarn.urgent=1h
+#O Timeout.queuewarn.non-urgent=12h
+#O Timeout.hoststatus=30m
+#O Timeout.resolver.retrans=5s
+#O Timeout.resolver.retrans.first=5s
+#O Timeout.resolver.retrans.normal=5s
+#O Timeout.resolver.retry=4
+#O Timeout.resolver.retry.first=4
+#O Timeout.resolver.retry.normal=4
+#O Timeout.lhlo=2m
+#O Timeout.auth=10m
+#O Timeout.starttls=1h
+
+# time for DeliverBy; extension disabled if less than 0
+#O DeliverByMin=0
+
+# should we not prune routes in route-addr syntax addresses?
+#O DontPruneRoutes=False
+
+# queue up everything before forking?
+O SuperSafe=True
+
+# status file
+O StatusFile=/var/spool/clientmqueue/sm-client.st
+
+# time zone handling:
+# if undefined, use system default
+# if defined but null, use TZ envariable passed in
+# if defined and non-null, use that info
+#O TimeZoneSpec=
+
+# default UID (can be username or userid:groupid)
+#O DefaultUser=mailnull
+
+# list of locations of user database file (null means no lookup)
+#O UserDatabaseSpec=/etc/mail/userdb
+
+# fallback MX host
+#O FallbackMXhost=fall.back.host.net
+
+# if we are the best MX host for a site, try it directly instead of config err
+#O TryNullMXList=False
+
+# load average at which we just queue messages
+#O QueueLA=8
+
+# load average at which we refuse connections
+#O RefuseLA=12
+
+# load average at which we delay connections; 0 means no limit
+#O DelayLA=0
+
+# maximum number of children we allow at one time
+#O MaxDaemonChildren=12
+
+# maximum number of new connections per second
+#O ConnectionRateThrottle=0
+
+# work recipient factor
+#O RecipientFactor=30000
+
+# deliver each queued job in a separate process?
+#O ForkEachJob=False
+
+# work class factor
+#O ClassFactor=1800
+
+# work time factor
+#O RetryFactor=90000
+
+# default character set
+#O DefaultCharSet=iso-8859-1
+
+# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
+#O ServiceSwitchFile=/etc/mail/service.switch
+
+# hosts file (normally /etc/hosts)
+#O HostsFile=/etc/hosts
+
+# dialup line delay on connection failure
+#O DialDelay=10s
+
+# action to take if there are no recipients in the message
+#O NoRecipientAction=add-to-undisclosed
+
+# chrooted environment for writing to files
+#O SafeFileEnvironment=/arch
+
+# are colons OK in addresses?
+#O ColonOkInAddr=True
+
+# shall I avoid expanding CNAMEs (violates protocols)?
+#O DontExpandCnames=False
+
+# SMTP initial login message (old $e macro)
+O SmtpGreetingMessage=$j Sendmail $v/$Z; $b
+
+# UNIX initial From header format (old $l macro)
+O UnixFromLine=From $g $d
+
+# From: lines that have embedded newlines are unwrapped onto one line
+#O SingleLineFromHeader=False
+
+# Allow HELO SMTP command that does not include a host name
+#O AllowBogusHELO=False
+
+# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
+#O MustQuoteChars=.
+
+# delimiter (operator) characters (old $o macro)
+O OperatorChars=.:%@!^/[]+
+
+# shall I avoid calling initgroups(3) because of high NIS costs?
+#O DontInitGroups=False
+
+# are group-writable :include: and .forward files (un)trustworthy?
+# True (the default) means they are not trustworthy.
+#O UnsafeGroupWrites=True
+
+
+# where do errors that occur when sending errors get sent?
+#O DoubleBounceAddress=postmaster
+
+# where to save bounces if all else fails
+#O DeadLetterDrop=/var/tmp/dead.letter
+
+# what user id do we assume for the majority of the processing?
+O RunAsUser=smmsp
+
+# maximum number of recipients per SMTP envelope
+#O MaxRecipientsPerMessage=100
+
+# limit the rate recipients per SMTP envelope are accepted
+# once the threshold number of recipients have been rejected
+#O BadRcptThrottle=20
+
+# shall we get local names from our installed interfaces?
+O DontProbeInterfaces=True
+
+# Return-Receipt-To: header implies DSN request
+#O RrtImpliesDsn=False
+
+# override connection address (for testing)
+#O ConnectOnlyTo=0.0.0.0
+
+# Trusted user for file ownership and starting the daemon
+O TrustedUser=smmsp
+
+# Control socket for daemon management
+#O ControlSocketName=/var/spool/mqueue/.control
+
+# Maximum MIME header length to protect MUAs
+#O MaxMimeHeaderLength=0/0
+
+# Maximum length of the sum of all headers
+#O MaxHeadersLength=32768
+
+# Maximum depth of alias recursion
+#O MaxAliasRecursion=10
+
+# location of pid file
+O PidFile=/var/spool/clientmqueue/sm-client.pid
+
+# Prefix string for the process title shown on 'ps' listings
+#O ProcessTitlePrefix=prefix
+
+# Data file (df) memory-buffer file maximum size
+#O DataFileBufferSize=4096
+
+# Transcript file (xf) memory-buffer file maximum size
+#O XscriptFileBufferSize=4096
+
+# lookup type to find information about local mailboxes
+#O MailboxDatabase=pw
+
+# list of authentication mechanisms
+#O AuthMechanisms=EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5
+
+# default authentication information for outgoing connections
+#O DefaultAuthInfo=/etc/mail/default-auth-info
+
+# SMTP AUTH flags
+#O AuthOptions
+
+# SMTP AUTH maximum encryption strength
+#O AuthMaxBits
+
+# SMTP STARTTLS server options
+#O TLSSrvOptions
+
+# Input mail filters
+#O InputMailFilters
+
+
+
+# CA directory
+#O CACERTPath
+# CA file
+#O CACERTFile
+# Server Cert
+#O ServerCertFile
+# Server private key
+#O ServerKeyFile
+# Client Cert
+#O ClientCertFile
+# Client private key
+#O ClientKeyFile
+# DHParameters (only required if DSA/DH is used)
+#O DHParameters
+# Random data source (required for systems without /dev/urandom under OpenSSL)
+#O RandFile
+
+############################
+# QUEUE GROUP DEFINITIONS #
+############################
+
+
+###########################
+# Message precedences #
+###########################
+
+Pfirst-class=0
+Pspecial-delivery=100
+Plist=-30
+Pbulk=-60
+Pjunk=-100
+
+#####################
+# Trusted users #
+#####################
+
+# this is equivalent to setting class "t"
+#Ft/etc/mail/trusted-users
+Troot
+Tdaemon
+Tuucp
+
+#########################
+# Format of headers #
+#########################
+
+H?P?Return-Path: <$g>
+HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
+ $.$?{auth_type}(authenticated$?{auth_ssf} bits=${auth_ssf}$.)
+ $.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}
+ (version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})$.$?u
+ for $u; $|;
+ $.$b
+H?D?Resent-Date: $a
+H?D?Date: $a
+H?F?Resent-From: $?x$x <$g>$|$g$.
+H?F?From: $?x$x <$g>$|$g$.
+H?x?Full-Name: $x
+# HPosted-Date: $a
+# H?l?Received-Date: $b
+H?M?Resent-Message-Id: <$t.$i@$j>
+H?M?Message-Id: <$t.$i@$j>
+
+#
+######################################################################
+######################################################################
+#####
+##### REWRITING RULES
+#####
+######################################################################
+######################################################################
+
+############################################
+### Ruleset 3 -- Name Canonicalization ###
+############################################
+Scanonify=3
+
+# handle null input (translate to <@> special case)
+R$@ $@ <@>
+
+# strip group: syntax (not inside angle brackets!) and trailing semicolon
+R$* $: $1 <@> mark addresses
+R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr>
+R@ $* <@> $: @ $1 unmark @host:...
+R$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr
+R$* :: $* <@> $: $1 :: $2 unmark node::addr
+R:include: $* <@> $: :include: $1 unmark :include:...
+R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon
+R$* : $* <@> $: $2 strip colon if marked
+R$* <@> $: $1 unmark
+R$* ; $1 strip trailing semi
+R$* < $+ :; > $* $@ $2 :; <@> catch <list:;>
+R$* < $* ; > $1 < $2 > bogus bracketed semi
+
+# null input now results from list:; syntax
+R$@ $@ :; <@>
+
+# strip angle brackets -- note RFC733 heuristic to get innermost item
+R$* $: < $1 > housekeeping <>
+R$+ < $* > < $2 > strip excess on left
+R< $* > $+ < $1 > strip excess on right
+R<> $@ < @ > MAIL FROM:<> case
+R< $+ > $: $1 remove housekeeping <>
+
+# strip route address <@a,@b,@c:user@d> -> <user@d>
+R@ $+ , $+ $2
+R@ [ $* ] : $+ $2
+R@ $+ : $+ $2
+
+# find focus for list syntax
+R $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax
+R $+ : $* ; $@ $1 : $2; list syntax
+
+# find focus for @ syntax addresses
+R$+ @ $+ $: $1 < @ $2 > focus on domain
+R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right
+R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical
+
+
+# convert old-style addresses to a domain-based address
+R$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names
+R$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps
+R$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains
+
+# convert node::user addresses into a domain-based address
+R$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names
+R$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr
+
+# if we have % signs, take the rightmost one
+R$* % $* $1 @ $2 First make them all @s.
+R$* @ $* @ $* $1 % $2 @ $3 Undo all but the last.
+R$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish
+
+# else we must be a local name
+R$* $@ $>Canonify2 $1
+
+
+################################################
+### Ruleset 96 -- bottom half of ruleset 3 ###
+################################################
+
+SCanonify2=96
+
+# handle special cases for local names
+R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all
+R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain
+R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain
+
+# check for IPv4/IPv6 domain literal
+R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr]
+R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal
+R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr
+
+
+
+
+
+# if really UUCP, handle it immediately
+
+# try UUCP traffic as a local address
+R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3
+R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3
+
+# hostnames ending in class P are always canonical
+R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4
+R$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4
+R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
+R$* CC $* $| $* $: $3
+# pass to name server to make hostname canonical
+R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4
+R$* $| $* $: $2
+
+# local host aliases and pseudo-domains are always canonical
+R$* < @ $=w > $* $: $1 < @ $2 . > $3
+R$* < @ $=M > $* $: $1 < @ $2 . > $3
+R$* < @ $* . . > $* $1 < @ $2 . > $3
+
+
+##################################################
+### Ruleset 4 -- Final Output Post-rewriting ###
+##################################################
+Sfinal=4
+
+R$+ :; <@> $@ $1 : handle <list:;>
+R$* <@> $@ handle <> and list:;
+
+# strip trailing dot off possibly canonical name
+R$* < @ $+ . > $* $1 < @ $2 > $3
+
+# eliminate internal code
+R$* < @ *LOCAL* > $* $1 < @ $j > $2
+
+# externalize local domain info
+R$* < $+ > $* $1 $2 $3 defocus
+R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical
+R@ $* $@ @ $1 ... and exit
+
+# UUCP must always be presented in old form
+R$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u
+
+# put DECnet back in :: form
+R$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u
+# delete duplicate local names
+R$+ % $=w @ $=w $1 @ $2 u%host@host => u@host
+
+
+
+##############################################################
+### Ruleset 97 -- recanonicalize and call ruleset zero ###
+### (used for recursive calls) ###
+##############################################################
+
+SRecurse=97
+R$* $: $>canonify $1
+R$* $@ $>parse $1
+
+
+######################################
+### Ruleset 0 -- Parse Address ###
+######################################
+
+Sparse=0
+
+R$* $: $>Parse0 $1 initial parsing
+R<@> $#local $: <@> special case error msgs
+R$* $: $>ParseLocal $1 handle local hacks
+R$* $: $>Parse1 $1 final parsing
+
+#
+# Parse0 -- do initial syntax checking and eliminate local addresses.
+# This should either return with the (possibly modified) input
+# or return with a #error mailer. It should not return with a
+# #mailer other than the #error mailer.
+#
+
+SParse0
+R<@> $@ <@> special case error msgs
+R$* : $* ; <@> $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses"
+R@ <@ $* > < @ $1 > catch "@@host" bogosity
+R<@ $+> $#error $@ 5.1.3 $: "553 User address required"
+R$+ <@> $#error $@ 5.1.3 $: "553 Hostname required"
+R$* $: <> $1
+R<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4
+R<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4
+R<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "553 Invalid address"
+R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3
+R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "553 Colon illegal in host name part"
+R<> $* $1
+R$* < @ . $* > $* $#error $@ 5.1.2 $: "553 Invalid host name"
+R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "553 Invalid host name"
+R$* < @ $* @ > $* $#error $@ 5.1.2 $: "553 Invalid route address"
+R$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "553 Invalid route address"
+R$* , $~O $* $#error $@ 5.1.3 $: "553 Invalid route address"
+
+
+# now delete the local info -- note $=O to find characters that cause forwarding
+R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user
+R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ...
+R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here
+R< @ $+ > $#error $@ 5.1.3 $: "553 User address required"
+R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ...
+R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo"
+R< @ *LOCAL* > $#error $@ 5.1.3 $: "553 User address required"
+R$* $=O $* < @ *LOCAL* >
+ $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ...
+R$* < @ *LOCAL* > $: $1
+
+#
+# Parse1 -- the bottom half of ruleset 0.
+#
+
+SParse1
+
+# handle numeric address spec
+R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec
+R$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path
+R$* < @ [ $+ ] : > $* $#esmtp $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send
+R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer
+R$* < @ [ $+ ] : $+ > $* $#esmtp $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer
+
+
+# short circuit local delivery so forwarded email works
+
+
+R$=L < @ $=w . > $#local $: @ $1 special local names
+R$+ < @ $=w . > $#local $: $1 regular local name
+
+
+# resolve remotely connected UUCP links (if any)
+
+# resolve fake top level domains by forwarding to other hosts
+
+
+
+# pass names that still have a host to a smarthost (if defined)
+R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name
+
+# deal with other remote names
+R$* < @$* > $* $#esmtp $@ $2 $: $1 < @ $2 > $3 user@host.domain
+
+# handle locally delivered names
+R$=L $#local $: @ $1 special local names
+R$+ $#local $: $1 regular local names
+
+###########################################################################
+### Ruleset 5 -- special rewriting after aliases have been expanded ###
+###########################################################################
+
+SLocal_localaddr
+Slocaladdr=5
+R$+ $: $1 $| $>"Local_localaddr" $1
+R$+ $| $#ok $@ $1 no change
+R$+ $| $#$* $#$2
+R$+ $| $* $: $1
+
+
+
+
+# deal with plussed users so aliases work nicely
+R$+ + * $#local $@ $&h $: $1
+R$+ + $* $#local $@ + $2 $: $1 + *
+
+# prepend an empty "forward host" on the front
+R$+ $: <> $1
+
+
+
+R< > $+ $: < > < $1 <> $&h > nope, restore +detail
+
+R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail
+R< > < $+ <> $* > $: < > < $1 > else discard
+R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part
+R< > < $+ > + $* $#local $@ $2 $: @ $1 strip the extra +
+R< > < $+ > $@ $1 no +detail
+R$+ $: $1 <> $&h add +detail back in
+
+R$+ <> + $* $: $1 + $2 check whether +detail
+R$+ <> $* $: $1 else discard
+R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension
+R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension
+
+R< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
+
+R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 >
+
+
+###################################################################
+### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ###
+###################################################################
+
+SMailerToTriple=95
+R< > $* $@ $1 strip off null relay
+R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4
+R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2
+R< local : $* > $* $>CanonLocal < $1 > $2
+R< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user
+R< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer
+R< $=w > $* $@ $2 delete local host
+R< $+ > $* $#relay $@ $1 $: $2 use unqualified mailer
+
+###################################################################
+### Ruleset CanonLocal -- canonify local: syntax ###
+###################################################################
+
+SCanonLocal
+# strip local host from routed addresses
+R< $* > < @ $+ > : $+ $@ $>Recurse $3
+R< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4
+
+# strip trailing dot from any host name that may appear
+R< $* > $* < @ $* . > $: < $1 > $2 < @ $3 >
+
+# handle local: syntax -- use old user, either with or without host
+R< > $* < @ $* > $* $#local $@ $1@$2 $: $1
+R< > $+ $#local $@ $1 $: $1
+
+# handle local:user@host syntax -- ignore host part
+R< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 >
+
+# handle local:user syntax
+R< $+ > $* <@ $* > $* $#local $@ $2@$3 $: $1
+R< $+ > $* $#local $@ $2 $: $1
+
+###################################################################
+### Ruleset 93 -- convert header names to masqueraded form ###
+###################################################################
+
+SMasqHdr=93
+
+
+# do not masquerade anything in class N
+R$* < @ $* $=N . > $@ $1 < @ $2 $3 . >
+
+R$* < @ *LOCAL* > $@ $1 < @ $j . >
+
+###################################################################
+### Ruleset 94 -- convert envelope names to masqueraded form ###
+###################################################################
+
+SMasqEnv=94
+R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2
+
+###################################################################
+### Ruleset 98 -- local part of ruleset zero (can be null) ###
+###################################################################
+
+SParseLocal=98
+
+
+
+
+######################################################################
+### CanonAddr -- Convert an address into a standard form for
+### relay checking. Route address syntax is
+### crudely converted into a %-hack address.
+###
+### Parameters:
+### $1 -- full recipient address
+###
+### Returns:
+### parsed address, not in source route form
+######################################################################
+
+SCanonAddr
+R$* $: $>Parse0 $>canonify $1 make domain canonical
+
+
+######################################################################
+### ParseRecipient -- Strip off hosts in $=R as well as possibly
+### $* $=m or the access database.
+### Check user portion for host separators.
+###
+### Parameters:
+### $1 -- full recipient address
+###
+### Returns:
+### parsed, non-local-relaying address
+######################################################################
+
+SParseRecipient
+R$* $: <?> $>CanonAddr $1
+R<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots
+R<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part
+
+# if no $=O character, no host in the user portion, we are done
+R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4>
+R<?> $* $@ $1
+
+
+R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 >
+
+
+
+R<RELAY> $* < @ $* > $@ $>ParseRecipient $1
+R<$+> $* $@ $2
+
+
+######################################################################
+### check_relay -- check hostname/address on SMTP startup
+######################################################################
+
+SLocal_check_relay
+Scheck_relay
+R$* $: $1 $| $>"Local_check_relay" $1
+R$* $| $* $| $#$* $#$3
+R$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2
+
+SBasic_check_relay
+# check for deferred delivery mode
+R$* $: < ${deliveryMode} > $1
+R< d > $* $@ deferred
+R< $* > $* $: $2
+
+
+
+
+######################################################################
+### check_mail -- check SMTP `MAIL FROM:' command argument
+######################################################################
+
+SLocal_check_mail
+Scheck_mail
+R$* $: $1 $| $>"Local_check_mail" $1
+R$* $| $#$* $#$2
+R$* $| $* $@ $>"Basic_check_mail" $1
+
+SBasic_check_mail
+# check for deferred delivery mode
+R$* $: < ${deliveryMode} > $1
+R< d > $* $@ deferred
+R< $* > $* $: $2
+
+# authenticated?
+R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL
+R$* $| $#$+ $#$2
+R$* $| $* $: $1
+
+R<> $@ <OK> we MUST accept <> (RFC 1123)
+R$+ $: <?> $1
+R<?><$+> $: <@> <$1>
+R<?>$+ $: <@> <$1>
+R$* $: $&{daemon_flags} $| $1
+R$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 >
+R$* u $* $| <@> < $* > $: <?> < $3 >
+R$* $| $* $: $2
+# handle case of @localhost on address
+R<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost >
+R<@> < $* @ [127.0.0.1] >
+ $: < ? $&{client_name} > < $1 @ [127.0.0.1] >
+R<@> < $* @ localhost.$m >
+ $: < ? $&{client_name} > < $1 @ localhost.$m >
+R<@> < $* @ localhost.UUCP >
+ $: < ? $&{client_name} > < $1 @ localhost.UUCP >
+R<@> $* $: $1 no localhost as domain
+R<? $=w> $* $: $2 local client: ok
+R<? $+> <$+> $#error $@ 5.5.4 $: "553 Real domain name required for sender address"
+R<?> $* $: $1
+R$* $: <?> $>CanonAddr $1 canonify sender address and mark it
+R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots
+# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
+R<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 >
+R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
+R<? $* <$->> $* < @ $+ >
+ $: <$2> $3 < @ $4 >
+
+
+# handle case of no @domain on address
+R<?> $* $: $&{daemon_flags} $| <?> $1
+R$* u $* $| <?> $* $: <OKR> $3
+R$* $| $* $: $2
+R<?> $* $: < ? $&{client_name} > $1
+R<?> $* $@ <OK> ...local unqualed ok
+R<? $+> $* $#error $@ 5.5.4 $: "553 Domain name required for sender address " $&f
+ ...remote is not
+# check results
+R<?> $* $: @ $1 mark address: nothing known about it
+R<$={ResOk}> $* $@ <OKR> domain ok: stop
+R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
+R<PERM> $* $#error $@ 5.1.8 $: "553 Domain of sender address " $&f " does not exist"
+
+######################################################################
+### check_rcpt -- check SMTP `RCPT TO:' command argument
+######################################################################
+
+SLocal_check_rcpt
+Scheck_rcpt
+R$* $: $1 $| $>"Local_check_rcpt" $1
+R$* $| $#$* $#$2
+R$* $| $* $@ $>"Basic_check_rcpt" $1
+
+SBasic_check_rcpt
+# empty address?
+R<> $#error $@ nouser $: "553 User address required"
+R$@ $#error $@ nouser $: "553 User address required"
+# check for deferred delivery mode
+R$* $: < ${deliveryMode} > $1
+R< d > $* $@ deferred
+R< $* > $* $: $2
+
+
+######################################################################
+R$* $: $1 $| @ $>"Rcpt_ok" $1
+R$* $| @ $#TEMP $+ $: $1 $| T $2
+R$* $| @ $#$* $#$2
+R$* $| @ RELAY $@ RELAY
+R$* $| @ $* $: O $| $>"Relay_ok" $1
+R$* $| T $+ $: T $2 $| $>"Relay_ok" $1
+R$* $| $#TEMP $+ $#error $2
+R$* $| $#$* $#$2
+R$* $| RELAY $@ RELAY
+R T $+ $| $* $#error $1
+# anything else is bogus
+R$* $#error $@ 5.7.1 $: "550 Relaying denied"
+
+
+######################################################################
+### Rcpt_ok: is the recipient ok?
+######################################################################
+SRcpt_ok
+R$* $: $>ParseRecipient $1 strip relayable hosts
+
+
+
+
+# authenticated via TLS?
+R$* $: $1 $| $>RelayTLS client authenticated?
+R$* $| $# $+ $# $2 error/ok?
+R$* $| $* $: $1 no
+
+R$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type}
+R$* $| $# $* $# $2
+R$* $| NO $: $1
+R$* $| $* $: $1 $| $&{auth_type}
+R$* $| $: $1
+R$* $| $={TrustAuthMech} $# RELAY
+R$* $| $* $: $1
+# anything terminating locally is ok
+R$+ < @ $=w > $@ RELAY
+R$+ < @ $* $=R > $@ RELAY
+
+
+
+# check for local user (i.e. unqualified address)
+R$* $: <?> $1
+R<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 >
+# local user is ok
+R<?> $+ $@ RELAY
+R<$+> $* $: $2
+
+######################################################################
+### Relay_ok: is the relay/sender ok?
+######################################################################
+SRelay_ok
+# anything originating locally is ok
+# check IP address
+R$* $: $&{client_addr}
+R$@ $@ RELAY originated locally
+R0 $@ RELAY originated locally
+R$=R $* $@ RELAY relayable IP address
+R$* $: [ $1 ] put brackets around it...
+R$=w $@ RELAY ... and see if it is local
+
+
+# check client name: first: did it resolve?
+R$* $: < $&{client_resolve} >
+R<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
+R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
+R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
+R$* $: <@> $&{client_name}
+R<@> $@ RELAY
+# pass to name server to make hostname canonical
+R<@> $* $=P $:<?> $1 $2
+R<@> $+ $:<?> $[ $1 $]
+R$* . $1 strip trailing dots
+R<?> $=w $@ RELAY
+R<?> $* $=R $@ RELAY
+
+
+
+
+######################################################################
+### trust_auth: is user trusted to authenticate as someone else?
+###
+### Parameters:
+### $1: AUTH= parameter from MAIL command
+######################################################################
+
+SLocal_trust_auth
+Strust_auth
+R$* $: $&{auth_type} $| $1
+# required by RFC 2554 section 4.
+R$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated"
+R$* $| $&{auth_authen} $@ identical
+R$* $| <$&{auth_authen}> $@ identical
+R$* $| $* $: $1 $| $>"Local_trust_auth" $1
+R$* $| $#$* $#$2
+R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
+
+######################################################################
+### Relay_Auth: allow relaying based on authentication?
+###
+### Parameters:
+### $1: ${auth_type}
+######################################################################
+SLocal_Relay_Auth
+
+
+
+######################################################################
+### tls_client: is connection with client "good" enough?
+### (done in server)
+###
+### Parameters:
+### ${verify} $| (MAIL|STARTTLS)
+######################################################################
+Stls_client
+R$* $| $* $@ $>"TLS_connection" $1
+
+######################################################################
+### tls_server: is connection with server "good" enough?
+### (done in client)
+###
+### Parameter:
+### ${verify}
+######################################################################
+Stls_server
+R$* $@ $>"TLS_connection" $1
+
+######################################################################
+### TLS_connection: is TLS connection "good" enough?
+###
+### Parameters:
+### ${verify}
+### Requirement: RHS from access map, may be ? for none.
+######################################################################
+STLS_connection
+RSOFTWARE $#error $@ 4.7.0 $: "403 TLS handshake."
+
+
+######################################################################
+### RelayTLS: allow relaying based on TLS authentication
+###
+### Parameters:
+### none
+######################################################################
+SRelayTLS
+# authenticated?
+
+######################################################################
+### authinfo: lookup authinfo in the access map
+###
+### Parameters:
+### $1: {server_name}
+### $2: {server_addr}
+######################################################################
+Sauthinfo
+
+
+
+
+SLocal_localaddr
+R$+ $: $>ParseRecipient $1
+R$* < @ $+ > $* $#relay $@ ${MTAHost} $: $1 < @ $2 > $3
+# DECnet
+R$+ :: $+ $#relay $@ ${MTAHost} $: $1 :: $2
+R$* $#relay $@ ${MTAHost} $: $1 < @ $j >
+#
+######################################################################
+######################################################################
+#####
+##### MAIL FILTER DEFINITIONS
+#####
+######################################################################
+######################################################################
+
+#
+######################################################################
+######################################################################
+#####
+##### MAILER DEFINITIONS
+#####
+######################################################################
+######################################################################
+
+
+##################################################
+### Local and Program Mailer specification ###
+##################################################
+
+##### $Id: local.m4,v 8.58 2000/10/26 01:58:29 ca Exp $ #####
+
+#
+# Envelope sender rewriting
+#
+SEnvFromL
+R<@> $n errors to mailer-daemon
+R@ <@ $*> $n temporarily bypass Sun bogosity
+R$+ $: $>AddDomain $1 add local domain if needed
+R$* $: $>MasqEnv $1 do masquerading
+
+#
+# Envelope recipient rewriting
+#
+SEnvToL
+R$+ < @ $* > $: $1 strip host part
+R$+ + $* $: < $&{addr_type} > $1 + $2 mark with addr type
+R<e s> $+ + $* $: $1 remove +detail for sender
+R< $* > $+ $: $2 else remove mark
+
+#
+# Header sender rewriting
+#
+SHdrFromL
+R<@> $n errors to mailer-daemon
+R@ <@ $*> $n temporarily bypass Sun bogosity
+R$+ $: $>AddDomain $1 add local domain if needed
+R$* $: $>MasqHdr $1 do masquerading
+
+#
+# Header recipient rewriting
+#
+SHdrToL
+R$+ $: $>AddDomain $1 add local domain if needed
+R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2
+
+#
+# Common code to add local domain name (only if always-add-domain)
+#
+SAddDomain
+
+Mlocal, P=[IPC], F=lmDFMuXkw5, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+Mprog, P=[IPC], F=lmDFMuXk5, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=$z:/,
+ T=X-Unix/X-Unix/X-Unix,
+ A=TCP $h
+
+#####################################
+### SMTP Mailer specification ###
+#####################################
+
+##### $Id: smtp.m4,v 8.64 2001/04/03 01:52:54 gshapiro Exp $ #####
+
+#
+# common sender and masquerading recipient rewriting
+#
+SMasqSMTP
+R$* < @ $* > $* $@ $1 < @ $2 > $3 already fully qualified
+R$+ $@ $1 < @ *LOCAL* > add local qualification
+
+#
+# convert pseudo-domain addresses to real domain addresses
+#
+SPseudoToReal
+
+# pass <route-addr>s through
+R< @ $+ > $* $@ < @ $1 > $2 resolve <route-addr>
+
+# output fake domains as user%fake@relay
+
+# do UUCP heuristics; note that these are shared with UUCP mailers
+R$+ < @ $+ .UUCP. > $: < $2 ! > $1 convert to UUCP form
+R$+ < @ $* > $* $@ $1 < @ $2 > $3 not UUCP form
+
+# leave these in .UUCP form to avoid further tampering
+R< $&h ! > $- ! $+ $@ $2 < @ $1 .UUCP. >
+R< $&h ! > $-.$+ ! $+ $@ $3 < @ $1.$2 >
+R< $&h ! > $+ $@ $1 < @ $&h .UUCP. >
+R< $+ ! > $+ $: $1 ! $2 < @ $Y > use UUCP_RELAY
+R$+ < @ $~[ $* : $+ > $@ $1 < @ $4 > strip mailer: part
+R$+ < @ > $: $1 < @ *LOCAL* > if no UUCP_RELAY
+
+
+#
+# envelope sender rewriting
+#
+SEnvFromSMTP
+R$+ $: $>PseudoToReal $1 sender/recipient common
+R$* :; <@> $@ list:; special case
+R$* $: $>MasqSMTP $1 qualify unqual'ed names
+R$+ $: $>MasqEnv $1 do masquerading
+
+
+#
+# envelope recipient rewriting --
+# also header recipient if not masquerading recipients
+#
+SEnvToSMTP
+R$+ $: $>PseudoToReal $1 sender/recipient common
+R$+ $: $>MasqSMTP $1 qualify unqual'ed names
+R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2
+
+#
+# header sender and masquerading header recipient rewriting
+#
+SHdrFromSMTP
+R$+ $: $>PseudoToReal $1 sender/recipient common
+R:; <@> $@ list:; special case
+
+# do special header rewriting
+R$* <@> $* $@ $1 <@> $2 pass null host through
+R< @ $* > $* $@ < @ $1 > $2 pass route-addr through
+R$* $: $>MasqSMTP $1 qualify unqual'ed names
+R$+ $: $>MasqHdr $1 do masquerading
+
+
+#
+# relay mailer header masquerading recipient rewriting
+#
+SMasqRelay
+R$+ $: $>MasqSMTP $1
+R$+ $: $>MasqHdr $1
+
+Msmtp, P=[IPC], F=mDFMuXk05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+Mesmtp, P=[IPC], F=mDFMuXak05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+Msmtp8, P=[IPC], F=mDFMuX8k05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+Mdsmtp, P=[IPC], F=mDFMuXa%k05, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+Mrelay, P=[IPC], F=mDFMuXa8k0, S=EnvFromSMTP/HdrFromSMTP, R=MasqSMTP, E=\r\n, L=2040,
+ T=DNS/RFC822/SMTP,
+ A=TCP $h
+
diff --git a/contrib/sendmail/cf/cf/submit.mc b/contrib/sendmail/cf/cf/submit.mc
new file mode 100644
index 0000000..f27dc1c
--- /dev/null
+++ b/contrib/sendmail/cf/cf/submit.mc
@@ -0,0 +1,22 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+#
+# This is the prototype file for a set-group-ID sm-msp sendmail that
+# acts as a initial mail submission program.
+#
+
+divert(0)dnl
+VERSIONID(`$Id: submit.mc,v 8.5 2001/09/08 01:20:53 gshapiro Exp $')
+define(`confCF_VERSION', `Submit')dnl
+define(`__OSTYPE__',`')dnl dirty hack to keep proto.m4 from complaining
+define(`_USE_DECNET_SYNTAX_', `1')dnl support DECnet
+FEATURE(`msp')dnl
diff --git a/contrib/sendmail/cf/cf/tcpproto.mc b/contrib/sendmail/cf/cf/tcpproto.mc
index de90c52..969cb71 100644
--- a/contrib/sendmail/cf/cf/tcpproto.mc
+++ b/contrib/sendmail/cf/cf/tcpproto.mc
@@ -26,7 +26,7 @@ divert(-1)
#
divert(0)dnl
-VERSIONID(`$Id: tcpproto.mc,v 8.13.22.1 2000/08/03 15:25:20 ca Exp $')
+VERSIONID(`$Id: tcpproto.mc,v 8.14 2000/08/03 15:26:50 ca Exp $')
OSTYPE(`unknown')
FEATURE(`nouucp', `reject')
MAILER(`local')
diff --git a/contrib/sendmail/cf/feature/access_db.m4 b/contrib/sendmail/cf/feature/access_db.m4
index 14a8fe8..256b281 100644
--- a/contrib/sendmail/cf/feature/access_db.m4
+++ b/contrib/sendmail/cf/feature/access_db.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,14 +10,28 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: access_db.m4,v 8.15 1999/07/22 17:55:34 gshapiro Exp $')
+VERSIONID(`$Id: access_db.m4,v 8.23 2001/03/16 00:51:25 gshapiro Exp $')
divert(-1)
define(`_ACCESS_TABLE_', `')
define(`_TAG_DELIM_', `:')dnl should be in OperatorChars
+ifelse(lower(_ARG2_),`skip',`define(`_ACCESS_SKIP_', `1')')
+ifelse(lower(_ARG2_),`lookupdotdomain',`define(`_LOOKUPDOTDOMAIN_', `1')')
+ifelse(lower(_ARG3_),`skip',`define(`_ACCESS_SKIP_', `1')')
+ifelse(lower(_ARG3_),`lookupdotdomain',`define(`_LOOKUPDOTDOMAIN_', `1')')
+define(`_ATMPF_', `<TMPF>')dnl
+dnl check whether arg contains -T`'_ATMPF_
+ifelse(defn(`_ARG_'), `', `',
+ defn(`_ARG_'), `LDAP', `',
+ `ifelse(index(_ARG_, _ATMPF_), `-1',
+ `errprint(`*** WARNING: missing -T'_ATMPF_` in argument of FEATURE(`access_db',' defn(`_ARG_')`)
+')
+ define(`_ABP_', index(_ARG_, ` '))
+ define(`_NARG_', `substr(_ARG_, 0, _ABP_) -T'_ATMPF_` substr(_ARG_, _ABP_)')
+')')
LOCAL_CONFIG
# Access list database (for spam stomping)
-Kaccess ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`access',
- `_ARG_')
+Kaccess ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE -T`'_ATMPF_ MAIL_SETTINGS_DIR`access',
+ defn(`_ARG_'), `LDAP', `ldap -T`'_ATMPF_ -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=access)(sendmailMTAKey=%0))',
+ defn(`_NARG_'), `', `_ARG_', `_NARG_')
diff --git a/contrib/sendmail/cf/feature/allmasquerade.m4 b/contrib/sendmail/cf/feature/allmasquerade.m4
index bbb8660..aa264f9 100644
--- a/contrib/sendmail/cf/feature/allmasquerade.m4
+++ b/contrib/sendmail/cf/feature/allmasquerade.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,7 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: allmasquerade.m4,v 8.11 1999/08/06 01:28:26 gshapiro Exp $')
+VERSIONID(`$Id: allmasquerade.m4,v 8.13 2000/09/12 22:00:53 ca Exp $')
divert(-1)
+ifdef(`_MAILER_local_',
+ `errprint(`*** MAILER(`local') must appear after FEATURE(`allmasquerade')')
+')dnl
+ifdef(`_MAILER_uucp_',
+ `errprint(`*** MAILER(`uucp') must appear after FEATURE(`allmasquerade')')
+')dnl
define(`_ALL_MASQUERADE_', 1)
diff --git a/contrib/sendmail/cf/feature/always_add_domain.m4 b/contrib/sendmail/cf/feature/always_add_domain.m4
index 3ea174b..a29956a 100644
--- a/contrib/sendmail/cf/feature/always_add_domain.m4
+++ b/contrib/sendmail/cf/feature/always_add_domain.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,7 +13,10 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: always_add_domain.m4,v 8.9 1999/02/07 07:26:08 gshapiro Exp $')
+VERSIONID(`$Id: always_add_domain.m4,v 8.11 2000/09/12 22:00:53 ca Exp $')
divert(-1)
-define(`_ALWAYS_ADD_DOMAIN_', 1)
+ifdef(`_MAILER_local_',
+ `errprint(`*** MAILER(`local') must appear after FEATURE(`always_add_domain')')
+')dnl
+define(`_ALWAYS_ADD_DOMAIN_', ifelse(len(X`'_ARG_),`1',`',_ARG_))
diff --git a/contrib/sendmail/cf/feature/authinfo.m4 b/contrib/sendmail/cf/feature/authinfo.m4
new file mode 100644
index 0000000..3533d30
--- /dev/null
+++ b/contrib/sendmail/cf/feature/authinfo.m4
@@ -0,0 +1,22 @@
+divert(-1)
+#
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: authinfo.m4,v 1.7 2001/03/16 00:51:25 gshapiro Exp $')
+divert(-1)
+
+define(`_AUTHINFO_TABLE_', `')
+
+LOCAL_CONFIG
+# authinfo list database: contains info for authentication as client
+Kauthinfo ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`authinfo',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=authinfo)(sendmailMTAKey=%0))',
+ `_ARG_')
diff --git a/contrib/sendmail/cf/feature/bestmx_is_local.m4 b/contrib/sendmail/cf/feature/bestmx_is_local.m4
index 22c8723..911d2b5 100644
--- a/contrib/sendmail/cf/feature/bestmx_is_local.m4
+++ b/contrib/sendmail/cf/feature/bestmx_is_local.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,10 +13,10 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: bestmx_is_local.m4,v 8.24 1999/10/18 21:50:24 ca Exp $')
+VERSIONID(`$Id: bestmx_is_local.m4,v 8.26 2000/09/17 17:30:00 gshapiro Exp $')
divert(-1)
-define(_BESTMX_IS_LOCAL_, _ARG_)
+define(`_BESTMX_IS_LOCAL_', _ARG_)
LOCAL_CONFIG
# turn on bestMX lookup table
diff --git a/contrib/sendmail/cf/feature/bitdomain.m4 b/contrib/sendmail/cf/feature/bitdomain.m4
index 7ac7304..3232be8 100644
--- a/contrib/sendmail/cf/feature/bitdomain.m4
+++ b/contrib/sendmail/cf/feature/bitdomain.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: bitdomain.m4,v 8.23 1999/07/22 17:55:34 gshapiro Exp $')
+VERSIONID(`$Id: bitdomain.m4,v 8.28 2001/03/16 00:51:25 gshapiro Exp $')
divert(-1)
define(`_BITDOMAIN_TABLE_', `')
LOCAL_CONFIG
# BITNET mapping table
-Kbitdomain ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`bitdomain',
+Kbitdomain ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`bitdomain',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=bitdomain)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/feature/compat_check.m4 b/contrib/sendmail/cf/feature/compat_check.m4
new file mode 100644
index 0000000..9f1fe93
--- /dev/null
+++ b/contrib/sendmail/cf/feature/compat_check.m4
@@ -0,0 +1,33 @@
+divert(-1)
+#
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+divert(0)
+VERSIONID(`$Id: compat_check.m4,v 1.3 2001/11/21 18:40:06 ca Exp $')
+divert(-1)
+ifdef(`_ACCESS_TABLE_', `',
+`errprint(`FEATURE(`compat_check') requires FEATURE(`access_db')
+')')
+
+LOCAL_RULESETS
+Scheck_compat
+# look up the pair of addresses
+# (we use <@> as the separator. Note this in the map too!)
+R< $+ > $| $+ $: $1 $| $2
+R$+ $| < $+ > $: $1 $| $2
+R$+ $| $+ $: <$(access Compat:$1<@>$2 $:OK $)>
+R$* $| $* $@ ok
+# act on the result,
+# it must be one of the following... anything else will be allowed..
+dnl for consistency with the other two even though discard does not take an
+dnl reply code
+R< DISCARD:$* > $#discard $: $1 " - discarded by check_compat"
+R< DISCARD $* > $#discard $: $1 " - discarded by check_compat"
+R< TEMP:$* > $#error $@ TEMPFAIL $: $1 " error from check_compat. Try again later"
+R< ERROR:$* > $#error $@ UNAVAILABLE $: $1 " error from check_compat"
diff --git a/contrib/sendmail/cf/feature/delay_checks.m4 b/contrib/sendmail/cf/feature/delay_checks.m4
index 1592525..151df95 100644
--- a/contrib/sendmail/cf/feature/delay_checks.m4
+++ b/contrib/sendmail/cf/feature/delay_checks.m4
@@ -10,7 +10,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: delay_checks.m4,v 8.7 2000/02/26 01:32:02 gshapiro Exp $')
+VERSIONID(`$Id: delay_checks.m4,v 8.8 2000/12/05 18:50:45 ca Exp $')
divert(-1)
define(`_DELAY_CHECKS_', 1)
@@ -20,3 +20,6 @@ ifelse(defn(`_ARG_'), `', `',
`errprint(`*** ERROR: illegal argument _ARG_ for FEATURE(delay_checks)
')
')
+
+dnl be backward compatible by default
+ifelse(len(X`'_ARG2_), `1', `define(`_DELAY_COMPAT_8_10_', 1)', `')
diff --git a/contrib/sendmail/cf/feature/dnsbl.m4 b/contrib/sendmail/cf/feature/dnsbl.m4
index e5fd489..8cfb98e 100644
--- a/contrib/sendmail/cf/feature/dnsbl.m4
+++ b/contrib/sendmail/cf/feature/dnsbl.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -11,15 +11,22 @@ divert(-1)
divert(0)
ifdef(`_DNSBL_R_',`dnl',`dnl
-VERSIONID(`$Id: dnsbl.m4,v 8.18.16.1 2000/11/22 01:13:21 ca Exp $')')
+VERSIONID(`$Id: dnsbl.m4,v 8.26 2001/11/12 16:04:14 ca Exp $')
+define(`_DNSBL_R_',`')
+LOCAL_CONFIG
+# map for DNS based blacklist lookups
+Kdnsbl host -T<TMP>ifdef(`DNSBL_MAP_OPT',` DNSBL_MAP_OPT')')
divert(-1)
define(`_DNSBL_SRV_', `ifelse(len(X`'_ARG_),`1',`blackholes.mail-abuse.org',_ARG_)')dnl
define(`_DNSBL_MSG_', `ifelse(len(X`'_ARG2_),`1',`"550 Mail from " $`'&{client_addr} " refused by blackhole site '_DNSBL_SRV_`"',`_ARG2_')')dnl
+define(`_DNSBL_MSG_TMP_', `ifelse(_ARG3_,`t',`"451 Temporary lookup failure of " $`'&{client_addr} " at '_DNSBL_SRV_`"',`_ARG3_')')dnl
divert(8)
# DNS based IP address spam list _DNSBL_SRV_
R$* $: $&{client_addr}
-R::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._DNSBL_SRV_. $: OK $)
-R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._DNSBL_SRV_. $: OK $)
+R$-.$-.$-.$- $: <?> $(dnsbl $4.$3.$2.$1._DNSBL_SRV_. $: OK $)
R<?>OK $: OKSOFAR
+ifelse(len(X`'_ARG3_),`1',
+`R<?>$+<TMP> $: TMPOK',
+`R<?>$+<TMP> $#error $@ 4.7.1 $: _DNSBL_MSG_TMP_')
R<?>$+ $#error $@ 5.7.1 $: _DNSBL_MSG_
divert(-1)
diff --git a/contrib/sendmail/cf/feature/domaintable.m4 b/contrib/sendmail/cf/feature/domaintable.m4
index b609ec9..b04b497 100644
--- a/contrib/sendmail/cf/feature/domaintable.m4
+++ b/contrib/sendmail/cf/feature/domaintable.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: domaintable.m4,v 8.17 1999/07/22 17:55:35 gshapiro Exp $')
+VERSIONID(`$Id: domaintable.m4,v 8.22 2001/03/16 00:51:25 gshapiro Exp $')
divert(-1)
define(`_DOMAIN_TABLE_', `')
LOCAL_CONFIG
# Domain table (adding domains)
-Kdomaintable ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`domaintable',
+Kdomaintable ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`domaintable',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=domain)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/feature/enhdnsbl.m4 b/contrib/sendmail/cf/feature/enhdnsbl.m4
new file mode 100644
index 0000000..e254ad4
--- /dev/null
+++ b/contrib/sendmail/cf/feature/enhdnsbl.m4
@@ -0,0 +1,44 @@
+divert(-1)
+#
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+ifdef(`_EDNSBL_R_',`dnl',`dnl
+VERSIONID(`$Id: enhdnsbl.m4,v 1.7 2001/07/22 18:02:52 ca Exp $')
+LOCAL_CONFIG
+define(`_EDNSBL_R_',`')dnl
+# map for enhanced DNS based blacklist lookups
+Kednsbl dns -R A -a. -T<TMP> -r`'ifdef(`EDNSBL_TO',`EDNSBL_TO',`5')
+')
+divert(-1)
+define(`_EDNSBL_SRV_', `ifelse(len(X`'_ARG_),`1',`blackholes.mail-abuse.org',_ARG_)')dnl
+define(`_EDNSBL_MSG_', `ifelse(len(X`'_ARG2_),`1',`"550 Mail from " $`'&{client_addr} " refused by blackhole site '_EDNSBL_SRV_`"',`_ARG2_')')dnl
+define(`_EDNSBL_MSG_TMP_', `ifelse(_ARG3_,`t',`"451 Temporary lookup failure of " $`'&{client_addr} " at '_EDNSBL_SRV_`"',`_ARG3_')')dnl
+define(`_EDNSBL_MATCH_', `ifelse(len(X`'_ARG4_),`1',`$`'+',_ARG4_)')dnl
+divert(8)
+# DNS based IP address spam list _EDNSBL_SRV_
+R$* $: $&{client_addr}
+R$-.$-.$-.$- $: <?> $(ednsbl $4.$3.$2.$1._EDNSBL_SRV_. $: OK $)
+R<?>OK $: OKSOFAR
+ifelse(len(X`'_ARG3_),`1',
+`R<?>$+<TMP> $: TMPOK',
+`R<?>$+<TMP> $#error $@ 4.7.1 $: _EDNSBL_MSG_TMP_')
+R<?>_EDNSBL_MATCH_ $#error $@ 5.7.1 $: _EDNSBL_MSG_
+ifelse(len(X`'_ARG5_),`1',`dnl',
+`R<?>_ARG5_ $#error $@ 5.7.1 $: _EDNSBL_MSG_')
+ifelse(len(X`'_ARG6_),`1',`dnl',
+`R<?>_ARG6_ $#error $@ 5.7.1 $: _EDNSBL_MSG_')
+ifelse(len(X`'_ARG7_),`1',`dnl',
+`R<?>_ARG7_ $#error $@ 5.7.1 $: _EDNSBL_MSG_')
+ifelse(len(X`'_ARG8_),`1',`dnl',
+`R<?>_ARG8_ $#error $@ 5.7.1 $: _EDNSBL_MSG_')
+ifelse(len(X`'_ARG9_),`1',`dnl',
+`R<?>_ARG9_ $#error $@ 5.7.1 $: _EDNSBL_MSG_')
+divert(-1)
diff --git a/contrib/sendmail/cf/feature/genericstable.m4 b/contrib/sendmail/cf/feature/genericstable.m4
index 9104948..c20022a 100644
--- a/contrib/sendmail/cf/feature/genericstable.m4
+++ b/contrib/sendmail/cf/feature/genericstable.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: genericstable.m4,v 8.16 1999/07/22 17:55:35 gshapiro Exp $')
+VERSIONID(`$Id: genericstable.m4,v 8.21 2001/03/16 00:51:26 gshapiro Exp $')
divert(-1)
define(`_GENERICS_TABLE_', `')
LOCAL_CONFIG
# Generics table (mapping outgoing addresses)
-Kgenerics ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`genericstable',
+Kgenerics ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`genericstable',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=generics)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/feature/ldap_routing.m4 b/contrib/sendmail/cf/feature/ldap_routing.m4
index 7ea0c86..e856da5 100644
--- a/contrib/sendmail/cf/feature/ldap_routing.m4
+++ b/contrib/sendmail/cf/feature/ldap_routing.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,7 +10,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: ldap_routing.m4,v 8.5.4.1 2000/07/15 18:05:05 gshapiro Exp $')
+VERSIONID(`$Id: ldap_routing.m4,v 8.8 2001/06/27 21:46:31 gshapiro Exp $')
divert(-1)
# Check first two arguments. If they aren't set, may need to warn in proto.m4
@@ -23,6 +23,11 @@ ifelse(len(X`'_ARG3_), `1', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
_ARG3_, `passthru', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
`define(`_LDAP_ROUTING_', `_MUST_EXIST_')')
+# Check for fouth argument to indicate how to deal with +detail info
+ifelse(len(X`'_ARG4_), `1', `',
+ _ARG4_, `strip', `define(`_LDAP_ROUTE_DETAIL_', `_STRIP_')',
+ _ARG4_, `preserve', `define(`_LDAP_ROUTE_DETAIL_', `_PRESERVE_')')
+
LOCAL_CONFIG
# LDAP routing maps
Kldapmh ifelse(len(X`'_ARG1_), `1',
diff --git a/contrib/sendmail/cf/feature/local_lmtp.m4 b/contrib/sendmail/cf/feature/local_lmtp.m4
index 4b44eab..f3c371b 100644
--- a/contrib/sendmail/cf/feature/local_lmtp.m4
+++ b/contrib/sendmail/cf/feature/local_lmtp.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,7 +10,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: local_lmtp.m4,v 8.15 1999/11/18 05:06:22 ca Exp $')
+VERSIONID(`$Id: local_lmtp.m4,v 8.16 2000/08/18 18:58:45 ca Exp $')
divert(-1)
ifdef(`_MAILER_local_',
@@ -24,3 +24,4 @@ define(`LOCAL_MAILER_PATH',
define(`LOCAL_MAILER_FLAGS', `PSXfmnz9')
define(`LOCAL_MAILER_ARGS', `mail.local -l')
define(`LOCAL_MAILER_DSN_DIAGNOSTIC_CODE', `SMTP')
+define(`_LOCAL_LMTP_', `1')
diff --git a/contrib/sendmail/cf/feature/local_no_masquerade.m4 b/contrib/sendmail/cf/feature/local_no_masquerade.m4
new file mode 100644
index 0000000..de2300f
--- /dev/null
+++ b/contrib/sendmail/cf/feature/local_no_masquerade.m4
@@ -0,0 +1,18 @@
+divert(-1)
+#
+# Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+
+divert(0)
+VERSIONID(`$Id: local_no_masquerade.m4,v 1.2 2000/08/03 15:54:59 ca Exp $')
+divert(-1)
+
+ifdef(`_MAILER_local_',
+ `errprint(`*** MAILER(`local') must appear after FEATURE(`local_no_masquerade')')
+')dnl
+define(`_LOCAL_NO_MASQUERADE_', `1')
diff --git a/contrib/sendmail/cf/feature/lookupdotdomain.m4 b/contrib/sendmail/cf/feature/lookupdotdomain.m4
new file mode 100644
index 0000000..f8c2a31
--- /dev/null
+++ b/contrib/sendmail/cf/feature/lookupdotdomain.m4
@@ -0,0 +1,22 @@
+divert(-1)
+#
+# Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: lookupdotdomain.m4,v 1.1 2000/04/13 22:32:49 ca Exp $')
+divert(-1)
+
+ifdef(`_ACCESS_TABLE_',
+ `define(`_LOOKUPDOTDOMAIN_')',
+ `errprint(`*** ERROR: FEATURE(`lookupdotdomain') requires FEATURE(`access_db')
+')')
+ifdef(`_RELAY_HOSTS_ONLY_',
+ `errprint(`*** WARNING: FEATURE(`lookupdotdomain') does not work well with FEATURE(`relay_hosts_only')
+')')
diff --git a/contrib/sendmail/cf/feature/mailertable.m4 b/contrib/sendmail/cf/feature/mailertable.m4
index 08c1bf6..e4dcd70 100644
--- a/contrib/sendmail/cf/feature/mailertable.m4
+++ b/contrib/sendmail/cf/feature/mailertable.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: mailertable.m4,v 8.18 1999/07/22 17:55:35 gshapiro Exp $')
+VERSIONID(`$Id: mailertable.m4,v 8.23 2001/03/16 00:51:26 gshapiro Exp $')
divert(-1)
define(`_MAILER_TABLE_', `')
LOCAL_CONFIG
# Mailer table (overriding domains)
-Kmailertable ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`mailertable',
+Kmailertable ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`mailertable',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=mailer)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/feature/msp.m4 b/contrib/sendmail/cf/feature/msp.m4
new file mode 100644
index 0000000..fa68e0f
--- /dev/null
+++ b/contrib/sendmail/cf/feature/msp.m4
@@ -0,0 +1,76 @@
+divert(-1)
+#
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)dnl
+VERSIONID(`$Id: msp.m4,v 1.29 2001/12/13 23:56:38 gshapiro Exp $')
+divert(-1)
+define(`ALIAS_FILE', `')
+define(`confDELIVERY_MODE', `i')
+define(`confUSE_MSP', `True')
+define(`confFORWARD_PATH', `')
+define(`confPRIVACY_FLAGS', `goaway,noetrn,restrictqrun')
+define(`confDONT_PROBE_INTERFACES', `True')
+dnl ---------------------------------------------
+dnl run as this user (even if called by root)
+ifdef(`confRUN_AS_USER',,`define(`confRUN_AS_USER', `smmsp')')
+ifdef(`confTRUSTED_USER',,`define(`confTRUSTED_USER', confRUN_AS_USER)')
+dnl ---------------------------------------------
+dnl This queue directory must have the same group
+dnl as sendmail and it must be group-writable.
+dnl notice: do not test for QUEUE_DIR, it is set in some ostype/*.m4 files
+ifdef(`MSP_QUEUE_DIR',
+`define(`QUEUE_DIR', `MSP_QUEUE_DIR')',
+`define(`QUEUE_DIR', `/var/spool/clientmqueue')')
+define(`_MTA_HOST_', ifelse(defn(`_ARG_'), `', `localhost', `_ARG_'))
+define(`_MSP_FQHN_',`dnl used to qualify addresses
+ifdef(`MASQUERADE_NAME', ifdef(`_MASQUERADE_ENVELOPE_', `$M', `$j'), `$j')')
+define(`RELAY_MAILER_ARGS', `TCP $h'ifelse(_ARG2_, `MSA', ` 587'))
+dnl ---------------------------------------------
+ifdef(`confPID_FILE', `dnl',
+`define(`confPID_FILE', QUEUE_DIR`/sm-client.pid')')
+define(`confQUEUE_FILE_MODE', `0660')dnl
+ifdef(`STATUS_FILE',
+`define(`_F_',
+`define(`_b_', index(STATUS_FILE, `sendmail.st'))ifelse(_b_, `-1', `STATUS_FILE', `substr(STATUS_FILE, 0, _b_)sm-client.st')')
+define(`STATUS_FILE', _F_)
+undefine(`_b_') undefine(`_F_')',
+`define(`STATUS_FILE', QUEUE_DIR`/sm-client.st')')
+FEATURE(`no_default_msa')dnl
+ifelse(defn(`_DPO_'), `',
+`DAEMON_OPTIONS(`Name=NoMTA, Addr=127.0.0.1, M=E')dnl')
+define(`_DEF_LOCAL_MAILER_FLAGS', `')dnl
+define(`_DEF_LOCAL_SHELL_FLAGS', `')dnl
+define(`LOCAL_MAILER_PATH', `[IPC]')dnl
+define(`LOCAL_MAILER_FLAGS', `lmDFMuXkw5')dnl
+define(`LOCAL_MAILER_ARGS', `TCP $h')dnl
+define(`LOCAL_MAILER_DSN_DIAGNOSTIC_CODE', `SMTP')dnl
+define(`LOCAL_SHELL_PATH', `[IPC]')dnl
+define(`LOCAL_SHELL_FLAGS', `lmDFMuXk5')dnl
+define(`LOCAL_SHELL_ARGS', `TCP $h')dnl
+MODIFY_MAILER_FLAGS(`SMTP', `+k05')dnl
+MODIFY_MAILER_FLAGS(`ESMTP', `+k05')dnl
+MODIFY_MAILER_FLAGS(`DSMTP', `+k05')dnl
+MODIFY_MAILER_FLAGS(`SMTP8', `+k05')dnl
+MODIFY_MAILER_FLAGS(`RELAY', `+k0')dnl
+MAILER(`local')dnl
+MAILER(`smtp')dnl
+
+LOCAL_CONFIG
+D{MTAHost}_MTA_HOST_
+
+LOCAL_RULESETS
+SLocal_localaddr
+R$+ $: $>ParseRecipient $1
+R$* < @ $+ > $* $#relay $@ ${MTAHost} $: $1 < @ $2 > $3
+ifdef(`_USE_DECNET_SYNTAX_',
+`# DECnet
+R$+ :: $+ $#relay $@ ${MTAHost} $: $1 :: $2', `dnl')
+R$* $#relay $@ ${MTAHost} $: $1 < @ _MSP_FQHN_ >
diff --git a/contrib/sendmail/cf/feature/no_default_msa.m4 b/contrib/sendmail/cf/feature/no_default_msa.m4
index 0450cde..5a05339 100644
--- a/contrib/sendmail/cf/feature/no_default_msa.m4
+++ b/contrib/sendmail/cf/feature/no_default_msa.m4
@@ -10,7 +10,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: no_default_msa.m4,v 8.1.10.1 2000/09/17 17:04:22 gshapiro Exp $')
+VERSIONID(`$Id: no_default_msa.m4,v 8.2 2001/02/14 05:03:22 gshapiro Exp $')
divert(-1)
define(`_NO_MSA_', `1')
diff --git a/contrib/sendmail/cf/feature/nullclient.m4 b/contrib/sendmail/cf/feature/nullclient.m4
index fe3767c..8f35ca1 100644
--- a/contrib/sendmail/cf/feature/nullclient.m4
+++ b/contrib/sendmail/cf/feature/nullclient.m4
@@ -22,7 +22,7 @@ ifelse(defn(`_ARG_'), `', `errprint(`Feature "nullclient" requires argument')',
#
divert(0)
-VERSIONID(`$Id: nullclient.m4,v 8.21.16.3 2000/09/17 17:04:22 gshapiro Exp $')
+VERSIONID(`$Id: nullclient.m4,v 8.24 2000/09/17 17:30:00 gshapiro Exp $')
divert(-1)
undefine(`ALIAS_FILE')
diff --git a/contrib/sendmail/cf/feature/preserve_local_plus_detail.m4 b/contrib/sendmail/cf/feature/preserve_local_plus_detail.m4
new file mode 100644
index 0000000..bb603a6
--- /dev/null
+++ b/contrib/sendmail/cf/feature/preserve_local_plus_detail.m4
@@ -0,0 +1,16 @@
+divert(-1)
+#
+# Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: preserve_local_plus_detail.m4,v 8.1 2000/04/10 05:48:05 gshapiro Exp $')
+divert(-1)
+
+define(`_PRESERVE_LOCAL_PLUS_DETAIL_', `1')
diff --git a/contrib/sendmail/cf/feature/preserve_luser_host.m4 b/contrib/sendmail/cf/feature/preserve_luser_host.m4
new file mode 100644
index 0000000..b6050d1
--- /dev/null
+++ b/contrib/sendmail/cf/feature/preserve_luser_host.m4
@@ -0,0 +1,19 @@
+divert(-1)
+#
+# Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: preserve_luser_host.m4,v 1.2 2000/11/10 18:50:30 ca Exp $')
+divert(-1)
+
+ifdef(`LUSER_RELAY', `',
+`errprint(`*** LUSER_RELAY should be defined before FEATURE(`preserve_luser_host')
+ ')')
+define(`_PRESERVE_LUSER_HOST_', `1')
diff --git a/contrib/sendmail/cf/feature/promiscuous_relay.m4 b/contrib/sendmail/cf/feature/promiscuous_relay.m4
index 86db75f..17cb7d1 100644
--- a/contrib/sendmail/cf/feature/promiscuous_relay.m4
+++ b/contrib/sendmail/cf/feature/promiscuous_relay.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,7 +10,10 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: promiscuous_relay.m4,v 8.10 1999/02/07 07:26:11 gshapiro Exp $')
+VERSIONID(`$Id: promiscuous_relay.m4,v 8.12 2001/02/06 17:14:35 ca Exp $')
divert(-1)
define(`_PROMISCUOUS_RELAY_', 1)
+errprint(`*** WARNING: FEATURE(`promiscuous_relay') configures your system as open
+ relay. Do NOT use it on a server that is connected to the Internet!
+')
diff --git a/contrib/sendmail/cf/feature/queuegroup.m4 b/contrib/sendmail/cf/feature/queuegroup.m4
new file mode 100644
index 0000000..06715a0
--- /dev/null
+++ b/contrib/sendmail/cf/feature/queuegroup.m4
@@ -0,0 +1,27 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: queuegroup.m4,v 1.4 2001/03/28 00:39:39 ca Exp $')
+divert(-1)
+
+ifdef(`_ACCESS_TABLE_', `',
+ `errprint(`*** ERROR: FEATURE(`queuegroup') requires FEATURE(`access_db')
+')')
+
+LOCAL_RULESETS
+Squeuegroup
+R< $+ > $1
+R $+ @ $+ $: $>SearchList <! qgrp> $| <F:$1@$2> <D:$2> <>
+ifelse(len(X`'_ARG_),`1',
+`R<?> $@',
+`R<?> $# _ARG_')
+R<$+> $# $1
diff --git a/contrib/sendmail/cf/feature/relay_local_from.m4 b/contrib/sendmail/cf/feature/relay_local_from.m4
index 6e1aa80..9858eb8 100644
--- a/contrib/sendmail/cf/feature/relay_local_from.m4
+++ b/contrib/sendmail/cf/feature/relay_local_from.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,7 +10,11 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: relay_local_from.m4,v 8.5 1999/02/07 07:26:12 gshapiro Exp $')
+VERSIONID(`$Id: relay_local_from.m4,v 8.6 2001/02/06 15:55:21 ca Exp $')
divert(-1)
define(`_RELAY_LOCAL_FROM_', 1)
+errprint(`*** WARNING: FEATURE(`relay_local_from') may cause your system to act as open
+ relay. Use SMTP AUTH or STARTTLS instead. If you cannot use those,
+ try FEATURE(`relay_mail_from').
+')
diff --git a/contrib/sendmail/cf/feature/relay_mail_from.m4 b/contrib/sendmail/cf/feature/relay_mail_from.m4
index f66408d..44bcbd6 100644
--- a/contrib/sendmail/cf/feature/relay_mail_from.m4
+++ b/contrib/sendmail/cf/feature/relay_mail_from.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -10,11 +10,14 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: relay_mail_from.m4,v 8.2 1999/04/02 02:25:13 gshapiro Exp $')
+VERSIONID(`$Id: relay_mail_from.m4,v 8.3 2001/02/06 16:07:12 ca Exp $')
divert(-1)
ifdef(`_ACCESS_TABLE_',
`define(`_RELAY_DB_FROM_', 1)
ifelse(_ARG_,`domain',`define(`_RELAY_DB_FROM_DOMAIN_', 1)')',
- `errprint(`*** ERROR: FEATURE(relay_mail_from) requires FEATURE(access_db)
+ `errprint(`*** ERROR: FEATURE(`relay_mail_from') requires FEATURE(`access_db')
')')
+errprint(`*** WARNING: FEATURE(`relay_mail_from') may cause your system to act as open
+ relay. Use SMTP AUTH or STARTTLS instead.
+')
diff --git a/contrib/sendmail/cf/feature/use_ct_file.m4 b/contrib/sendmail/cf/feature/use_ct_file.m4
index e87ca62..9e372ec 100644
--- a/contrib/sendmail/cf/feature/use_ct_file.m4
+++ b/contrib/sendmail/cf/feature/use_ct_file.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,12 +13,11 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: use_ct_file.m4,v 8.9 1999/02/07 07:26:13 gshapiro Exp $')
+VERSIONID(`$Id: use_ct_file.m4,v 8.11 2001/08/26 20:58:57 gshapiro Exp $')
divert(-1)
-# if defined, the sendmail.cf will read the /etc/sendmail.ct file
-# to find the names of trusted users. There should only be a few
-# of these, and normally this is done directly in the .cf file.
+# if defined, the sendmail.cf will read the /etc/mail/trusted-users file to
+# find the names of trusted users. There should only be a few of these.
define(`_USE_CT_FILE_', `')
diff --git a/contrib/sendmail/cf/feature/use_cw_file.m4 b/contrib/sendmail/cf/feature/use_cw_file.m4
index c7e1cee..7058cab 100644
--- a/contrib/sendmail/cf/feature/use_cw_file.m4
+++ b/contrib/sendmail/cf/feature/use_cw_file.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,12 +13,12 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: use_cw_file.m4,v 8.9 1999/02/07 07:26:13 gshapiro Exp $')
+VERSIONID(`$Id: use_cw_file.m4,v 8.11 2001/08/26 20:58:57 gshapiro Exp $')
divert(-1)
-# if defined, the sendmail.cf will read the /etc/sendmail.cw file
-# to find alternate names for this host. Typically only used when
-# several hosts have been squashed into one another at high speed.
+# if defined, the sendmail.cf will read the /etc/mail/local-host-names file
+# to find alternate names for this host. Typically only used when several
+# hosts have been squashed into one another at high speed.
define(`USE_CW_FILE', `')
diff --git a/contrib/sendmail/cf/feature/uucpdomain.m4 b/contrib/sendmail/cf/feature/uucpdomain.m4
index cc34032..4d23229 100644
--- a/contrib/sendmail/cf/feature/uucpdomain.m4
+++ b/contrib/sendmail/cf/feature/uucpdomain.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: uucpdomain.m4,v 8.22 1999/07/22 17:55:35 gshapiro Exp $')
+VERSIONID(`$Id: uucpdomain.m4,v 8.27 2001/03/16 00:51:26 gshapiro Exp $')
divert(-1)
define(`_UUDOMAIN_TABLE_', `')
LOCAL_CONFIG
# UUCP domain table
-Kuudomain ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`uudomain',
+Kuudomain ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`uudomain',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=uucpdomain)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/feature/virtusertable.m4 b/contrib/sendmail/cf/feature/virtusertable.m4
index b1f6028..d9c628f 100644
--- a/contrib/sendmail/cf/feature/virtusertable.m4
+++ b/contrib/sendmail/cf/feature/virtusertable.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,13 +13,13 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: virtusertable.m4,v 8.16 1999/07/22 17:55:36 gshapiro Exp $')
+VERSIONID(`$Id: virtusertable.m4,v 8.21 2001/03/16 00:51:26 gshapiro Exp $')
divert(-1)
define(`_VIRTUSER_TABLE_', `')
LOCAL_CONFIG
# Virtual user table (maps incoming users)
-Kvirtuser ifelse(defn(`_ARG_'), `',
- DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`virtusertable',
+Kvirtuser ifelse(defn(`_ARG_'), `', DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`virtusertable',
+ defn(`_ARG_'), `LDAP', `ldap -1 -v sendmailMTAMapValue -k (&(objectClass=sendmailMTAMapObject)(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j))(sendmailMTAMapName=virtuser)(sendmailMTAKey=%0))',
`_ARG_')
diff --git a/contrib/sendmail/cf/m4/cfhead.m4 b/contrib/sendmail/cf/m4/cfhead.m4
index d247b19..708a095 100644
--- a/contrib/sendmail/cf/m4/cfhead.m4
+++ b/contrib/sendmail/cf/m4/cfhead.m4
@@ -23,6 +23,10 @@ include(TEMPFILE)dnl
syscmd(rm -f TEMPFILE)dnl')', `dnl')
#####
######################################################################
+#####
+##### DO NOT EDIT THIS FILE! Only edit the source .mc file.
+#####
+######################################################################
######################################################################
divert(-1)
@@ -46,8 +50,6 @@ define(`OSTYPE',
## helpful functions
define(`lower', `translit(`$1', `ABCDEFGHIJKLMNOPQRSTUVWXYZ', `abcdefghijklmnopqrstuvwx')')
define(`strcasecmp', `ifelse(lower($1), lower($2), `1', `0')')
-## new FEATUREs
-define(`_DNSBL_R_',`')
## access to further arguments in FEATURE/HACK
define(`_ACC_ARG_1_',`$1')
define(`_ACC_ARG_2_',`$2')
@@ -101,14 +103,21 @@ dnl in MAILER.m4: _MODMF_(LMF,`LOCAL')
dnl ----------------------------------------
define(`MAILER',
`define(`_M_N_', `ifelse(`$2', `', `$1', `$2')')dnl
-ifdef(_MAILER_`'_M_N_`'_, `dnl`'',
+ifdef(`_MAILER_DEFINED_', `', `define(`_MAILER_DEFINED_', `1')')dnl
+ifdef(_MAILER_`'_M_N_`'_,
+`errprint(`*** ERROR: MAILER('_M_N_`) already included
+')',
`define(_MAILER_`'_M_N_`'_, `')define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')PUSHDIVERT(7)include(_CF_DIR_`'mailer/$1.m4)POPDIVERT`'')')
define(`DOMAIN', `PUSHDIVERT(-1)define(`_ARG_', `$2')include(_CF_DIR_`'domain/$1.m4)POPDIVERT`'')
-define(`FEATURE', `PUSHDIVERT(-1)define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')include(_CF_DIR_`'feature/$1.m4)POPDIVERT`'')
+define(`FEATURE', `PUSHDIVERT(-1)ifdef(`_MAILER_DEFINED_',`errprint(`*** ERROR: FEATURE() should be before MAILER()
+')')define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')include(_CF_DIR_`'feature/$1.m4)POPDIVERT`'')
define(`HACK', `PUSHDIVERT(-1)define(`_ARG_', `$2')define(`_ARGS_', `shift($@)')include(_CF_DIR_`'hack/$1.m4)POPDIVERT`'')
define(`_DPO_',`')
define(`DAEMON_OPTIONS', `define(`_DPO_', defn(`_DPO_')
O DaemonPortOptions=`$1')')
+define(`_CPO_',`')
+define(`CLIENT_OPTIONS', `define(`_CPO_', defn(`_CPO_')
+O ClientPortOptions=`$1')')
define(`_MAIL_FILTERS_', `')
define(`MAIL_FILTER', `define(`_MAIL_FILTERS_', defn(`_MAIL_FILTERS_')
X`'$1`, '`$2')')
@@ -116,7 +125,10 @@ define(`INPUT_MAIL_FILTER', `MAIL_FILTER(`$1', `$2')
ifelse(defn(`confINPUT_MAIL_FILTERS')X, `X',
`define(`confINPUT_MAIL_FILTERS', $1)',
`define(`confINPUT_MAIL_FILTERS', defn(`confINPUT_MAIL_FILTERS')`, '`$1')')')
-define(`CF_LEVEL', `9')dnl
+define(`_QUEUE_GROUP_', `')
+define(`QUEUE_GROUP', `define(`_QUEUE_GROUP_', defn(`_QUEUE_GROUP_')
+Q`'$1`, '`$2')')
+define(`CF_LEVEL', `10')dnl
define(`VERSIONID', ``##### $1 #####'')
define(`LOCAL_RULE_0', `divert(3)')
define(`LOCAL_RULE_1',
@@ -139,6 +151,36 @@ define(`LOCAL_RULESETS',
`divert(9)
')
+define(`LOCAL_SRV_FEATURES',
+`define(`_LOCAL_SRV_FEATURES_')
+ifdef(`_MAILER_DEFINED_',,`errprint(`*** WARNING: MAILER() should be before LOCAL_SRV_FEATURES
+')')
+divert(9)
+SLocal_srv_features')
+define(`LOCAL_TRY_TLS',
+`define(`_LOCAL_TRY_TLS_')
+ifdef(`_MAILER_DEFINED_',,`errprint(`*** WARNING: MAILER() should be before LOCAL_TRY_TLS
+')')
+divert(9)
+SLocal_try_tls')
+define(`LOCAL_TLS_RCPT',
+`define(`_LOCAL_TLS_RCPT_')
+ifdef(`_MAILER_DEFINED_',,`errprint(`*** WARNING: MAILER() should be before LOCAL_TLS_RCPT
+')')
+divert(9)
+SLocal_tls_rcpt')
+define(`LOCAL_TLS_CLIENT',
+`define(`_LOCAL_TLS_CLIENT_')
+ifdef(`_MAILER_DEFINED_',,`errprint(`*** WARNING: MAILER() should be before LOCAL_TLS_CLIENT
+')')
+divert(9)
+SLocal_tls_client')
+define(`LOCAL_TLS_SERVER',
+`define(`_LOCAL_TLS_SERVER_')
+ifdef(`_MAILER_DEFINED_',,`errprint(`*** WARNING: MAILER() should be before LOCAL_TLS_SERVER
+')')
+divert(9)
+SLocal_tls_server')
define(`LOCAL_RULE_3', `divert(2)')
define(`LOCAL_CONFIG', `divert(6)')
define(`MAILER_DEFINITIONS', `divert(7)')
@@ -149,17 +191,19 @@ define(`DOL', ``$'$1')
define(`SITECONFIG',
`CONCAT(D, $3, $2)
define(`_CLASS_$3_', `')dnl
-ifelse($3, U, Cw$2 $2.UUCP, `dnl')
+ifelse($3, U, C{w}$2 $2.UUCP, `dnl')
define(`SITE', `ifelse(CONCAT($'2`, $3), SU,
CONCAT(CY, $'1`),
CONCAT(C, $3, $'1`))')
sinclude(_CF_DIR_`'siteconfig/$1.m4)')
define(`EXPOSED_USER', `PUSHDIVERT(5)C{E}$1
POPDIVERT`'dnl`'')
-ifdef(`_FFR_EXPOSED_USER_FILE', `define(`EXPOSED_USER_FILE', `PUSHDIVERT(5)F{E}$1
-POPDIVERT`'dnl`'')', `dnl')
+define(`EXPOSED_USER_FILE', `PUSHDIVERT(5)F{E}$1
+POPDIVERT`'dnl`'')
define(`LOCAL_USER', `PUSHDIVERT(5)C{L}$1
POPDIVERT`'dnl`'')
+define(`LOCAL_USER_FILE', `PUSHDIVERT(5)F{L}$1
+POPDIVERT`'dnl`'')
define(`MASQUERADE_AS', `define(`MASQUERADE_NAME', $1)')
define(`MASQUERADE_DOMAIN', `PUSHDIVERT(5)C{M}$1
POPDIVERT`'dnl`'')
@@ -167,6 +211,8 @@ define(`MASQUERADE_EXCEPTION', `PUSHDIVERT(5)C{N}$1
POPDIVERT`'dnl`'')
define(`MASQUERADE_DOMAIN_FILE', `PUSHDIVERT(5)F{M}$1
POPDIVERT`'dnl`'')
+define(`MASQUERADE_EXCEPTION_FILE', `PUSHDIVERT(5)F{N}$1
+POPDIVERT`'dnl`'')
define(`LOCAL_DOMAIN', `PUSHDIVERT(5)C{w}$1
POPDIVERT`'dnl`'')
define(`CANONIFY_DOMAIN', `PUSHDIVERT(5)C{Canonify}$1
@@ -181,6 +227,10 @@ define(`LDAPROUTE_DOMAIN', `PUSHDIVERT(5)C{LDAPRoute}$1
POPDIVERT`'dnl`'')
define(`LDAPROUTE_DOMAIN_FILE', `PUSHDIVERT(5)F{LDAPRoute}$1
POPDIVERT`'dnl`'')
+define(`LDAPROUTE_EQUIVALENT', `PUSHDIVERT(5)C{LDAPRouteEquiv}$1
+POPDIVERT`'dnl`'')
+define(`LDAPROUTE_EQUIVALENT_FILE', `PUSHDIVERT(5)F{LDAPRouteEquiv}$1
+POPDIVERT`'dnl`'')
define(`VIRTUSER_DOMAIN', `PUSHDIVERT(5)C{VirtHost}$1
define(`_VIRTHOSTS_')
POPDIVERT`'dnl`'')
@@ -191,7 +241,7 @@ define(`RELAY_DOMAIN', `PUSHDIVERT(5)C{R}$1
POPDIVERT`'dnl`'')
define(`RELAY_DOMAIN_FILE', `PUSHDIVERT(5)F{R}$1
POPDIVERT`'dnl`'')
-define(`TRUST_AUTH_MECH', `PUSHDIVERT(5)C{TrustAuthMech}$1
+define(`TRUST_AUTH_MECH', `_DEFIFNOT(`_USE_AUTH_',`1')PUSHDIVERT(5)C{TrustAuthMech}$1
POPDIVERT`'dnl`'')
define(`_OPTINS', `ifdef(`$1', `$2$1$3')')
@@ -211,14 +261,14 @@ define(`confFROM_LINE', `From $g $d')
define(`confOPERATORS', `.:%@!^/[]+')
define(`confSMTP_LOGIN_MSG', `$j Sendmail $v/$Z; $b')
define(`_REC_AUTH_', `$.$?{auth_type}(authenticated')
-define(`_REC_FULL_AUTH_', `$.$?{auth_type}(authenticated as ${auth_authen} $?{auth_author}for ${auth_author} $.with ${auth_type}')
+define(`_REC_FULL_AUTH_', `$.$?{auth_type}(user=${auth_authen} $?{auth_author}author=${auth_author} $.mech=${auth_type}')
define(`_REC_HDR_', `$?sfrom $s $.$?_($?s$|from $.$_)')
define(`_REC_END_', `for $u; $|;
$.$b')
-define(`_REC_TLS_', `(using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})$.$?u')
+define(`_REC_TLS_', `(version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})$.$?u')
define(`_REC_BY_', `$.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}')
define(`confRECEIVED_HEADER', `_REC_HDR_
- _REC_AUTH_$?{auth_ssf} (${auth_ssf} bits)$.)
+ _REC_AUTH_$?{auth_ssf} bits=${auth_ssf}$.)
_REC_BY_
_REC_TLS_
_REC_END_')
@@ -251,4 +301,4 @@ define(`confMILTER_MACROS_ENVRCPT', ``{rcpt_mailer}, {rcpt_host}, {rcpt_addr}'')
divert(0)dnl
-VERSIONID(`$Id: cfhead.m4,v 8.76.4.16 2001/03/06 22:56:36 ca Exp $')
+VERSIONID(`$Id: cfhead.m4,v 8.107 2001/07/22 03:25:37 ca Exp $')
diff --git a/contrib/sendmail/cf/m4/proto.m4 b/contrib/sendmail/cf/m4/proto.m4
index d8a1641..aa12a70 100644
--- a/contrib/sendmail/cf/m4/proto.m4
+++ b/contrib/sendmail/cf/m4/proto.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -13,14 +13,16 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: proto.m4,v 8.446.2.5.2.44 2001/07/31 22:25:49 gshapiro Exp $')
-
-MAILER(local)dnl
+VERSIONID(`$Id: proto.m4,v 8.628 2001/12/28 19:02:40 ca Exp $')
# level CF_LEVEL config file format
V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
divert(-1)
+dnl if MAILER(`local') not defined: do it ourself; be nice
+dnl maybe we should issue a warning?
+ifdef(`_MAILER_local_',`', `MAILER(local)')
+
# do some sanity checking
ifdef(`__OSTYPE__',,
`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
@@ -76,8 +78,10 @@ define(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'i
dnl required to "rename" the check_* rulesets...
define(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
dnl default relaying denied message
-ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')')
-define(`CODE553', `553')
+ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
+ifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
+ifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
+define(`_CODE553', `553')
divert(0)dnl
# override file safeties - setting this option compromises system security,
@@ -93,6 +97,10 @@ _OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
# local info #
##################
+# my LDAP cluster
+# need to set this before any LDAP lookups are done (including classes)
+ifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
+
Cwlocalhost
ifdef(`USE_CW_FILE',
`# file containing names of hosts for which we receive email
@@ -131,7 +139,7 @@ CPFAX
')dnl
# "Smart" relay host (may be null)
-DS`'ifdef(`SMART_HOST', SMART_HOST)
+DS`'ifdef(`SMART_HOST', `SMART_HOST')
ifdef(`LUSER_RELAY', `dnl
# place to which unknown users should be forwarded
@@ -151,15 +159,18 @@ C[[
ifdef(`_ACCESS_TABLE_', `dnl
# access_db acceptance class
C{Accept}OK RELAY
-ifdef(`_DELAY_CHECKS_',`dnl
+ifdef(`_DELAY_COMPAT_8_10_',`dnl
ifdef(`_BLACKLIST_RCPT_',`dnl
# possible access_db RHS for spam friends/haters
C{SpamTag}SPAMFRIEND SPAMHATER')')',
`dnl')
+dnl mark for "domain is ok" (resolved or accepted anyway)
+define(`_RES_OK_', `OKR')dnl
ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
# Resolve map (to check if a host exists in check_mail)
-Kresolve host -a<OK> -T<TEMP>')
+Kresolve host -a<_RES_OK_> -T<TEMP>')
+C{ResOk}_RES_OK_
ifdef(`_NEED_MACRO_MAP_', `dnl
ifdef(`_MACRO_MAP_', `', `# macro storage map
@@ -171,16 +182,20 @@ ifdef(`confCR_FILE', `dnl
FR`'confCR_FILE',
`dnl')
-define(`TLS_SRV_TAG', `TLS_Srv')dnl
-define(`TLS_CLT_TAG', `TLS_Clt')dnl
-define(`TLS_TRY_TAG', `Try_TLS')dnl
-define(`TLS_OFF_TAG', `Offer_TLS')dnl
+define(`TLS_SRV_TAG', `"TLS_Srv"')dnl
+define(`TLS_CLT_TAG', `"TLS_Clt"')dnl
+define(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
+define(`TLS_TRY_TAG', `"Try_TLS"')dnl
+define(`SRV_FEAT_TAG', `"Srv_Features"')dnl
dnl this may be useful in other contexts too
ifdef(`_ARITH_MAP_', `', `# arithmetic map
define(`_ARITH_MAP_', `1')dnl
Karith arith')
ifdef(`_ACCESS_TABLE_', `dnl
-# possible values for tls_connect in access map
+ifdef(`_MACRO_MAP_', `', `# macro storage map
+define(`_MACRO_MAP_', `1')dnl
+Kmacro macro')
+# possible values for TLS_connection in access map
C{tls}VERIFY ENCR', `dnl')
ifdef(`_CERT_REGEX_ISSUER_', `dnl
# extract relevant part from cert issuer
@@ -189,14 +204,16 @@ ifdef(`_CERT_REGEX_SUBJECT_', `dnl
# extract relevant part from cert subject
KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
+ifdef(`LOCAL_RELAY', `dnl
# who I send unqualified names to (null means deliver locally)
-DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
+DR`'LOCAL_RELAY')
+ifdef(`MAIL_HUB', `dnl
# who gets all local email traffic ($R has precedence for unqualified names)
-DH`'ifdef(`MAIL_HUB', MAIL_HUB)
+DH`'MAIL_HUB')
# dequoting map
-Kdequote dequote
+Kdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
divert(0)dnl # end of nullclient diversion
# class E: names that should be exposed as from this host, even if we masquerade
@@ -207,8 +224,9 @@ divert(0)dnl # end of nullclient diversion
undivert(5)dnl
ifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
+ifdef(`MASQUERADE_NAME', `dnl
# who I masquerade as (null for no masquerading) (see also $=M)
-DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
+DM`'MASQUERADE_NAME')
# my name for error messages
ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
@@ -219,6 +237,10 @@ include(_CF_DIR_`m4/version.m4')
###############
# Options #
###############
+ifdef(`confAUTO_REBUILD',
+`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
+ There was a potential for a denial of service attack if this is set.
+)')dnl
# strip message body to 7 bits on input?
_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
@@ -250,11 +272,6 @@ _OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
# default delivery mode
_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
-# automatically rebuild the alias database?
-# NOTE: There is a potential for a denial of service attack if this is set.
-# This option is deprecated and will be removed from a future version.
-_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False')
-
# error message header/file
_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
@@ -264,6 +281,9 @@ _OPTION(ErrorMode, `confERROR_MODE', `print')
# save Unix-style "From_" lines at top of header?
_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
+# queue file mode (qf files)
+_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
+
# temporary file mode
_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
@@ -271,7 +291,7 @@ _OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
# maximum hop count
-_OPTION(MaxHopCount, `confMAX_HOP', `17')
+_OPTION(MaxHopCount, `confMAX_HOP', `25')
# location of help file
O HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
@@ -321,12 +341,23 @@ ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
)'dnl
`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
ifelse(defn(`_DPO_'), `',
-`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet
-O DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
+`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
+O DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
# SMTP client options
-_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0')
+ifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
+`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information.
+)'dnl
+`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
+ifelse(defn(`_CPO_'), `',
+`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
+
+# Modifiers to `define' {daemon_flags} for direct submissions
+_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
+
+# Use as mail submission program? See sendmail/SECURITY
+_OPTION(UseMSP, `confUSE_MSP', `')
# privacy flags
_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
@@ -337,12 +368,37 @@ _OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
# slope of queue-only function
_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
+# limit on number of concurrent queue runners
+_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
+
+# maximum number of queue-runners per queue-grouping with multiple queues
+_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
+
+# priority of queue runners (nice(3))
+_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
+
+# shall we sort the queue by hostname first?
+_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
+
+# minimum time in queue before retry
+_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
+
+# how many jobs can you process in the queue?
+_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
+
+# perform initial split of envelope without checking MX records
+_OPTION(FastSplit, `confFAST_SPLIT', `1')
+
# queue directory
O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
+# key for shared memory; 0 to turn off
+_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
+
# timeouts (many of these)
_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
+_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
_OPTION(Timeout.helo, `confTO_HELO', `5m')
_OPTION(Timeout.mail, `confTO_MAIL', `10m')
@@ -372,6 +428,12 @@ _OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
+_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
+_OPTION(Timeout.auth, `confTO_AUTH', `10m')
+_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
+
+# time for DeliverBy; extension disabled if less than 0
+_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
# should we not prune routes in route-addr syntax addresses?
_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
@@ -408,6 +470,9 @@ _OPTION(QueueLA, `confQUEUE_LA', `8')
# load average at which we refuse connections
_OPTION(RefuseLA, `confREFUSE_LA', `12')
+# load average at which we delay connections; 0 means no limit
+_OPTION(DelayLA, `confDELAY_LA', `0')
+
# maximum number of children we allow at one time
_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
@@ -426,16 +491,10 @@ _OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
# work time factor
_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
-# shall we sort the queue by hostname first?
-_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
-
-# minimum time in queue before retry
-_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
-
# default character set
_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
-# service switch file (ignored on Solaris, Ultrix, OSF/1, others)
+# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
# hosts file (normally /etc/hosts)
@@ -453,9 +512,6 @@ _OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
# are colons OK in addresses?
_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
-# how many jobs can you process in the queue?
-_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
-
# shall I avoid expanding CNAMEs (violates protocols)?
_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
@@ -481,7 +537,11 @@ _OPTION(OperatorChars, `confOPERATORS', `.:@[]')
_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
# are group-writable `:include:' and .forward files (un)trustworthy?
+# True (the default) means they are not trustworthy.
_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
+ifdef(`confUNSAFE_GROUP_WRITES',
+`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
+')')
# where do errors that occur when sending errors get sent?
_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
@@ -495,6 +555,10 @@ _OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
# maximum number of recipients per SMTP envelope
_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
+# limit the rate recipients per SMTP envelope are accepted
+# once the threshold number of recipients have been rejected
+_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
+
# shall we get local names from our installed interfaces?
_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
@@ -531,8 +595,11 @@ _OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
# Transcript file (xf) memory-buffer file maximum size
_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
+# lookup type to find information about local mailboxes
+_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
+
# list of authentication mechanisms
-_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
+_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
# default authentication information for outgoing connections
_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
@@ -540,11 +607,18 @@ _OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-i
# SMTP AUTH flags
_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
-ifdef(`_FFR_MILTER', `
+# SMTP AUTH maximum encryption strength
+_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
+
+# SMTP STARTTLS server options
+_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
+
# Input mail filters
_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
+ifdef(`confINPUT_MAIL_FILTERS', `dnl
# Milter options
+_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
@@ -567,10 +641,10 @@ _OPTION(DHParameters, `confDH_PARAMETERS', `')
# Random data source (required for systems without /dev/urandom under OpenSSL)
_OPTION(RandFile, `confRAND_FILE', `')
-ifdef(`confQUEUE_FILE_MODE',
-`# queue file mode (qf files)
-O QueueFileMode=confQUEUE_FILE_MODE
-')
+############################
+`# QUEUE GROUP DEFINITIONS #'
+############################
+_QUEUE_GROUP_
###########################
# Message precedences #
@@ -631,9 +705,9 @@ R$@ $@ <@>
R$* $: $1 <@> mark addresses
R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr>
R@ $* <@> $: @ $1 unmark @host:...
+R$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr
R$* :: $* <@> $: $1 :: $2 unmark node::addr
R:`include': $* <@> $: :`include': $1 unmark :`include':...
-R$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr
R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon
R$* : $* <@> $: $2 strip colon if marked
R$* <@> $: $1 unmark
@@ -656,10 +730,15 @@ ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
R@ $+ , $+ @ $1 : $2 change all "," to ":"
# localize and dispose of route-based addresses
+dnl XXX: IPv6 colon conflict
+ifdef(`NO_NETINET6', `dnl',
+`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>')
R@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr>
dnl',`dnl
# strip route address <@a,@b,@c:user@d> -> <user@d>
R@ $+ , $+ $2
+ifdef(`NO_NETINET6', `dnl',
+`R@ [ $* ] : $+ $2')
R@ $+ : $+ $2
dnl')
@@ -672,8 +751,9 @@ R$+ @ $+ $: $1 < @ $2 > focus on domain
R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right
R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical
-# do some sanity checking
-R$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs
+dnl This is flagged as an error in S0; no need to silently fix it here.
+dnl # do some sanity checking
+dnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs
ifdef(`_NO_UUCP_', `dnl',
`# convert old-style addresses to a domain-based address
@@ -708,13 +788,8 @@ R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain
ifdef(`_NO_UUCP_', `dnl',
`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain')
-# check for IPv6 domain literal (save quoted form)
-R$* < @ [ IPv6 : $+ ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr
-R$+ $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal
-R$+ $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 : $1 ] > $4 canon IP addr
-
-# check for IPv4 domain literal
-R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d]
+# check for IPv4/IPv6 domain literal
+R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr]
R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal
R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr
@@ -780,13 +855,18 @@ dnl this should only apply to unqualified hostnames
dnl but if a valid character inside an unqualified hostname is an OperatorChar
dnl then $- does not work.
# lookup unqualified hostnames
-R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
+R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
dnl _NO_CANONIFY_ is not set: canonify unless:
dnl {daemon_flags} contains CC (do not canonify)
dnl but add a trailing dot to qualified hostnames so other rules will work
dnl should we do this for every hostname: even unqualified?
R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
R$* CC $* $| $* $: $3
+ifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
+# do not canonify header addresses
+R$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5
+R$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
+R$* h $* $| $* $: $3', `dnl')
# pass to name server to make hostname canonical
R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4')
dnl remove {daemon_flags} for other cases
@@ -803,6 +883,12 @@ ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4',
`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')',
`dnl')
+ifdef(`_GENERICS_TABLE_', `dnl
+dnl hosts for genericstable are also canonical
+ifdef(`_GENERICS_ENTIRE_DOMAIN_',
+`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4',
+`R$* < @ $=G > $* $: $1 < @ $2 . > $3')',
+`dnl')
dnl remove superfluous dots (maybe repeatedly) which may have been added
dnl by one of the rules before
R$* < @ $* . . > $* $1 < @ $2 . > $3
@@ -870,26 +956,41 @@ R$* $: $>Parse1 $1 final parsing
SParse0
R<@> $@ <@> special case error msgs
-R$* : $* ; <@> $#error $@ 5.1.3 $: "CODE553 List:; syntax illegal for recipient addresses"
+R$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
R@ <@ $* > < @ $1 > catch "@@host" bogosity
-R<@ $+> $#error $@ 5.1.3 $: "CODE553 User address required"
+R<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required"
+R$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required"
R$* $: <> $1
-R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3
-R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "CODE553 Colon illegal in host name part"
+dnl allow tricks like [host1]:[host2]
+R<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4
+R<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4
+dnl but no a@[b]c
+R<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address"
+R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3
+R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
R<> $* $1
-R$* < @ . $* > $* $#error $@ 5.1.2 $: "CODE553 Invalid host name"
-R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "CODE553 Invalid host name"
+R$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name"
+R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name"
+dnl no a@b@
+R$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address"
+dnl no a@b@c
+R$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address"
dnl comma only allowed before @; this check is not complete
-R$* , $~O $* $#error $@ 5.1.2 $: "CODE553 Invalid route address"
+R$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address"
+
+ifdef(`_STRICT_RFC821_', `# more RFC 821 checks
+R$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
+R. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
+dnl', `dnl')
# now delete the local info -- note $=O to find characters that cause forwarding
R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user
R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ...
R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here
-R< @ $+ > $#error $@ 5.1.3 $: "CODE553 User address required"
+R< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required"
R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ...
R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo"
-R< @ *LOCAL* > $#error $@ 5.1.3 $: "CODE553 User address required"
+R< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required"
R$* $=O $* < @ *LOCAL* >
$@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ...
R$* < @ *LOCAL* > $: $1
@@ -901,7 +1002,8 @@ R$* < @ *LOCAL* > $: $1
SParse1
ifdef(`_LDAP_ROUTING_', `dnl
# handle LDAP routing for hosts in $={LDAPRoute}
-R$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>',
+R$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
+R$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
`dnl')
ifdef(`_MAILER_smtp_',
@@ -909,35 +1011,63 @@ ifdef(`_MAILER_smtp_',
dnl there is no check whether this is really an IP number
R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec
R$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path
-R$* < @ [ IPv6 : $+ ] : > $*
- $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 : $2 ] > $3 no smarthost: send
-R$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send
+R$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send
R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer
R$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer',
`dnl')
ifdef(`_VIRTUSER_TABLE_', `dnl
# handle virtual users
+ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
+dnl this is not a documented option
+dnl it stops looping in virtusertable mapping if input and output
+dnl are identical, i.e., if address A is mapped to A.
+dnl it does not deal with multi-level recursion
+# handle full domains in RHS of virtusertable
+R$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 >
+R$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
+R<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $)
+R<?> $+ $| $* $: $1',
+`dnl')
R$+ $: <!> $1 Mark for lookup
+dnl input: <!> local<@domain>
ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
+dnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
R<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
+dnl if <@> local<@domain>: no match but try lookup
+dnl user+detail: try user++@domain if detail not empty
+R<@> $+ + $+ < @ $* . >
+ $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+dnl user+detail: try user+*@domain
R<@> $+ + $* < @ $* . >
- $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
+ $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+dnl user+detail: try user@domain
R<@> $+ + $* < @ $* . >
- $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . >
+ $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
dnl try default entry: @domain
+dnl ++@domain
+R<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
dnl +*@domain
-R<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
dnl @domain if +detail exists
-R<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
dnl without +detail (or no match)
R<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
+dnl no match
R<@> $+ $: $1
+dnl remove mark
R<!> $+ $: $1
R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4
R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2
+ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
+# check virtuser input address against output address, if same, skip recursion
+R< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1
+# it is the same: stop now
+R< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1
+R< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 >
+dnl', `dnl')
dnl this is not a documented option
dnl it performs no looping at all for virtusertable
ifdef(`_NO_VIRTUSER_RECURSION_',
@@ -1020,7 +1150,7 @@ R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost nam
# deal with other remote names
ifdef(`_MAILER_smtp_',
`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain',
-`R$* < @$* > $* $#error $@ 5.1.2 $: "CODE553 Unrecognized host name " $2')
+`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
# handle locally delivered names
R$=L $#_LOCAL_ $: @ $1 special local names
@@ -1033,15 +1163,25 @@ R$+ $#_LOCAL_ $: $1 regular local names
SLocal_localaddr
Slocaladdr=5
R$+ $: $1 $| $>"Local_localaddr" $1
+R$+ $| $#ok $@ $1 no change
R$+ $| $#$* $#$2
R$+ $| $* $: $1
-ifdef(`_FFR_5_', `
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+# Preserve rcpt_host in {Host}
+R$+ $: $1 $| $&h $| $&{Host} check h and {Host}
+R$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host}
+R$+ $| $| $+ $: $1 h not set, {Host} set
+R$+ $| +$* $| $* $: $1 h is +detail, {Host} set
+R$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h
+')dnl
+
+ifdef(`_FFR_5_', `dnl
# Preserve host in a macro
R$+ $: $(macro {LocalAddrHost} $) $1
R$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1')
-ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `
+ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
# deal with plussed users so aliases work nicely
R$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
@@ -1051,35 +1191,61 @@ R$+ $: <> $1
ifdef(`LUSER_RELAY', `dnl
# send unrecognized local users to a relay host
-ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
+ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
R< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+
R< > $+ $: < ? $L > < > $(user $1 $) look up user
R< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L
R< ? $* > < $* > $+ $: < $1 > $3 $2 not found', `
R< > $+ $: < $L > $(user $1 $) look up user
-R< $* > $+ <> $: < > $2 found; strip $L')',
-`dnl')
+R< $* > $+ <> $: < > $2 found; strip $L')
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+R< $+ > $+ $: < $1 > $2 $&{Host}')
+dnl')
-# see if we have a relay or a hub
-R< > $+ $: < $H > $1 try hub
-R< > $+ $: < $R > $1 try relay
-ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
-R< > $+ $@ $1', `
+ifdef(`MAIL_HUB', `dnl
+R< > $+ $: < $H > $1 try hub', `dnl')
+ifdef(`LOCAL_RELAY', `dnl
+R< > $+ $: < $R > $1 try relay', `dnl')
+ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
+R< > $+ $@ $1', `dnl
R< > $+ $: < > < $1 <> $&h > nope, restore +detail
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+R< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail')
R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail
R< > < $+ <> $* > $: < > < $1 > else discard
R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part
R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra +
R< > < $+ > $@ $1 no +detail
R$+ $: $1 <> $&h add +detail back in
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+R$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail')
R$+ <> + $* $: $1 + $2 check whether +detail
R$+ <> $* $: $1 else discard')
R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension
R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension
-R< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
+R< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
+R< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
+ifdef(`_PRESERVE_LUSER_HOST_', `dnl
+R< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >')
R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 >
ifdef(`_MAILER_TABLE_', `dnl
+ifdef(`_LDAP_ROUTING_', `dnl
+###################################################################
+### Ruleset LDAPMailertable -- mailertable lookup for LDAP ###
+dnl input: <Domain> FullAddress
+###################################################################
+
+SLDAPMailertable
+R< $+ > $* $: < $(mailertable $1 $) > $2 lookup
+R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved?
+R< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain
+R< $+ > $#$* $#$2 found
+R< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay',
+`dnl')
+
###################################################################
### Ruleset 90 -- try domain part of mailertable entry ###
dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
@@ -1108,7 +1274,6 @@ dnl <error:text> -> error
dnl <mailer:user@host> lp<@domain>rest -> mailer host user
dnl <mailer:host> address -> mailer host address
dnl <localdomain> address -> address
-dnl <[IPv6:number]> address -> relay number address
dnl <host> address -> relay host address
###################################################################
@@ -1117,10 +1282,10 @@ R< > $* $@ $1 strip off null relay
R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4
R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2
R< local : $* > $* $>CanonLocal < $1 > $2
-R< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user
-R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer
+dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
+R< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user
+R< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer
R< $=w > $* $@ $2 delete local host
-R< [ IPv6 : $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer
R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer
###################################################################
@@ -1170,6 +1335,7 @@ R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark
dnl workspace: either user<@domain> or <user@domain> user <@domain> @
dnl ignore the first case for now
dnl if it has the mark lookup full address
+dnl broken: %1 is full address not just detail
R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 >
dnl workspace: ... or <match|@user@domain> user <@domain>
dnl no match, try user+detail@domain
@@ -1194,6 +1360,7 @@ R< > $* $: $1 not found',
# do not masquerade anything in class N
R$* < @ $* $=N . > $@ $1 < @ $2 $3 . >
+ifdef(`MASQUERADE_NAME', `dnl
# special case the users that should be exposed
R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed
ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
@@ -1211,6 +1378,9 @@ ifdef(`_LIMITED_MASQUERADE_', `dnl',
R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2
R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null
R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null
+dnl', `dnl no masquerading
+dnl just fix *LOCAL* leftovers
+R$* < @ *LOCAL* > $@ $1 < @ $j . >')
###################################################################
### Ruleset 94 -- convert envelope names to masqueraded form ###
@@ -1229,115 +1399,186 @@ SParseLocal=98
undivert(3)dnl LOCAL_RULE_0
ifdef(`_LDAP_ROUTING_', `dnl
+######################################################################
+### LDAPExpand: Expand address using LDAP routing
+###
+### Parameters:
+### <$1> -- parsed address (user < @ domain . >) (pass through)
+### <$2> -- RFC822 address (user @ domain) (used for lookup)
+### <$3> -- +detail information
+###
+### Returns:
+### Mailer triplet ($#mailer $@ host $: address)
+### Parsed address (user < @ domain . >)
+######################################################################
+
SLDAPExpand
# do the LDAP lookups
-R<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2>
+R<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
# if mailRoutingAddress and local or non-existant mailHost,
# return the new mailRoutingAddress
-R< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1
-R< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1
+ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
+R<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2
+R<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2')
+R<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1
+R<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1
# if mailRoutingAddress and non-local mailHost,
# relay to mailHost with new mailRoutingAddress
-R< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1
+ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
+ifdef(`_MAILER_TABLE_', `dnl
+# check mailertable for host, relay from there
+R<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
+`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
+ifdef(`_MAILER_TABLE_', `dnl
+# check mailertable for host, relay from there
+R<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1',
+`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1')
# if no mailRoutingAddress and local mailHost,
# return original address
-R< > < $=w > <$+> <$+> $@ $2
+R<> <$=w> <$+> <$+> <$*> $@ $2
# if no mailRoutingAddress and non-local mailHost,
# relay to mailHost with original address
-R< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2
+ifdef(`_MAILER_TABLE_', `dnl
+# check mailertable for host, relay from there
+R<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2',
+`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2')
-# if no mailRoutingAddress and no mailHost,
+ifdef(`_LDAP_ROUTE_DETAIL_',
+`# if no mailRoutingAddress and no mailHost,
+# try without +detail
+R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
+
+# if still no mailRoutingAddress and no mailHost,
# try @domain
-R< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3>
+ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
+R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>')
+R<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4>
# if no mailRoutingAddress and no mailHost and this was a domain attempt,
ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
# user does not exist
-R< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"',
+R<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 >
+# only give error for envelope recipient
+R<?> <e r> <$+> $#error $@ nouser $: "550 User unknown"
+R<?> <$*> <$+> $@ $2',
`dnl
# return the original address
-R< > < > <$+> <@ $+> $@ $1')',
+R<> <> <$+> <@ $+> <$*> $@ $1')',
`dnl')
ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
')')
-ifdef(`_ACCESS_TABLE_', `dnl
+ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
######################################################################
-### LookUpDomain -- search for domain in access database
+### D: LookUpDomain -- search for domain in access database
###
### Parameters:
### <$1> -- key (domain name)
### <$2> -- default (what to return if not found in db)
dnl must not be empty
-### <$3> -- passthru (additional data passed unchanged through)
-### <$4> -- mark (must be <(!|+) single-token>)
+### <$3> -- mark (must be <(!|+) single-token>)
### ! does lookup only with tag
### + does lookup with and without tag
+### <$4> -- passthru (additional data passed unchanged through)
dnl returns: <default> <passthru>
dnl <result> <passthru>
######################################################################
-SLookUpDomain
-dnl remove IPv6 mark and dequote address
-dnl it is a bit ugly because it is checked on each "iteration"
-R<[IPv6 : $+]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4>
+SD
dnl workspace <key> <default> <passthru> <mark>
dnl lookup with tag (in front, no delimiter here)
-R<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
+dnl 2 3 4 5
+R<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
-ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
-R<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl')
dnl lookup without tag?
-R<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
-ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
-R<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl')
-dnl lookup IP address (no check is done whether it is an IP number!)
-R<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5>
-dnl lookup IPv6 address
-R<?> <[$+::$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5>
-R<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5>
+dnl 1 2 3 4
+R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
+ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
+dnl XXX apply this also to IP addresses?
+dnl currently it works the wrong way round for [1.2.3.4]
+dnl 1 2 3 4 5 6
+R<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
+dnl 1 2 3 4 5
+R<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
+ifdef(`_ACCESS_SKIP_', `dnl
+dnl found SKIP: return <default> and <passthru>
+dnl 1 2 3 4 5
+R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl')
+dnl not found: IPv4 net (no check is done whether it is an IP number!)
+dnl 1 2 3 4 5 6
+R<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6>
+ifdef(`NO_NETINET6', `dnl',
+`dnl not found: IPv6 net
+dnl (could be merged with previous rule if we have a class containing .:)
+dnl 1 2 3 4 5 6
+R<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>
+R<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>')
dnl not found, but subdomain: try again
-R<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5>
-dnl not found, no subdomain: return default
-R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3>
-dnl return result of lookup
-R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>
+dnl 1 2 3 4 5 6
+R<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6>
+ifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
+dnl 1 2 3 4
+R<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
+dnl not found, no subdomain: return <default> and <passthru>
+dnl 1 2 3 4 5
+R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>
+ifdef(`_ATMPF_', `dnl tempfail?
+dnl 2 3 4 5 6
+R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl')
+dnl return <result of lookup> and <passthru>
+dnl 2 3 4 5 6
+R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6>
######################################################################
-### LookUpAddress -- search for host address in access database
+### A: LookUpAddress -- search for host address in access database
###
### Parameters:
### <$1> -- key (dot quadded host address)
### <$2> -- default (what to return if not found in db)
dnl must not be empty
-### <$3> -- passthru (additional data passed through)
-### <$4> -- mark (must be <(!|+) single-token>)
+### <$3> -- mark (must be <(!|+) single-token>)
### ! does lookup only with tag
### + does lookup with and without tag
+### <$4> -- passthru (additional data passed through)
dnl returns: <default> <passthru>
dnl <result> <passthru>
######################################################################
-SLookUpAddress
+SA
dnl lookup with tag
-R<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
+dnl 2 3 4 5
+R<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
dnl lookup without tag
-R<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
-dnl no match; IPv6: remove last part
-R<?> <$+::$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5>
-R<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5>
+dnl 1 2 3 4
+R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
+dnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
+ifdef(`_ACCESS_SKIP_', `dnl
+dnl found SKIP: return <default> and <passthru>
+dnl 1 2 3 4 5
+R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl')
+ifdef(`NO_NETINET6', `dnl',
+`dnl no match; IPv6: remove last part
+dnl 1 2 3 4 5 6
+R<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>
+R<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>')
dnl no match; IPv4: remove last part
-R<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5>
+dnl 1 2 3 4 5 6
+R<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>
dnl no match: return default
-R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3>
+dnl 1 2 3 4 5
+R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>
+ifdef(`_ATMPF_', `dnl tempfail?
+dnl 2 3 4 5 6
+R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl')
dnl match: return result
-R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>',
-`dnl')
-
+dnl 2 3 4 5 6
+R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6>
+dnl endif _ACCESS_TABLE_
+divert(0)
######################################################################
### CanonAddr -- Convert an address into a standard form for
### relay checking. Route address syntax is
@@ -1385,23 +1626,18 @@ R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4>
dnl no $=O in localpart: return
R<?> $* $@ $1
-dnl workspace: <?> localpart<@domain>, where localpart contains $=O
+dnl workspace: <NO> localpart<@domain>, where localpart contains $=O
dnl mark everything which has an "authorized" domain with <RELAY>
ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
# if we relay, check username portion for user%host so host can be checked also
R<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl')
-
-ifdef(`_RELAY_MX_SERVED_', `dnl
-dnl do "we" ($=w) act as backup MX server for the destination domain?
-R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
-R<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
-dnl yes: mark it as <RELAY>
-R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4
-dnl no: put old <NO> mark back
-R<MX> < : $* : > < $+ > $: <NO> $2', `dnl')
-
dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
dnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
+
+dnl what if access map returns something else than RELAY?
+dnl we are only interested in RELAY entries...
+dnl other To: entries: blacklist recipient; generic entries?
+dnl if it is an error we probably do not want to relay anyway
ifdef(`_RELAY_HOSTS_ONLY_',
`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 >
ifdef(`_ACCESS_TABLE_', `dnl
@@ -1409,12 +1645,23 @@ R<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 >
R<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 >
ifdef(`_ACCESS_TABLE_', `dnl
-R<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To>
+R<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
R<$+> <$+> $: <$1> $2',`dnl')')
+ifdef(`_RELAY_MX_SERVED_', `dnl
+dnl do "we" ($=w) act as backup MX server for the destination domain?
+R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
+R<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
+dnl yes: mark it as <RELAY>
+R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4
+dnl no: put old <NO> mark back
+R<MX> < : $* : > < $+ > $: <NO> $2', `dnl')
+
+dnl do we relay to this recipient domain?
R<RELAY> $* < @ $* > $@ $>ParseRecipient $1
-R<$-> $* $@ $2
+dnl something else
+R<$+> $* $@ $2
######################################################################
@@ -1435,26 +1682,28 @@ R< $* > $* $: $2
ifdef(`_ACCESS_TABLE_', `dnl
dnl workspace: {client_name} $| {client_addr}
-R$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect>
-dnl workspace: <result-of-lookup> <{client_addr}>
-R<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup
-dnl workspace: <result-of-lookup> <{client_addr}>
-R<?> < $+ > $: $1 found nothing
+R$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 >
dnl workspace: <result-of-lookup> <{client_addr}>
-dnl or {client_addr}
-R<$={Accept}> < $* > $@ $1 return value of lookup
-R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
-R<DISCARD> $* $#discard $: discard
+R<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup
+dnl workspace: <result-of-lookup> (<>|<{client_addr}>)
+R<?> <$*> $: OK found nothing
+dnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
+R<$={Accept}> <$*> $@ $1 return value of lookup
+R<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
+R<DISCARD> <$*> $#discard $: discard
+ifdef(`_FFR_QUARANTINE',
+`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl')
dnl error tag
R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4
R<ERROR:$+> <$*> $#error $: $1
+ifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
dnl generic error from access map
R<$+> <$*> $#error $: $1', `dnl')
ifdef(`_RBL_',`dnl
# DNS based IP address spam list
+dnl workspace: ignored...
R$* $: $&{client_addr}
-R::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
R<?>OK $: OKSOFAR
R<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
@@ -1529,7 +1778,7 @@ dnl workspace: < ? $&{client_name} > <user@localhost|host>
dnl or: <address>
dnl or: <?> <address> (thanks to u in ${daemon_flags})
R<? $=w> $* $: $2 local client: ok
-R<? $+> <$+> $#error $@ 5.5.4 $: "CODE553 Real domain name required for sender address"
+R<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
R<?> $* $: $1')
dnl workspace: address (or <address>)
@@ -1541,23 +1790,23 @@ R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots
R<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 >
dnl workspace <mark> CanonicalAddress where mark is ? or OK
ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
-`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK',
+`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK',
`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
R<? $* <$->> $* < @ $+ >
$: <$2> $3 < @ $4 >')
-dnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP
+dnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP
dnl mark is ? iff the address is user (wo @domain)
ifdef(`_ACCESS_TABLE_', `dnl
# check sender address: user@address, user@, address
dnl should we remove +ext from user?
-dnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP
-R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3>
+dnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
+R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
R<$+> $+ $: @<$1> <$2> $| <U:$2@>
dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
dnl will only return user<@domain when "reversing" the args
-R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <>
+R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
dnl workspace: <@><mark> <CanonicalAddress> $| <result>
R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result
dnl workspace: <result> <mark> <CanonicalAddress>
@@ -1574,25 +1823,28 @@ ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
dnl prepend daemon_flags
R<?> $* $: $&{daemon_flags} $| <?> $1
dnl accept unqualified sender: change mark to avoid test
-R$* u $* $| <?> $* $: <OK> $3
+R$* u $* $| <?> $* $: <_RES_OK_> $3
dnl remove daemon_flags
R$* $| $* $: $2
R<?> $* $: < ? $&{client_name} > $1
R<?> $* $@ <OK> ...local unqualed ok
-R<? $+> $* $#error $@ 5.5.4 $: "CODE553 Domain name required for sender address " $&f
+R<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
...remote is not')
# check results
R<?> $* $: @ $1 mark address: nothing known about it
-R<OK> $* $@ <OK>
+R<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop
R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
-R<PERM> $* $#error $@ 5.1.8 $: "CODE553 Domain of sender address " $&f " does not exist"
+R<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
ifdef(`_ACCESS_TABLE_', `dnl
-R<$={Accept}> $* $# $1
+R<$={Accept}> $* $# $1 accept from access map
R<DISCARD> $* $#discard $: discard
+ifdef(`_FFR_QUARANTINE',
+`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl')
R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
dnl error tag
R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
R<ERROR:$+> $* $#error $: $1
+ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
dnl generic error from access map
R<$+> $* $#error $: $1 error from access db',
`dnl')
@@ -1608,27 +1860,76 @@ R$* $| $#$* $#$2
R$* $| $* $@ $>"Basic_check_rcpt" $1
SBasic_check_rcpt
+# empty address?
+R<> $#error $@ nouser $: "553 User address required"
+R$@ $#error $@ nouser $: "553 User address required"
# check for deferred delivery mode
R$* $: < ${deliveryMode} > $1
R< d > $* $@ deferred
R< $* > $* $: $2
ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
-# require qualified recipient?
+dnl this code checks for user@host where host is not a FQHN.
+dnl it is not activated.
+dnl notice: code to check for a recipient without a domain name is
+dnl available down below; look for the same macro.
+dnl this check is done here because the name might be qualified by the
+dnl canonicalization.
+# require fully qualified domain part?
+dnl very simple canonification: make sure the address is in < >
R$+ $: <?> $1
-R<?><$+> $: <@> <$1>
-R<?>$+ $: <@> <$1>
+R<?> <$+> $: <@> <$1>
+R<?> $+ $: <@> <$1>
+R<@> < postmaster > $: postmaster
+R<@> < $* @ $+ . $+ > $: < $3 @ $4 . $5 >
dnl prepend daemon_flags
-R$* $: $&{daemon_flags} $| $1
+R<@> $* $: $&{daemon_flags} $| <@> $1
dnl workspace: ${daemon_flags} $| <@> <address>
dnl do not allow these at all or only from local systems?
-R$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 >
+R$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 >
R<?> < $* > $: <$1>
R<? $=w> < $* > $: <$1>
-R<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required"
+R<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required"
dnl remove daemon_flags for other cases
R$* $| <@> $* $: $2', `dnl')
+dnl ##################################################################
+dnl call subroutines for recipient and relay
+dnl possible returns from subroutines:
+dnl $#TEMP temporary failure
+dnl $#error permanent failure (or temporary if from access map)
+dnl $#other stop processing
+dnl RELAY RELAYing allowed
+dnl other otherwise
+######################################################################
+R$* $: $1 $| @ $>"Rcpt_ok" $1
+dnl temporary failure? remove mark @ and remember
+R$* $| @ $#TEMP $+ $: $1 $| T $2
+dnl error or ok (stop)
+R$* $| @ $#$* $#$2
+ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
+R$* $| @ RELAY $@ RELAY
+dnl something else: call check sender (relay)
+R$* $| @ $* $: O $| $>"Relay_ok" $1
+dnl temporary failure: call check sender (relay)
+R$* $| T $+ $: T $2 $| $>"Relay_ok" $1
+dnl temporary failure? return that
+R$* $| $#TEMP $+ $#error $2
+dnl error or ok (stop)
+R$* $| $#$* $#$2
+R$* $| RELAY $@ RELAY
+dnl something else: return previous temp failure
+R T $+ $| $* $#error $1
+# anything else is bogus
+R$* $#error $@ 5.7.1 $: confRELAY_MSG
+divert(0)
+
+######################################################################
+### Rcpt_ok: is the recipient ok?
+dnl input: recipient address (RCPT TO)
+dnl output: see explanation at call
+######################################################################
+SRcpt_ok
ifdef(`_LOOSE_RELAY_CHECK_',`dnl
R$* $: $>CanonAddr $1
R$* < @ $* . > $1 < @ $2 > strip trailing dots',
@@ -1641,7 +1942,7 @@ R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3',
`dnl
# limit bestmx to $=B
R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
-R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3
+R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3
R$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4
R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4')
@@ -1651,50 +1952,60 @@ ifdef(`_ACCESS_TABLE_', `dnl
R$* $: <?> $1
dnl user is now tagged with @ to be consistent with check_mail
dnl and to distinguish users from hosts (com would be host, com@ would be user)
-R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2>
-R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2>
+R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
+R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
R<?> $+ $: <> <$1> $| <U:$1@>
dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
dnl will only return user<@domain when "reversing" the args
-R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <>
+R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
R<@> <$*> $| <$*> $: <$2> <$1> reverse result
R<?> <$*> $: @ $1 mark address as no match
+dnl we may have to filter here because otherwise some RHSs
+dnl would be interpreted as generic error messages...
+dnl error messages should be "tagged" by prefixing them with error: !
+dnl that would make a lot of things easier.
R<$={Accept}> <$*> $: @ $2 mark address as no match
-ifdef(`_DELAY_CHECKS_',`dnl
+ifdef(`_ACCESS_SKIP_', `dnl
+R<SKIP> <$*> $: @ $1 mark address as no match', `dnl')
+ifdef(`_DELAY_COMPAT_8_10_',`dnl
+dnl compatility with 8.11/8.10:
dnl we have to filter these because otherwise they would be interpreted
dnl as generic error message...
dnl error messages should be "tagged" by prefixing them with error: !
dnl that would make a lot of things easier.
dnl maybe we should stop checks already here (if SPAM_xyx)?
R<$={SpamTag}> <$*> $: @ $2 mark address as no match')
-R<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
+R<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG
R<DISCARD> $* $#discard $: discard
+ifdef(`_FFR_QUARANTINE',
+`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl')
dnl error tag
R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
R<ERROR:$+> $* $#error $: $1
+ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
dnl generic error from access map
R<$+> $* $#error $: $1 error from access db
R@ $* $1 remove mark', `dnl')', `dnl')
-ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)')
-# authenticated?
-dnl do this unconditionally? this requires to manage CAs carefully
-dnl just because someone has a CERT signed by a "trusted" CA
-dnl does not mean we want to allow relaying for her,
-dnl either use a subroutine or provide something more sophisticated
-dnl this could for example check the DN (maybe an access map lookup)
-R$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated?
-R$* $| $# $+ $# $2 error/ok?
-R$* $| $* $: $1 no
-
-# authenticated by a trusted mechanism?
-R$* $: $1 $| $&{auth_type}
+ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
+# authenticated via TLS?
+R$* $: $1 $| $>RelayTLS client authenticated?
+R$* $| $# $+ $# $2 error/ok?
+R$* $| $* $: $1 no
+
+R$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type}
+dnl workspace: localpart<@domain> $| result of Local_Relay_Auth
+R$* $| $# $* $# $2
+dnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
+R$* $| NO $: $1
+R$* $| $* $: $1 $| $&{auth_type}
+dnl workspace: localpart<@domain> [ $| ${auth_type} ]
dnl empty ${auth_type}?
R$* $| $: $1
dnl mechanism ${auth_type} accepted?
dnl use $# to override further tests (delay_checks): see check_rcpt below
-R$* $| $={TrustAuthMech} $# RELAYAUTH
-dnl undo addition of ${auth_type}
+R$* $| $={TrustAuthMech} $# RELAY
+dnl remove ${auth_type}
R$* $| $* $: $1
dnl workspace: localpart<@domain> | localpart
ifelse(defn(`_NO_UUCP_'), `r',
@@ -1702,20 +2013,21 @@ ifelse(defn(`_NO_UUCP_'), `r',
R$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl')
# anything terminating locally is ok
ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
-R$+ < @ $* $=m > $@ RELAYTO', `dnl')
-R$+ < @ $=w > $@ RELAYTO
+R$+ < @ $* $=m > $@ RELAY', `dnl')
+R$+ < @ $=w > $@ RELAY
ifdef(`_RELAY_HOSTS_ONLY_',
-`R$+ < @ $=R > $@ RELAYTO
+`R$+ < @ $=R > $@ RELAY
ifdef(`_ACCESS_TABLE_', `dnl
R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
-`R$+ < @ $* $=R > $@ RELAYTO
+`R$+ < @ $* $=R > $@ RELAY
ifdef(`_ACCESS_TABLE_', `dnl
-R$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')')
+R$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
ifdef(`_ACCESS_TABLE_', `dnl
dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
-R<RELAY> $* $@ RELAYTO
+R<RELAY> $* $@ RELAY
+ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
R<$*> <$*> $: $2',`dnl')
@@ -1723,8 +2035,8 @@ ifdef(`_RELAY_MX_SERVED_', `dnl
# allow relaying for hosts which we MX serve
R$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 >
dnl this must not necessarily happen if the client is checked first...
-R< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
-R<$* : $=w . : $*> $* $@ RELAYTO
+R< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
+R<$* : $=w . : $*> $* $@ RELAY
R< : $* : > $* $: $2',
`dnl')
@@ -1737,7 +2049,7 @@ dnl but we should accept it anyway (maybe making it an option:
dnl RequireFQDN ?)
dnl postmaster must be accepted without domain (DRUMS)
ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
-R<?> postmaster $@ TOPOSTMASTER
+R<?> postmaster $@ OK
# require qualified recipient?
dnl prepend daemon_flags
R<?> $+ $: $&{daemon_flags} $| <?> $1
@@ -1747,31 +2059,38 @@ dnl r flag? add client_name
R$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3
dnl no r flag: relay to local user (only local part)
# no qualified recipient required
-R$* $| <?> $+ $@ RELAYTOLOCAL
+R$* $| <?> $+ $@ RELAY
dnl client_name is empty
-R<?> <?> $+ $@ RELAYTOLOCAL
+R<?> <?> $+ $@ RELAY
dnl client_name is local
-R<? $=w> <?> $+ $@ RELAYTOLOCAL
+R<? $=w> <?> $+ $@ RELAY
dnl client_name is not local
R<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl
dnl no qualified recipient required
-R<?> $+ $@ RELAYTOLOCAL')
+R<?> $+ $@ RELAY')
dnl it is a remote user: remove mark and then check client
R<$+> $* $: $2
dnl currently the recipient address is not used below
+######################################################################
+### Relay_ok: is the relay/sender ok?
+dnl input: ignored
+dnl output: see explanation at call
+######################################################################
+SRelay_ok
# anything originating locally is ok
# check IP address
R$* $: $&{client_addr}
-R$@ $@ RELAYFROM originated locally
-R0 $@ RELAYFROM originated locally
-R$=R $* $@ RELAYFROM relayable IP address
+R$@ $@ RELAY originated locally
+R0 $@ RELAY originated locally
+R$=R $* $@ RELAY relayable IP address
ifdef(`_ACCESS_TABLE_', `dnl
-R$* $: $>LookUpAddress <$1> <?> <$1> <+Connect>
-R<RELAY> $* $@ RELAYFROM relayable IP address
+R$* $: $>A <$1> <?> <+ Connect> <$1>
+R<RELAY> $* $@ RELAY relayable IP address
+ifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
R<$*> <$*> $: $2', `dnl')
R$* $: [ $1 ] put brackets around it...
-R$=w $@ RELAYFROM ... and see if it is local
+R$=w $@ RELAY ... and see if it is local
ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
@@ -1780,48 +2099,56 @@ dnl input: {client_addr} or something "broken"
dnl just throw the input away; we do not need it.
# check whether FROM is allowed to use system as relay
R$* $: <?> $>CanonAddr $&f
+R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot
ifdef(`_RELAY_LOCAL_FROM_', `dnl
# check whether local FROM is ok
-R<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl')
+R<?> $+ < @ $=w > $@ RELAY FROM local', `dnl')
ifdef(`_RELAY_DB_FROM_', `dnl
-R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot
-R<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <>
-R$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl
-ifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
+R<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<D:$2>') <>
+R<@> <RELAY> $@ RELAY RELAY FROM sender ok
+ifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
+', `dnl
+ifdef(`_RELAY_DB_FROM_DOMAIN_',
+`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
')',
`dnl')
dnl')', `dnl')
+dnl notice: the rulesets above do not leave a unique workspace behind.
+dnl it does not matter in this case because the following rule ignores
+dnl the input. otherwise these rules must "clean up" the workspace.
# check client name: first: did it resolve?
dnl input: ignored
R$* $: < $&{client_resolve} >
-R<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
+R<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
dnl ${client_resolve} should be OK, so go ahead
-R$* $: <?> $&{client_name}
+R$* $: <@> $&{client_name}
+dnl should not be necessary since it has been done for client_addr already
+R<@> $@ RELAY
+dnl workspace: <@> ${client_name} (not empty)
# pass to name server to make hostname canonical
-R<?> $* $~P $:<?> $[ $1 $2 $]
+R<@> $* $=P $:<?> $1 $2
+R<@> $+ $:<?> $[ $1 $]
+dnl workspace: <?> ${client_name} (canonified)
R$* . $1 strip trailing dots
-dnl should not be necessary since it has been done for client_addr already
-R<?> $@ RELAYFROM
ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
-R<?> $* $=m $@ RELAYFROM', `dnl')
-R<?> $=w $@ RELAYFROM
+R<?> $* $=m $@ RELAY', `dnl')
+R<?> $=w $@ RELAY
ifdef(`_RELAY_HOSTS_ONLY_',
-`R<?> $=R $@ RELAYFROM
+`R<?> $=R $@ RELAY
ifdef(`_ACCESS_TABLE_', `dnl
R<?> $* $: <$(access Connect:$1 $: ? $)> <$1>
R<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')',
-`R<?> $* $=R $@ RELAYFROM
+`R<?> $* $=R $@ RELAY
ifdef(`_ACCESS_TABLE_', `dnl
-R<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')')
+R<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
ifdef(`_ACCESS_TABLE_', `dnl
-R<RELAY> $* $@ RELAYFROM
+R<RELAY> $* $@ RELAY
+ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
R<$*> <$*> $: $2',`dnl')
-
-# anything else is bogus
-R$* $#error $@ 5.7.1 $: confRELAY_MSG
+dnl end of _PROMISCUOUS_RELAY_
divert(0)
ifdef(`_DELAY_CHECKS_',`dnl
# turn a canonical address in the form user<@domain>
@@ -1849,11 +2176,11 @@ ifdef(`_ACCESS_TABLE_', `',
dnl one of the next two rules is supposed to match
dnl this code has been copied from BLACKLIST... etc
dnl and simplified by omitting some < >.
-R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@>
-R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 >
+R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
+R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
dnl R<?> $@ something_is_very_wrong_here
-# lookup the addresses only with To tag
-R<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <>
+# lookup the addresses only with Spam tag
+R<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
R<@> $* $| $* $: $2 $1 reverse result
dnl', `dnl')
ifdef(`_SPAM_FRIEND_',
@@ -1861,24 +2188,163 @@ ifdef(`_SPAM_FRIEND_',
ifdef(`_SPAM_HATER_',
`errprint(`*** ERROR: define either SpamHater or SpamFriend
')', `dnl')
-R<SPAMFRIEND> $+ $@ SPAMFRIEND
+R<FRIEND> $+ $@ SPAMFRIEND
R<$*> $+ $: $2',
`dnl')
ifdef(`_SPAM_HATER_',
`# is the recipient no spam hater?
-R<SPAMHATER> $+ $: $1 spam hater: continue checks
+R<HATER> $+ $: $1 spam hater: continue checks
R<$*> $+ $@ NOSPAMHATER everyone else: stop
dnl',`dnl')
dnl run further checks: check_mail
dnl should we "clean up" $&f?
-R$* $: $1 $| $>checkmail <$&f>
+ifdef(`_FFR_MAIL_MACRO',
+`R$* $: $1 $| $>checkmail $&{mail_from}',
+`R$* $: $1 $| $>checkmail <$&f>')
R$* $| $#$* $#$2
dnl run further checks: check_relay
R$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
R$* $| $#$* $#$2
R$* $| $* $: $1
', `dnl')
-ifdef(`_ACCESS_TABLE_', `dnl
+
+ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
+######################################################################
+### F: LookUpFull -- search for an entry in access database
+###
+### lookup of full key (which should be an address) and
+### variations if +detail exists: +* and without +detail
+###
+### Parameters:
+### <$1> -- key
+### <$2> -- default (what to return if not found in db)
+dnl must not be empty
+### <$3> -- mark (must be <(!|+) single-token>)
+### ! does lookup only with tag
+### + does lookup with and without tag
+### <$4> -- passthru (additional data passed unchanged through)
+dnl returns: <default> <passthru>
+dnl <result> <passthru>
+######################################################################
+
+SF
+dnl workspace: <key> <def> <o tag> <thru>
+dnl full lookup
+dnl 2 3 4 5
+R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+dnl no match, try without tag
+dnl 1 2 3 4
+R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+dnl no match, +detail: try +*
+dnl 1 2 3 4 5 6 7
+R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
+ $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
+dnl no match, +detail: try +* without tag
+dnl 1 2 3 4 5 6
+R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
+ $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
+dnl no match, +detail: try without +detail
+dnl 1 2 3 4 5 6 7
+R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
+ $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
+dnl no match, +detail: try without +detail and without tag
+dnl 1 2 3 4 5 6
+R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
+ $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
+dnl no match, return <default> <passthru>
+dnl 1 2 3 4 5
+R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
+ifdef(`_ATMPF_', `dnl tempfail?
+dnl 2 3 4 5
+R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
+dnl match, return <match> <passthru>
+dnl 2 3 4 5
+R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
+
+######################################################################
+### E: LookUpExact -- search for an entry in access database
+###
+### Parameters:
+### <$1> -- key
+### <$2> -- default (what to return if not found in db)
+dnl must not be empty
+### <$3> -- mark (must be <(!|+) single-token>)
+### ! does lookup only with tag
+### + does lookup with and without tag
+### <$4> -- passthru (additional data passed unchanged through)
+dnl returns: <default> <passthru>
+dnl <result> <passthru>
+######################################################################
+
+SE
+dnl 2 3 4 5
+R<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+dnl no match, try without tag
+dnl 1 2 3 4
+R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+dnl no match, return default passthru
+dnl 1 2 3 4 5
+R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
+ifdef(`_ATMPF_', `dnl tempfail?
+dnl 2 3 4 5
+R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
+dnl match, return <match> <passthru>
+dnl 2 3 4 5
+R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
+
+######################################################################
+### U: LookUpUser -- search for an entry in access database
+###
+### lookup of key (which should be a local part) and
+### variations if +detail exists: +* and without +detail
+###
+### Parameters:
+### <$1> -- key (user@)
+### <$2> -- default (what to return if not found in db)
+dnl must not be empty
+### <$3> -- mark (must be <(!|+) single-token>)
+### ! does lookup only with tag
+### + does lookup with and without tag
+### <$4> -- passthru (additional data passed unchanged through)
+dnl returns: <default> <passthru>
+dnl <result> <passthru>
+######################################################################
+
+SU
+dnl user lookups are always with trailing @
+dnl 2 3 4 5
+R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+dnl no match, try without tag
+dnl 1 2 3 4
+R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+dnl do not remove the @ from the lookup:
+dnl it is part of the +detail@ which is omitted for the lookup
+dnl no match, +detail: try +*
+dnl 1 2 3 4 5 6
+R<?> <$+ + $* @> <$*> <$- $-> <$*>
+ $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
+dnl no match, +detail: try +* without tag
+dnl 1 2 3 4 5
+R<?> <$+ + $* @> <$*> <+ $-> <$*>
+ $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
+dnl no match, +detail: try without +detail
+dnl 1 2 3 4 5 6
+R<?> <$+ + $* @> <$*> <$- $-> <$*>
+ $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
+dnl no match, +detail: try without +detail and without tag
+dnl 1 2 3 4 5
+R<?> <$+ + $* @> <$*> <+ $-> <$*>
+ $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
+dnl no match, return <default> <passthru>
+dnl 1 2 3 4 5
+R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
+ifdef(`_ATMPF_', `dnl tempfail?
+dnl 2 3 4 5
+R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
+dnl match, return <match> <passthru>
+dnl 2 3 4 5
+R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
+
######################################################################
### SearchList: search a list of items in the access map
### Parameters:
@@ -1887,7 +2353,7 @@ dnl maybe we should have a @ (again) in front of the mark to
dnl avoid errorneous matches (with error messages?)
dnl if we can make sure that tag is always a single token
dnl then we can omit the delimiter $|, otherwise we need it
-dnl to avoid errorneous matchs (first rule: H: if there
+dnl to avoid errorneous matchs (first rule: D: if there
dnl is that mark somewhere in the list, it will be taken).
dnl moreover, we can do some tricks to enforce lookup with
dnl the tag only, e.g.:
@@ -1897,7 +2363,7 @@ dnl the tag only, e.g.:
dnl Warning: + and ! should be in OperatorChars (otherwise there must be
dnl a blank between them and the tag.
### possible values for "mark" are:
-### H: recursive host lookup (LookUpDomain)
+### D: recursive host lookup (LookUpDomain)
dnl A: recursive address lookup (LookUpAddress) [not yet required]
### E: exact lookup, no modifications
### F: full lookup, try user+ext@domain and user@domain
@@ -1907,42 +2373,32 @@ dnl A: recursive address lookup (LookUpAddress) [not yet required]
# class with valid marks for SearchList
dnl if A is activated: add it
-C{src}E F H U
+C{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
SSearchList
-# mark H: lookup domain
-R<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1>
-R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3>
-dnl A: NOT YET REQUIRED
-dnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1>
-dnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3>
-dnl lookup of the item with tag
-dnl this applies to F: U: E:
-R<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5>
-dnl no match, try without tag
-R<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4>
-dnl do we really have to distinguish these cases?
-dnl probably yes, there might be a + in the domain part (is that allowed?)
-dnl user+detail lookups: should it be:
-dnl user+detail, user+*, user; just like aliases?
-R<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6>
-R<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5>
-dnl user lookups are always with trailing @
-dnl do not remove the @ from the lookup:
-dnl it is part of the +detail@ which is omitted for the lookup
-R<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5>
-dnl no match, try without tag
-R<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4>
-dnl no match, try rest of list
-R<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4>
-dnl no match, list empty: return failure
-R<$+> $| <$={src}:$+> <> $@ <?>
-dnl got result, return it
-R<$+> $| <$+> <$*> $@ <$2>
+# just call the ruleset with the name of the tag... nice trick...
+dnl 2 3 4
+R<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
+dnl workspace: <o tag> $| <rest> $| <result of lookup> <>
+dnl no match and nothing left: return
+R<$+> $| <> $| <?> <> $@ <?>
+dnl no match but something left: continue
+R<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2>
+dnl match: return
+R<$+> $| <$*> $| <$+> <> $@ <$3>
dnl return result from recursive invocation
-R<$+> $| <$+> $@ <$2>', `dnl')
+R<$+> $| <$+> $@ <$2>
+dnl endif _ACCESS_TABLE_
+divert(0)
+
+######################################################################
+### trust_auth: is user trusted to authenticate as someone else?
+###
+### Parameters:
+### $1: AUTH= parameter from MAIL command
+######################################################################
-# is user trusted to authenticate as someone else?
-dnl AUTH= parameter from MAIL command
+dnl empty ruleset definition so it can be called
+SLocal_trust_auth
Strust_auth
R$* $: $&{auth_type} $| $1
# required by RFC 2554 section 4.
@@ -1956,111 +2412,288 @@ R$* $| $#$* $#$2
dnl default: error
R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
-dnl empty ruleset definition so it can be called
-SLocal_trust_auth
+######################################################################
+### Relay_Auth: allow relaying based on authentication?
+###
+### Parameters:
+### $1: ${auth_type}
+######################################################################
+SLocal_Relay_Auth
-ifdef(`_FFR_TLS_O_T', `dnl
-Soffer_tls
-R$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG>
-R<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG>
-R<?>$* $: <$(access TLS_OFF_TAG: $: ? $)>
+ifdef(`_ACCESS_TABLE_', `dnl
+######################################################################
+### srv_features: which features to offer to a client?
+### (done in server)
+######################################################################
+Ssrv_features
+ifdef(`_LOCAL_SRV_FEATURES_', `dnl
+R$* $: $1 $| $>"Local_srv_features" $1
+R$* $| $#$* $#$2
+R$* $| $* $: $1', `dnl')
+R$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
+R<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
+R<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
R<?>$* $@ OK
-R<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]"
+ifdef(`_ATMPF_', `dnl tempfail?
+R<$* _ATMPF_>$* $#temp', `dnl')
+R<$+>$* $# $1
+######################################################################
+### try_tls: try to use STARTTLS?
+### (done in client)
+######################################################################
Stry_tls
-R$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG>
-R<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG>
-R<?>$* $: <$(access TLS_TRY_TAG: $: ? $)>
+ifdef(`_LOCAL_TRY_TLS_', `dnl
+R$* $: $1 $| $>"Local_try_tls" $1
+R$* $| $#$* $#$2
+R$* $| $* $: $1', `dnl')
+R$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
+R<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
+R<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
R<?>$* $@ OK
+ifdef(`_ATMPF_', `dnl tempfail?
+R<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
R<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
-')dnl
+
+######################################################################
+### tls_rcpt: is connection with server "good" enough?
+### (done in client, per recipient)
+dnl called from deliver() before RCPT command
+###
+### Parameters:
+### $1: recipient
+######################################################################
+Stls_rcpt
+ifdef(`_LOCAL_TLS_RCPT_', `dnl
+R$* $: $1 $| $>"Local_tls_rcpt" $1
+R$* $| $#$* $#$2
+R$* $| $* $: $1', `dnl')
+dnl store name of other side
+R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1
+dnl canonify recipient address
+R$+ $: <?> $>CanonAddr $1
+dnl strip trailing dots
+R<?> $+ < @ $+ . > <?> $1 <@ $2 >
+dnl full address?
+R<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
+dnl only localpart?
+R<?> $+ $: $1 $| <U:$1@> <E:>
+dnl look it up
+dnl also look up a default value via E:
+R$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
+dnl found nothing: stop here
+R$* $| <?> $@ OK
+ifdef(`_ATMPF_', `dnl tempfail?
+R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
+dnl use the generic routine (for now)
+R$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>')
-# is connection with client "good" enough? (done in server)
-# input: ${verify} $| (MAIL|STARTTLS)
+######################################################################
+### tls_client: is connection with client "good" enough?
+### (done in server)
+###
+### Parameters:
+### ${verify} $| (MAIL|STARTTLS)
+######################################################################
dnl MAIL: called from check_mail
dnl STARTTLS: called from smtp() after STARTTLS has been accepted
Stls_client
+ifdef(`_LOCAL_TLS_CLIENT_', `dnl
+R$* $: $1 $| $>"Local_tls_client" $1
+R$* $| $#$* $#$2
+R$* $| $* $: $1', `dnl')
ifdef(`_ACCESS_TABLE_', `dnl
+dnl store name of other side
+R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1
dnl ignore second arg for now
dnl maybe use it to distinguish permanent/temporary error?
dnl if MAIL: permanent (STARTTLS has not been offered)
dnl if STARTTLS: temporary (offered but maybe failed)
-R$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG>
-R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG>
+R$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
+R$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
dnl do a default lookup: just TLS_CLT_TAG
R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
-R$* $@ $>"tls_connection" $1', `dnl
-R$* $| $* $@ $>"tls_connection" $1')
+ifdef(`_ATMPF_', `dnl tempfail?
+R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
+R$* $@ $>"TLS_connection" $1', `dnl
+R$* $| $* $@ $>"TLS_connection" $1')
-# is connection with server "good" enough? (done in client)
+######################################################################
+### tls_server: is connection with server "good" enough?
+### (done in client)
+###
+### Parameter:
+### ${verify}
+######################################################################
dnl i.e. has the server been authenticated and is encryption active?
dnl called from deliver() after STARTTLS command
-# input: ${verify}
Stls_server
+ifdef(`_LOCAL_TLS_SERVER_', `dnl
+R$* $: $1 $| $>"Local_tls_server" $1
+R$* $| $#$* $#$2
+R$* $| $* $: $1', `dnl')
ifdef(`_ACCESS_TABLE_', `dnl
-R$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG>
-R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG>
+dnl store name of other side
+R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1
+R$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
+R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
dnl do a default lookup: just TLS_SRV_TAG
R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
-R$* $@ $>"tls_connection" $1', `dnl
-R$* $@ $>"tls_connection" $1')
+ifdef(`_ATMPF_', `dnl tempfail?
+R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
+R$* $@ $>"TLS_connection" $1', `dnl
+R$* $@ $>"TLS_connection" $1')
-Stls_connection
+######################################################################
+### TLS_connection: is TLS connection "good" enough?
+###
+### Parameters:
ifdef(`_ACCESS_TABLE_', `dnl
+### ${verify} $| <Requirement> [<>]', `dnl
+### ${verify}')
+### Requirement: RHS from access map, may be ? for none.
+dnl syntax for Requirement:
+dnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
+dnl extensions: could be a list of further requirements
+dnl for now: CN:string {cn_subject} == string
+######################################################################
+STLS_connection
+ifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
+dnl deal with TLS handshake failures: abort
+RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
+divert(-1)')
dnl common ruleset for tls_{client|server}
-dnl input: $&{verify} $| <ResultOfLookup> [<>]
+dnl input: ${verify} $| <ResultOfLookup> [<>]
dnl remove optional <>
R$* $| <$*>$* $: $1 $| <$2>
+dnl workspace: ${verify} $| <ResultOfLookup>
+# create the appropriate error codes
dnl permanent or temporary error?
R$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3>
R$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3>
dnl default case depends on TLS_PERM_ERR
R$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
-dnl deal with TLS handshake failures: abort
+dnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
+# deal with TLS handshake failures: abort
RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed."
dnl no <reply:dns> i.e. not requirements in the access map
dnl use default error
RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
-R$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1
-R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1
+R$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1
+dnl separate optional requirements
+R$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1
+R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1
+dnl separate optional requirements
+R$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1
dnl some other value in access map: accept
dnl this also allows to override the default case (if used)
R$* $| $* $@ OK
# authentication required: give appropriate error
# other side did authenticate (via STARTTLS)
-dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify}
+dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
dnl only verification required and it succeeded
-R<$*><VERIFY> OK $@ OK
+R<$*><VERIFY> <> OK $@ OK
+dnl verification required and it succeeded but extensions are given
+dnl change it to <SMTP:ESC> <REQ:0> <extensions>
+R<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2>
dnl verification required + some level of encryption
-R<$*><VERIFY:$-> OK $: <$1> <REQ:$2>
+R<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3>
dnl just some level of encryption required
-R<$*><ENCR:$-> $* $: <$1> <REQ:$2>
-dnl verification required but ${verify} is not set
-R<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required"
-R<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed"
-R<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated"
-R<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS"
+R<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3>
+dnl workspace:
+dnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK)
+dnl 2. <SMTP:ESC> <REQ:bits> <[extensions]>
+dnl verification required but ${verify} is not set (case 1.)
+R<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required"
+R<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed"
+R<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated"
+R<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested"
+R<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS"
dnl some other value for ${verify}
-R<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4
-dnl some level of encryption required: get the maximum level
-R<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf}
+R<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4
+dnl some level of encryption required: get the maximum level (case 2.)
+R<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
dnl compare required bits with actual bits
-R<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $)
-R<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
+R<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
+R<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
+dnl strength requirements fulfilled
+dnl TLS Additional Requirements Separator
+dnl this should be something which does not appear in the extensions itself
+dnl @ could be part of a CN, DN, etc...
+dnl use < > ? those are encoded in CN, DN, ...
+define(`_TLS_ARS_', `++')dnl
+dnl workspace:
+dnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
+R<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5>
+dnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
+dnl continue: check extensions
+R<$-:$+ _TLS_ARS_ > $@ OK
+dnl split extensions into own list
+R<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3>
+R<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4>
+R<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2>
+######################################################################
+### TLS_req: check additional TLS requirements
+###
+### Parameters: [<list> <of> <req>] $| <$-:$+>
+### $-: SMTP reply code
+### $+: Enhanced Status Code
+dnl further requirements for this ruleset:
+dnl name of "other side" is stored is {TLS_name} (client/server_name)
+dnl
+dnl currently only CN[:common_name] is implemented
+dnl right now this is only a logical AND
+dnl i.e. all requirements must be true
+dnl how about an OR? CN must be X or CN must be Y or ..
+dnl use a macro to compute this as a trivial sequential
+dnl operations (no precedences etc)?
+######################################################################
+STLS_req
+dnl no additional requirements: ok
+R $| $+ $@ OK
+dnl require CN: but no CN specified: use name of other side
+R<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2>
+dnl match, check rest
+R<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
+dnl CN does not match
+dnl 1 2 3 4
+R<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
+dnl cert subject
+R<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
+dnl CS does not match
+dnl 1 2 3 4
+R<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
+dnl match, check rest
+R<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
+dnl CI does not match
+dnl 1 2 3 4
+R<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
+dnl return from recursive call
+ROK $@ OK
+
+######################################################################
+### max: return the maximum of two values separated by :
+###
+### Parameters: [$-]:[$-]
+######################################################################
Smax
-dnl compute the max of two values separated by :
R: $: 0
R:$- $: $1
R$-: $: $1
R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2
RTRUE:$-:$- $: $2
-R$-:$-:$- $: $2',
-`dnl use default error
-dnl deal with TLS handshake failures: abort
-RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."')
+R$-:$-:$- $: $2
+dnl endif _ACCESS_TABLE_
+divert(0)
-SRelayAuth
+######################################################################
+### RelayTLS: allow relaying based on TLS authentication
+###
+### Parameters:
+### none
+######################################################################
+SRelayTLS
# authenticated?
dnl we do not allow relaying for anyone who can present a cert
dnl signed by a "trusted" CA. For example, even if we put verisigns
@@ -2073,24 +2706,54 @@ dnl (maybe after extracting a part with a regular expression)
dnl if this returns RELAY we relay without further questions
dnl if it returns SUBJECT we perform a similar check on the
dnl cert subject.
-R$* $| OK $: $1
-R$* $| $* $@ NO not authenticated
ifdef(`_ACCESS_TABLE_', `dnl
+R$* $: <?> $&{verify}
+R<?> OK $: OK authenticated: continue
+R<?> $* $@ NO not authenticated
ifdef(`_CERT_REGEX_ISSUER_', `dnl
-R$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)',
-`R$* $: $1 $| $&{cert_issuer}')
-R$* $| $+ $: $1 $| $(access CERTISSUER:$2 $)
+R$* $: $(CERTIssuer $&{cert_issuer} $)',
+`R$* $: $&{cert_issuer}')
+R$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
dnl use $# to stop further checks (delay_check)
-R$* $| RELAY $# RELAYCERTISSUER
+RRELAY $# RELAY
ifdef(`_CERT_REGEX_SUBJECT_', `dnl
-R$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)',
-`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}')
-R$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $)
-R$* $| <@> RELAY $# RELAYCERTSUBJECT
-R$* $| $* $: $1', `dnl')
+RSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)',
+`RSUBJECT $: <@> $&{cert_subject}')
+R<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
+R<@> RELAY $# RELAY
+R$* $: NO', `dnl')
+
+######################################################################
+### authinfo: lookup authinfo in the access map
+###
+### Parameters:
+### $1: {server_name}
+### $2: {server_addr}
+dnl both are currently ignored
+dnl if it should be done via another map, we either need to restrict
+dnl functionality (it calls D and A) or copy those rulesets (or add another
+dnl parameter which I want to avoid, it's quite complex already)
+######################################################################
+dnl omit this ruleset if neither is defined?
+dnl it causes DefaultAuthInfo to be ignored
+dnl (which may be considered a good thing).
+Sauthinfo
+ifdef(`_AUTHINFO_TABLE_', `dnl
+R$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
+R<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
+R<?> $: <$(authinfo AuthInfo: $: ? $)>
+R<?> $@ no no authinfo available
+R<$*> $# $1
+dnl', `dnl
+ifdef(`_ACCESS_TABLE_', `dnl
+R$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
+R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
+R$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
+R$* $| <?>$* $@ no no authinfo available
+R$* $| <$*> <> $# $2
+dnl', `dnl')')
undivert(9)dnl LOCAL_RULESETS
-ifdef(`_FFR_MILTER', `
#
######################################################################
######################################################################
@@ -2099,7 +2762,7 @@ ifdef(`_FFR_MILTER', `
#####
######################################################################
######################################################################
-_MAIL_FILTERS_')
+_MAIL_FILTERS_
#
######################################################################
######################################################################
diff --git a/contrib/sendmail/cf/m4/version.m4 b/contrib/sendmail/cf/m4/version.m4
index adc2c2c..ed123cc 100644
--- a/contrib/sendmail/cf/m4/version.m4
+++ b/contrib/sendmail/cf/m4/version.m4
@@ -1,6 +1,6 @@
divert(-1)
#
-# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -11,8 +11,8 @@ divert(-1)
# the sendmail distribution.
#
#
-VERSIONID(`$Id: version.m4,v 8.39.4.35 2001/08/20 14:45:34 gshapiro Exp $')
+VERSIONID(`$Id: version.m4,v 8.81 2002/01/13 18:23:32 ca Exp $')
#
divert(0)
# Configuration version number
-DZ8.11.6`'ifdef(`confCF_VERSION', `/confCF_VERSION')
+DZ8.12.2`'ifdef(`confCF_VERSION', `/confCF_VERSION')
diff --git a/contrib/sendmail/cf/mailer/cyrus.m4 b/contrib/sendmail/cf/mailer/cyrus.m4
index a6afa4a..cca7f8e 100644
--- a/contrib/sendmail/cf/mailer/cyrus.m4
+++ b/contrib/sendmail/cf/mailer/cyrus.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -35,15 +35,13 @@ PUSHDIVERT(-1)
# Contributed to Berkeley by John Gardiner Myers <jgm+@CMU.EDU>.
#
-ifdef(`_MAILER_local_', `',
- `errprint(`*** MAILER(`local') must appear before MAILER(`cyrus')')')dnl
-
_DEFIFNOT(`CYRUS_MAILER_FLAGS', `Ah5@/:|')
ifdef(`CYRUS_MAILER_PATH',, `define(`CYRUS_MAILER_PATH', /usr/cyrus/bin/deliver)')
ifdef(`CYRUS_MAILER_ARGS',, `define(`CYRUS_MAILER_ARGS', `deliver -e -m $h -- $u')')
ifdef(`CYRUS_MAILER_USER',, `define(`CYRUS_MAILER_USER', `cyrus:mail')')
_DEFIFNOT(`CYRUS_BB_MAILER_FLAGS', `u')
ifdef(`CYRUS_BB_MAILER_ARGS',, `define(`CYRUS_BB_MAILER_ARGS', `deliver -e -m $u')')
+define(`_CYRUS_QGRP', `ifelse(defn(`CYRUS_MAILER_QGRP'),`',`', ` Q=CYRUS_MAILER_QGRP,')')dnl
POPDIVERT
@@ -51,12 +49,12 @@ POPDIVERT
### Cyrus Mailer specification ###
##################################################
-VERSIONID(`$Id: cyrus.m4,v 8.21 1999/10/18 04:57:52 gshapiro Exp $ (Carnegie Mellon)')
+VERSIONID(`$Id: cyrus.m4,v 8.23 2001/11/12 23:11:34 ca Exp $ (Carnegie Mellon)')
Mcyrus, P=CYRUS_MAILER_PATH, F=_MODMF_(CONCAT(`lsDFMnPq', CYRUS_MAILER_FLAGS), `CYRUS'), S=EnvFromL, R=EnvToL/HdrToL,
- ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, T=DNS/RFC822/X-Unix,
+ ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, T=DNS/RFC822/X-Unix,_CYRUS_QGRP
A=CYRUS_MAILER_ARGS
Mcyrusbb, P=CYRUS_MAILER_PATH, F=_MODMF_(CONCAT(`lsDFMnP', CYRUS_BB_MAILER_FLAGS), `CYRUS'), S=EnvFromL, R=EnvToL/HdrToL,
- ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, T=DNS/RFC822/X-Unix,
+ ifdef(`CYRUS_MAILER_MAX', `M=CYRUS_MAILER_MAX, ')U=CYRUS_MAILER_USER, T=DNS/RFC822/X-Unix,_CYRUS_QGRP
A=CYRUS_BB_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/fax.m4 b/contrib/sendmail/cf/mailer/fax.m4
index 63c6931..4e2116e 100644
--- a/contrib/sendmail/cf/mailer/fax.m4
+++ b/contrib/sendmail/cf/mailer/fax.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -22,15 +22,16 @@ ifdef(`FAX_MAILER_PATH',,
`define(`FAX_MAILER_PATH', /usr/local/bin/faxmail)')
ifdef(`FAX_MAILER_MAX',,
`define(`FAX_MAILER_MAX', 100000)')
+define(`_FAX_QGRP', `ifelse(defn(`FAX_MAILER_QGRP'),`',`', ` Q=FAX_MAILER_QGRP,')')dnl
POPDIVERT
####################################
### FAX Mailer specification ###
####################################
-VERSIONID(`$Id: fax.m4,v 8.15 1999/10/18 04:57:53 gshapiro Exp $')
+VERSIONID(`$Id: fax.m4,v 8.16 2001/11/12 23:11:34 ca Exp $')
Mfax, P=FAX_MAILER_PATH, F=DFMhu, S=14, R=24,
- M=FAX_MAILER_MAX, T=X-Phone/X-FAX/X-Unix,
+ M=FAX_MAILER_MAX, T=X-Phone/X-FAX/X-Unix,_FAX_QGRP
A=FAX_MAILER_ARGS
LOCAL_CONFIG
diff --git a/contrib/sendmail/cf/mailer/local.m4 b/contrib/sendmail/cf/mailer/local.m4
index 3a0b7fd..c1946c9 100644
--- a/contrib/sendmail/cf/mailer/local.m4
+++ b/contrib/sendmail/cf/mailer/local.m4
@@ -21,65 +21,73 @@ _DEFIFNOT(`LOCAL_SHELL_FLAGS', `eu9')
ifdef(`LOCAL_SHELL_PATH',, `define(`LOCAL_SHELL_PATH', /bin/sh)')
ifdef(`LOCAL_SHELL_ARGS',, `define(`LOCAL_SHELL_ARGS', `sh -c $u')')
ifdef(`LOCAL_SHELL_DIR',, `define(`LOCAL_SHELL_DIR', `$z:/')')
+define(`LOCAL_RWR', `ifdef(`_LOCAL_LMTP_',
+`S=EnvFromSMTP/HdrFromL, R=EnvToL/HdrToL',
+`S=EnvFromL/HdrFromL, R=EnvToL/HdrToL')')
+define(`_LOCAL_QGRP', `ifelse(defn(`LOCAL_MAILER_QGRP'),`',`', ` Q=LOCAL_MAILER_QGRP,')')dnl
+define(`_PROG_QGRP', `ifelse(defn(`LOCAL_PROG_QGRP'),`',`', ` Q=LOCAL_PROG_QGRP,')')dnl
POPDIVERT
##################################################
### Local and Program Mailer specification ###
##################################################
-VERSIONID(`$Id: local.m4,v 8.50.16.2 2000/09/17 17:04:22 gshapiro Exp $')
+VERSIONID(`$Id: local.m4,v 8.58 2000/10/26 01:58:29 ca Exp $')
#
# Envelope sender rewriting
#
-SEnvFromL=10
+SEnvFromL
R<@> $n errors to mailer-daemon
R@ <@ $*> $n temporarily bypass Sun bogosity
R$+ $: $>AddDomain $1 add local domain if needed
-R$* $: $>MasqEnv $1 do masquerading
+ifdef(`_LOCAL_NO_MASQUERADE_', `dnl', `dnl
+R$* $: $>MasqEnv $1 do masquerading')
#
# Envelope recipient rewriting
#
-SEnvToL=20
+SEnvToL
R$+ < @ $* > $: $1 strip host part
-ifdef(`_FFR_ADDR_TYPE', `dnl
-ifdef(`confUSERDB_SPEC', `dnl',
-`dnl Do not forget to bump V9 to V10 before removing _FFR_ADDR_TYPE check
+ifdef(`confUSERDB_SPEC', `dnl', `dnl
R$+ + $* $: < $&{addr_type} > $1 + $2 mark with addr type
R<e s> $+ + $* $: $1 remove +detail for sender
-R< $* > $+ $: $2 else remove mark')', `dnl')
+R< $* > $+ $: $2 else remove mark')
#
# Header sender rewriting
#
-SHdrFromL=30
+SHdrFromL
R<@> $n errors to mailer-daemon
R@ <@ $*> $n temporarily bypass Sun bogosity
R$+ $: $>AddDomain $1 add local domain if needed
-R$* $: $>MasqHdr $1 do masquerading
+ifdef(`_LOCAL_NO_MASQUERADE_', `dnl', `dnl
+R$* $: $>MasqHdr $1 do masquerading')
#
# Header recipient rewriting
#
-SHdrToL=40
+SHdrToL
R$+ $: $>AddDomain $1 add local domain if needed
-ifdef(`_ALL_MASQUERADE_',
-`R$* $: $>MasqHdr $1 do all-masquerading',
+ifdef(`_ALL_MASQUERADE_', `dnl
+ifdef(`_LOCAL_NO_MASQUERADE_', `dnl', `dnl
+R$* $: $>MasqHdr $1 do all-masquerading')',
`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2')
#
# Common code to add local domain name (only if always-add-domain)
#
-SAddDomain=50
+SAddDomain
ifdef(`_ALWAYS_ADD_DOMAIN_', `dnl
R$* < @ $* > $* $@ $1 < @ $2 > $3 already fully qualified
+ifelse(len(X`'_ALWAYS_ADD_DOMAIN_),`1',`
R$+ $@ $1 < @ *LOCAL* > add local qualification',
+`R$+ $@ $1 < @ _ALWAYS_ADD_DOMAIN_ > add qualification')',
`dnl')
-Mlocal, P=LOCAL_MAILER_PATH, F=_MODMF_(CONCAT(_DEF_LOCAL_MAILER_FLAGS, LOCAL_MAILER_FLAGS), `LOCAL'), S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,_OPTINS(`LOCAL_MAILER_EOL', ` E=', `, ')
- _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')_OPTINS(`LOCAL_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`LOCAL_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`LOCAL_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/LOCAL_MAILER_DSN_DIAGNOSTIC_CODE,
+Mlocal, P=LOCAL_MAILER_PATH, F=_MODMF_(CONCAT(_DEF_LOCAL_MAILER_FLAGS, LOCAL_MAILER_FLAGS), `LOCAL'), LOCAL_RWR,_OPTINS(`LOCAL_MAILER_EOL', ` E=', `, ')
+ _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')_OPTINS(`LOCAL_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`LOCAL_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`LOCAL_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/LOCAL_MAILER_DSN_DIAGNOSTIC_CODE,_LOCAL_QGRP
A=LOCAL_MAILER_ARGS
Mprog, P=LOCAL_SHELL_PATH, F=CONCAT(_DEF_LOCAL_SHELL_FLAGS, LOCAL_SHELL_FLAGS), S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=LOCAL_SHELL_DIR,
- _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')T=X-Unix/X-Unix/X-Unix,
+ _OPTINS(`LOCAL_MAILER_MAX', `M=', `, ')T=X-Unix/X-Unix/X-Unix,_PROG_QGRP
A=LOCAL_SHELL_ARGS
diff --git a/contrib/sendmail/cf/mailer/mail11.m4 b/contrib/sendmail/cf/mailer/mail11.m4
index d60a063..14bc794 100644
--- a/contrib/sendmail/cf/mailer/mail11.m4
+++ b/contrib/sendmail/cf/mailer/mail11.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -24,6 +24,7 @@ _DEFIFNOT(`MAIL11_MAILER_FLAGS', `nsFx')
ifdef(`MAIL11_MAILER_ARGS',, `define(`MAIL11_MAILER_ARGS', mail11 $g $x $h $u)')
define(`_USE_DECNET_SYNTAX_')
define(`_LOCAL_', ifdef(`confLOCAL_MAILER', confLOCAL_MAILER, `local'))
+define(`_MAIL11_QGRP', `ifelse(defn(`MAIL11_MAILER_QGRP'),`',`', ` Q=MAIL11_MAILER_QGRP,')')dnl
POPDIVERT
@@ -41,13 +42,9 @@ POPDIVERT
### UTK-MAIL11 Mailer specification ###
###########################################
-VERSIONID(`$Id: mail11.m4,v 8.19 1999/10/18 04:57:54 gshapiro Exp $')
+VERSIONID(`$Id: mail11.m4,v 8.22 2001/11/12 23:11:34 ca Exp $')
-SMail11From=15
-R$+ $: $>25 $1 preprocess
-R$w :: $+ $@ $w :: $1 ready to go
-
-SMail11To=25
+SMail11To
R$+ < @ $- .UUCP > $: $2 ! $1 back to old style
R$+ < @ $- .DECNET > $: $2 :: $1 convert to DECnet style
R$+ < @ $- .LOCAL > $: $2 :: $1 convert to DECnet style
@@ -55,6 +52,10 @@ R$+ < @ $=w. > $: $2 :: $1 convert to DECnet style
R$=w :: $+ $2 strip local names
R$+ :: $+ $@ $1 :: $2 already qualified
+SMail11From
+R$+ $: $>Mail11To $1 preprocess
+R$w :: $+ $@ $w :: $1 ready to go
+
Mmail11, P=MAIL11_MAILER_PATH, F=_MODMF_(MAIL11_MAILER_FLAGS, `MAIL11'), S=Mail11From, R=Mail11To,
- T=DNS/X-DECnet/X-Unix,
+ T=DNS/X-DECnet/X-Unix,_MAIL11_QGRP
A=MAIL11_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/phquery.m4 b/contrib/sendmail/cf/mailer/phquery.m4
index 09032e4..58b71b0 100644
--- a/contrib/sendmail/cf/mailer/phquery.m4
+++ b/contrib/sendmail/cf/mailer/phquery.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -14,12 +14,10 @@ PUSHDIVERT(-1)
# Contributed by Kimmo Suominen <kim@tac.nyc.ny.us>.
#
-ifdef(`_MAILER_local_', `',
- `errprint(`*** MAILER(`local') must appear before MAILER(`phquery')')')dnl
-
ifdef(`PH_MAILER_PATH',, `define(`PH_MAILER_PATH', /usr/local/etc/phquery)')
_DEFIFNOT(`PH_MAILER_FLAGS', `ehmu')
ifdef(`PH_MAILER_ARGS',, `define(`PH_MAILER_ARGS', `phquery -- $u')')
+define(`_PH_QGRP', `ifelse(defn(`PH_MAILER_QGRP'),`',`', ` Q=PH_MAILER_QGRP,')')dnl
POPDIVERT
@@ -27,8 +25,8 @@ POPDIVERT
### PH Mailer specification ###
####################################
-VERSIONID(`$Id: phquery.m4,v 8.15 1999/10/18 04:57:54 gshapiro Exp $')
+VERSIONID(`$Id: phquery.m4,v 8.17 2001/11/12 23:11:34 ca Exp $')
Mph, P=PH_MAILER_PATH, F=_MODMF_(CONCAT(`nrDFM', PH_MAILER_FLAGS), `PH'), S=EnvFromL, R=EnvToL/HdrToL,
- T=DNS/RFC822/X-Unix,
+ T=DNS/RFC822/X-Unix,_PH_QGRP
A=PH_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/pop.m4 b/contrib/sendmail/cf/mailer/pop.m4
index a7b373d..d2680e1 100644
--- a/contrib/sendmail/cf/mailer/pop.m4
+++ b/contrib/sendmail/cf/mailer/pop.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -12,12 +12,10 @@ PUSHDIVERT(-1)
#
#
-ifdef(`_MAILER_local_', `',
- `errprint(`*** MAILER(`local') must appear before MAILER(`pop')')')dnl
-
ifdef(`POP_MAILER_PATH',, `define(`POP_MAILER_PATH', /usr/lib/mh/spop)')
_DEFIFNOT(`POP_MAILER_FLAGS', `Penu')
ifdef(`POP_MAILER_ARGS',, `define(`POP_MAILER_ARGS', `pop $u')')
+define(`_POP_QGRP', `ifelse(defn(`POP_MAILER_QGRP'),`',`', ` Q=POP_MAILER_QGRP,')')dnl
POPDIVERT
@@ -25,10 +23,10 @@ POPDIVERT
### POP Mailer specification ###
####################################
-VERSIONID(`$Id: pop.m4,v 8.20 1999/10/18 04:57:54 gshapiro Exp $')
+VERSIONID(`$Id: pop.m4,v 8.22 2001/11/12 23:11:34 ca Exp $')
Mpop, P=POP_MAILER_PATH, F=_MODMF_(CONCAT(`lsDFMq', POP_MAILER_FLAGS), `POP'), S=EnvFromL, R=EnvToL/HdrToL,
- T=DNS/RFC822/X-Unix,
+ T=DNS/RFC822/X-Unix,_POP_QGRP
A=POP_MAILER_ARGS
LOCAL_CONFIG
diff --git a/contrib/sendmail/cf/mailer/procmail.m4 b/contrib/sendmail/cf/mailer/procmail.m4
index 8589f3a..103e042 100644
--- a/contrib/sendmail/cf/mailer/procmail.m4
+++ b/contrib/sendmail/cf/mailer/procmail.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -12,9 +12,6 @@ PUSHDIVERT(-1)
#
#
-ifdef(`_MAILER_smtp_', `',
- `errprint(`*** MAILER(`smtp') must appear before MAILER(`procmail')')')dnl
-
ifdef(`PROCMAIL_MAILER_PATH',,
`ifdef(`PROCMAIL_PATH',
`define(`PROCMAIL_MAILER_PATH', PROCMAIL_PATH)',
@@ -22,6 +19,7 @@ ifdef(`PROCMAIL_MAILER_PATH',,
_DEFIFNOT(`PROCMAIL_MAILER_FLAGS', `SPhnu9')
ifdef(`PROCMAIL_MAILER_ARGS',,
`define(`PROCMAIL_MAILER_ARGS', `procmail -Y -m $h $f $u')')
+define(`_PROCMAIL_QGRP', `ifelse(defn(`PROCMAIL_MAILER_QGRP'),`',`', ` Q=PROCMAIL_MAILER_QGRP,')')dnl
POPDIVERT
@@ -29,8 +27,8 @@ POPDIVERT
### PROCMAIL Mailer specification ###
##################*****##################
-VERSIONID(`$Id: procmail.m4,v 8.20 1999/10/18 04:57:54 gshapiro Exp $')
+VERSIONID(`$Id: procmail.m4,v 8.22 2001/11/12 23:11:34 ca Exp $')
Mprocmail, P=PROCMAIL_MAILER_PATH, F=_MODMF_(CONCAT(`DFM', PROCMAIL_MAILER_FLAGS), `PROCMAIL'), S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP/HdrFromSMTP,
- ifdef(`PROCMAIL_MAILER_MAX', `M=PROCMAIL_MAILER_MAX, ')T=DNS/RFC822/X-Unix,
+ ifdef(`PROCMAIL_MAILER_MAX', `M=PROCMAIL_MAILER_MAX, ')T=DNS/RFC822/X-Unix,_PROCMAIL_QGRP
A=PROCMAIL_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/qpage.m4 b/contrib/sendmail/cf/mailer/qpage.m4
index 31521d5..b0d9d51 100644
--- a/contrib/sendmail/cf/mailer/qpage.m4
+++ b/contrib/sendmail/cf/mailer/qpage.m4
@@ -3,7 +3,7 @@ PUSHDIVERT(-1)
# Copyright (C) 1997, Philip A. Prindeville and Enteka Enterprise Technology
# Services
#
-# Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
#
# By using this file, you agree to the terms and conditions set
@@ -16,6 +16,7 @@ ifdef(`QPAGE_MAILER_PATH', `', `define(`QPAGE_MAILER_PATH', `/usr/local/bin/qpag
_DEFIFNOT(`QPAGE_MAILER_FLAGS', `mDFMs')
ifdef(`QPAGE_MAILER_ARGS', `', `define(`QPAGE_MAILER_ARGS', `qpage -l0 -m -P$u')')
ifdef(`QPAGE_MAILER_MAX', `', `define(`QPAGE_MAILER_MAX', `4096')')
+define(`_QPAGE_QGRP', `ifelse(defn(`QPAGE_MAILER_QGRP'),`',`', ` Q=QPAGE_MAILER_QGRP,')')dnl
POPDIVERT
@@ -23,8 +24,8 @@ POPDIVERT
### QPAGE Mailer specification ###
######################################
-VERSIONID(`$Id: qpage.m4,v 8.9 1999/11/16 03:33:04 gshapiro Exp $')
+VERSIONID(`$Id: qpage.m4,v 8.10 2001/11/12 23:11:34 ca Exp $')
Mqpage, P=QPAGE_MAILER_PATH, F=_MODMF_(QPAGE_MAILER_FLAGS, `QPAGE'),
- M=QPAGE_MAILER_MAX, T=DNS/RFC822/X-Unix,
+ M=QPAGE_MAILER_MAX, T=DNS/RFC822/X-Unix,_QPAGE_QGRP
A=QPAGE_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/smtp.m4 b/contrib/sendmail/cf/mailer/smtp.m4
index e623a73..2bf5a82 100644
--- a/contrib/sendmail/cf/mailer/smtp.m4
+++ b/contrib/sendmail/cf/mailer/smtp.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -19,24 +19,29 @@ ifdef(`ESMTP_MAILER_ARGS',, `define(`ESMTP_MAILER_ARGS', `TCP $h')')
ifdef(`SMTP8_MAILER_ARGS',, `define(`SMTP8_MAILER_ARGS', `TCP $h')')
ifdef(`DSMTP_MAILER_ARGS',, `define(`DSMTP_MAILER_ARGS', `TCP $h')')
ifdef(`RELAY_MAILER_ARGS',, `define(`RELAY_MAILER_ARGS', `TCP $h')')
+define(`_SMTP_QGRP', `ifelse(defn(`SMTP_MAILER_QGRP'),`',`', ` Q=SMTP_MAILER_QGRP,')')dnl
+define(`_ESMTP_QGRP', `ifelse(defn(`ESMTP_MAILER_QGRP'),`',`', ` Q=ESMTP_MAILER_QGRP,')')dnl
+define(`_SMTP8_QGRP', `ifelse(defn(`SMTP8_MAILER_QGRP'),`',`', ` Q=SMTP8_MAILER_QGRP,')')dnl
+define(`_DSMTP_QGRP', `ifelse(defn(`DSMTP_MAILER_QGRP'),`',`', ` Q=DSMTP_MAILER_QGRP,')')dnl
+define(`_RELAY_QGRP', `ifelse(defn(`RELAY_MAILER_QGRP'),`',`', ` Q=RELAY_MAILER_QGRP,')')dnl
POPDIVERT
#####################################
### SMTP Mailer specification ###
#####################################
-VERSIONID(`$Id: smtp.m4,v 8.56.2.1.2.3 2000/09/25 13:53:27 ca Exp $')
+VERSIONID(`$Id: smtp.m4,v 8.64 2001/04/03 01:52:54 gshapiro Exp $')
#
# common sender and masquerading recipient rewriting
#
-SMasqSMTP=61
+SMasqSMTP
R$* < @ $* > $* $@ $1 < @ $2 > $3 already fully qualified
R$+ $@ $1 < @ *LOCAL* > add local qualification
#
# convert pseudo-domain addresses to real domain addresses
#
-SPseudoToReal=51
+SPseudoToReal
# pass <route-addr>s through
R< @ $+ > $* $@ < @ $1 > $2 resolve <route-addr>
@@ -44,7 +49,7 @@ R< @ $+ > $* $@ < @ $1 > $2 resolve <route-addr>
# output fake domains as user%fake@relay
ifdef(`BITNET_RELAY',
`R$+ <@ $+ .BITNET. > $: $1 % $2 .BITNET < @ $B > user@host.BITNET
-R$+.BITNET <@ $+:$+ > $: $1 .BITNET < @ $3 > strip mailer: part',
+R$+.BITNET <@ $~[ $*:$+ > $: $1 .BITNET < @ $4 > strip mailer: part',
`dnl')
ifdef(`_NO_UUCP_', `dnl', `
# do UUCP heuristics; note that these are shared with UUCP mailers
@@ -56,14 +61,14 @@ R< $&h ! > $- ! $+ $@ $2 < @ $1 .UUCP. >
R< $&h ! > $-.$+ ! $+ $@ $3 < @ $1.$2 >
R< $&h ! > $+ $@ $1 < @ $&h .UUCP. >
R< $+ ! > $+ $: $1 ! $2 < @ $Y > use UUCP_RELAY
-R$+ < @ $+ : $+ > $@ $1 < @ $3 > strip mailer: part
+R$+ < @ $~[ $* : $+ > $@ $1 < @ $4 > strip mailer: part
R$+ < @ > $: $1 < @ *LOCAL* > if no UUCP_RELAY')
#
# envelope sender rewriting
#
-SEnvFromSMTP=11
+SEnvFromSMTP
R$+ $: $>PseudoToReal $1 sender/recipient common
R$* :; <@> $@ list:; special case
R$* $: $>MasqSMTP $1 qualify unqual'ed names
@@ -74,7 +79,7 @@ R$+ $: $>MasqEnv $1 do masquerading
# envelope recipient rewriting --
# also header recipient if not masquerading recipients
#
-SEnvToSMTP=21
+SEnvToSMTP
R$+ $: $>PseudoToReal $1 sender/recipient common
R$+ $: $>MasqSMTP $1 qualify unqual'ed names
R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2
@@ -82,7 +87,7 @@ R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2
#
# header sender and masquerading header recipient rewriting
#
-SHdrFromSMTP=31
+SHdrFromSMTP
R$+ $: $>PseudoToReal $1 sender/recipient common
R:; <@> $@ list:; special case
@@ -96,22 +101,22 @@ R$+ $: $>MasqHdr $1 do masquerading
#
# relay mailer header masquerading recipient rewriting
#
-SMasqRelay=71
+SMasqRelay
R$+ $: $>MasqSMTP $1
R$+ $: $>MasqHdr $1
Msmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
- _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,
+ _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,_SMTP_QGRP
A=SMTP_MAILER_ARGS
-Mesmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
- _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,
+Mesmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a', SMTP_MAILER_FLAGS), `ESMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
+ _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,_ESMTP_QGRP
A=ESMTP_MAILER_ARGS
-Msmtp8, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `8', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
- _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,
+Msmtp8, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `8', SMTP_MAILER_FLAGS), `SMTP8'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
+ _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,_SMTP8_QGRP
A=SMTP8_MAILER_ARGS
-Mdsmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a%', SMTP_MAILER_FLAGS), `SMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
- _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,
+Mdsmtp, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a%', SMTP_MAILER_FLAGS), `DSMTP'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'), E=\r\n, L=990,
+ _OPTINS(`SMTP_MAILER_MAX', `M=', `, ')_OPTINS(`SMTP_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')_OPTINS(`SMTP_MAILER_CHARSET', `C=', `, ')T=DNS/RFC822/SMTP,_DSMTP_QGRP
A=DSMTP_MAILER_ARGS
Mrelay, P=[IPC], F=_MODMF_(CONCAT(_DEF_SMTP_MAILER_FLAGS, `a8', RELAY_MAILER_FLAGS), `RELAY'), S=EnvFromSMTP/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `MasqSMTP/MasqRelay', `MasqSMTP'), E=\r\n, L=2040,
- _OPTINS(`RELAY_MAILER_CHARSET', `C=', `, ')_OPTINS(`RELAY_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')T=DNS/RFC822/SMTP,
+ _OPTINS(`RELAY_MAILER_CHARSET', `C=', `, ')_OPTINS(`RELAY_MAILER_MAXMSGS', `m=', `, ')_OPTINS(`SMTP_MAILER_MAXRCPTS', `r=', `, ')T=DNS/RFC822/SMTP,_RELAY_QGRP
A=RELAY_MAILER_ARGS
diff --git a/contrib/sendmail/cf/mailer/usenet.m4 b/contrib/sendmail/cf/mailer/usenet.m4
index 770eb30..d3ae38b 100644
--- a/contrib/sendmail/cf/mailer/usenet.m4
+++ b/contrib/sendmail/cf/mailer/usenet.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -12,19 +12,17 @@ PUSHDIVERT(-1)
#
#
-ifdef(`_MAILER_local_', `',
- `errprint(`*** MAILER(`local') must appear before MAILER(`usenet')')')dnl
-
ifdef(`USENET_MAILER_PATH',, `define(`USENET_MAILER_PATH', /usr/lib/news/inews)')
_DEFIFNOT(`USENET_MAILER_FLAGS', `rsDFMmn')
ifdef(`USENET_MAILER_ARGS',, `define(`USENET_MAILER_ARGS', `inews -m -h -n')')
+define(`_USENET_QGRP', `ifelse(defn(`USENET_MAILER_QGRP'),`',`', ` Q=USENET_MAILER_QGRP,')')dnl
POPDIVERT
####################################
### USENET Mailer specification ###
####################################
-VERSIONID(`$Id: usenet.m4,v 8.19 1999/11/16 03:33:04 gshapiro Exp $')
+VERSIONID(`$Id: usenet.m4,v 8.21 2000/10/26 02:08:19 ca Exp $')
Musenet, P=USENET_MAILER_PATH, F=_MODMF_(USENET_MAILER_FLAGS, `USENET'), S=EnvFromL, R=EnvToL,
- _OPTINS(`USENET_MAILER_MAX', `M=', `, ')T=X-Usenet/X-Usenet/X-Unix,
+ _OPTINS(`USENET_MAILER_MAX', `M=', `, ')T=X-Usenet/X-Usenet/X-Unix,USENET_MAILER_QGRP
A=USENET_MAILER_ARGS $u
diff --git a/contrib/sendmail/cf/mailer/uucp.m4 b/contrib/sendmail/cf/mailer/uucp.m4
index dd915c3..6513556 100644
--- a/contrib/sendmail/cf/mailer/uucp.m4
+++ b/contrib/sendmail/cf/mailer/uucp.m4
@@ -1,6 +1,6 @@
PUSHDIVERT(-1)
#
-# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983 Eric P. Allman. All rights reserved.
# Copyright (c) 1988, 1993
@@ -11,8 +11,6 @@ PUSHDIVERT(-1)
# the sendmail distribution.
#
#
-ifdef(`_MAILER_smtp_', `',
- `errprint(`*** MAILER(`smtp') must appear before MAILER(`uucp')')')dnl
ifdef(`UUCP_MAILER_PATH',, `define(`UUCP_MAILER_PATH', /usr/bin/uux)')
ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -a$g -gC $h!rmail ($u)')')
@@ -20,17 +18,18 @@ _DEFIFNOT(`UUCP_MAILER_FLAGS', `')
ifdef(`UUCP_MAILER_MAX',,
`define(`UUCP_MAILER_MAX',
`ifdef(`UUCP_MAX_SIZE', `UUCP_MAX_SIZE', 100000)')')
+define(`_UUCP_QGRP', `ifelse(defn(`UUCP_MAILER_QGRP'),`',`', ` Q=UUCP_MAILER_QGRP,')')dnl
POPDIVERT
#####################################
### UUCP Mailer specification ###
#####################################
-VERSIONID(`$Id: uucp.m4,v 8.38 1999/10/18 04:57:55 gshapiro Exp $')
+VERSIONID(`$Id: uucp.m4,v 8.44 2001/08/24 19:49:08 ca Exp $')
#
# envelope and header sender rewriting
#
-SFromU=12
+SFromU
# handle error address as a special case
R<@> $n errors to mailer-daemon
@@ -52,7 +51,7 @@ R! $+ $: $k ! $1 in case $U undefined
#
# envelope recipient rewriting
#
-SEnvToU=22
+SEnvToU
# list:; should disappear
R:; <@> $@
@@ -67,7 +66,7 @@ R$* < @ $+ > $2 ! $1 convert to UUCP format
#
# header recipient rewriting
#
-SHdrToU=42
+SHdrToU
# list:; syntax should disappear
R:; <@> $@
@@ -88,7 +87,7 @@ ifdef(`_MAILER_smtp_',
`#
# envelope sender rewriting for uucp-dom mailer
#
-SEnvFromUD=52
+SEnvFromUD
# handle error address as a special case
R<@> $n errors to mailer-daemon
@@ -99,7 +98,7 @@ R$* $@ $>EnvFromSMTP $1
#
# envelope sender rewriting for uucp-uudom mailer
#
-SEnvFromUUD=72
+SEnvFromUUD
# handle error address as a special case
R<@> $n errors to mailer-daemon
@@ -111,8 +110,10 @@ R$* < @ $* . > $* $1 < @ $2 > $3 strip trailing dots
R<@ $- . UUCP > : $+ $@ $1 ! $2 convert to UUCP format
R<@ $+ > : $+ $@ $1 ! $2 convert to UUCP format
R$* < @ $- . UUCP > $@ $2 ! $1 convert to UUCP format
-R$* < @ $+ > $@ $2 ! $1 convert to UUCP format')
-
+R$* < @ $+ > $@ $2 ! $1 convert to UUCP format',
+`errprint(`*** MAILER(`smtp') must appear before MAILER(`uucp')
+ if uucp-dom should be included.')
+')
PUSHDIVERT(4)
# resolve locally connected UUCP links
@@ -128,29 +129,29 @@ POPDIVERT
# old UUCP mailer (two names)
Muucp, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`DFMhuUd', UUCP_MAILER_FLAGS), `UUCP'), S=FromU, R=EnvToU/HdrToU,
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS
Muucp-old, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`DFMhuUd', UUCP_MAILER_FLAGS), `UUCP'), S=FromU, R=EnvToU/HdrToU,
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS
# smart UUCP mailer (handles multiple addresses) (two names)
Msuucp, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`mDFMhuUd', UUCP_MAILER_FLAGS), `UUCP'), S=FromU, R=EnvToU/HdrToU,
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS
Muucp-new, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`mDFMhuUd', UUCP_MAILER_FLAGS), `UUCP'), S=FromU, R=EnvToU/HdrToU,
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS
ifdef(`_MAILER_smtp_',
`# domain-ized UUCP mailer
Muucp-dom, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`mDFMhud', UUCP_MAILER_FLAGS), `UUCP'), S=EnvFromUD/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'),
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS
# domain-ized UUCP mailer with UUCP-style sender envelope
Muucp-uudom, P=UUCP_MAILER_PATH, F=_MODMF_(CONCAT(`mDFMhud', UUCP_MAILER_FLAGS), `UUCP'), S=EnvFromUUD/HdrFromSMTP, R=ifdef(`_ALL_MASQUERADE_', `EnvToSMTP/HdrFromSMTP', `EnvToSMTP'),
- M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,
+ M=UUCP_MAILER_MAX, _OPTINS(`UUCP_MAILER_CHARSET', `C=', `, ')T=X-UUCP/X-UUCP/X-Unix,_UUCP_QGRP
A=UUCP_MAILER_ARGS')
diff --git a/contrib/sendmail/cf/ostype/a-ux.m4 b/contrib/sendmail/cf/ostype/a-ux.m4
new file mode 100644
index 0000000..c4d4321
--- /dev/null
+++ b/contrib/sendmail/cf/ostype/a-ux.m4
@@ -0,0 +1,21 @@
+divert(-1)
+#
+# Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+# Copyright (c) 1983 Eric P. Allman. All rights reserved.
+# Copyright (c) 1988, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: a-ux.m4,v 8.2 2001/07/23 16:19:36 gshapiro Exp $')
+ifdef(`QUEUE_DIR',, `define(`QUEUE_DIR', /usr/spool/mqueue)')dnl
+ifdef(`UUCP_MAILER_PATH',, `define(`UUCP_MAILER_PATH', /usr/bin/uux)')dnl
+_DEFIFNOT(`LOCAL_MAILER_FLAGS', `mn9')dnl
+ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', `mail -d -r $f $u')')dnl
+define(`confEBINDIR', `/usr/lib')dnl
diff --git a/contrib/sendmail/cf/ostype/aix5.m4 b/contrib/sendmail/cf/ostype/aix5.m4
index c23c0f3..e8df77e 100644
--- a/contrib/sendmail/cf/ostype/aix5.m4
+++ b/contrib/sendmail/cf/ostype/aix5.m4
@@ -10,7 +10,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: aix5.m4,v 1.1.2.1 2000/12/09 03:32:08 ca Exp $')
+VERSIONID(`$Id: aix5.m4,v 1.1 2000/12/08 21:53:36 ca Exp $')
ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /bin/bellmail)')dnl
ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', mail -F $g $u)')dnl
_DEFIFNOT(`LOCAL_MAILER_FLAGS', `mn9')dnl
diff --git a/contrib/sendmail/cf/ostype/darwin.m4 b/contrib/sendmail/cf/ostype/darwin.m4
index c5fffe0..7a0ecf5 100644
--- a/contrib/sendmail/cf/ostype/darwin.m4
+++ b/contrib/sendmail/cf/ostype/darwin.m4
@@ -11,7 +11,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: darwin.m4,v 8.1.2.1 2000/06/15 06:37:04 gshapiro Exp $')
+VERSIONID(`$Id: darwin.m4,v 8.1 2000/06/15 06:36:30 gshapiro Exp $')
ifdef(`STATUS_FILE',, `define(`STATUS_FILE', `/var/log/sendmail.st')')dnl
ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /usr/libexec/mail.local)')dnl
ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -z -a$g $h!rmail ($u)')')dnl
diff --git a/contrib/sendmail/cf/ostype/freebsd5.m4 b/contrib/sendmail/cf/ostype/freebsd5.m4
new file mode 100644
index 0000000..eb7a73a
--- /dev/null
+++ b/contrib/sendmail/cf/ostype/freebsd5.m4
@@ -0,0 +1,20 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: freebsd5.m4,v 1.1 2001/10/08 22:25:34 gshapiro Exp $')
+ifdef(`STATUS_FILE',, `define(`STATUS_FILE', `/var/log/sendmail.st')')dnl
+dnl turn on S flag for local mailer
+MODIFY_MAILER_FLAGS(`LOCAL', `+S')dnl
+ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', /usr/libexec/mail.local)')dnl
+ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', `mail $u')')dnl
+ifdef(`UUCP_MAILER_PATH',, `define(`UUCP_MAILER_PATH', `/usr/local/bin/uux')')dnl
+ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -z -a$g $h!rmail ($u)')')dnl
diff --git a/contrib/sendmail/cf/ostype/linux.m4 b/contrib/sendmail/cf/ostype/linux.m4
index a1998e4..b02ad29 100644
--- a/contrib/sendmail/cf/ostype/linux.m4
+++ b/contrib/sendmail/cf/ostype/linux.m4
@@ -13,7 +13,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: linux.m4,v 8.11.16.2 2000/09/17 17:04:22 gshapiro Exp $')
+VERSIONID(`$Id: linux.m4,v 8.13 2000/09/17 17:30:00 gshapiro Exp $')
define(`confEBINDIR', `/usr/sbin')
ifdef(`PROCMAIL_MAILER_PATH',,
define(`PROCMAIL_MAILER_PATH', `/usr/bin/procmail'))
diff --git a/contrib/sendmail/cf/ostype/mklinux.m4 b/contrib/sendmail/cf/ostype/mklinux.m4
index 12c6f8bf..90b7d2d 100644
--- a/contrib/sendmail/cf/ostype/mklinux.m4
+++ b/contrib/sendmail/cf/ostype/mklinux.m4
@@ -15,7 +15,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: mklinux.m4,v 8.14.4.1 2000/05/09 18:48:58 gshapiro Exp $')
+VERSIONID(`$Id: mklinux.m4,v 8.15 2000/05/09 18:48:56 gshapiro Exp $')
define(`confEBINDIR', `/usr/sbin')
ifdef(`STATUS_FILE',,
`define(`STATUS_FILE', `/var/log/sendmail.st')')
diff --git a/contrib/sendmail/cf/ostype/mpeix.m4 b/contrib/sendmail/cf/ostype/mpeix.m4
new file mode 100644
index 0000000..9e760e9
--- /dev/null
+++ b/contrib/sendmail/cf/ostype/mpeix.m4
@@ -0,0 +1,22 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+VERSIONID(`$Id: mpeix.m4,v 1.1 2001/12/13 23:56:40 gshapiro Exp $')
+
+ifdef(`LOCAL_MAILER_PATH',, `define(`LOCAL_MAILER_PATH', `/bin/tsmail')')dnl
+_DEFIFNOT(`LOCAL_MAILER_FLAGS', `mu9')dnl
+ifdef(`LOCAL_MAILER_ARGS',, `define(`LOCAL_MAILER_ARGS', `tsmail $u')')dnl
+ifdef(`LOCAL_SHELL_PATH',, `define(`LOCAL_SHELL_PATH', `/bin/sh')')dnl
+ifdef(`confDEF_USER_ID',, `define(`confDEF_USER_ID', `SERVER.SENDMAIL')')dnl
+ifdef(`confTRUSTED_USER',, `define(`confTRUSTED_USER', `SERVER.SENDMAIL')')dnl
+define(`confTIME_ZONE', `USE_TZ')dnl
+define(`confDONT_BLAME_SENDMAIL', `ForwardFileInGroupWritableDirPath')dnl
diff --git a/contrib/sendmail/cf/ostype/solaris8.m4 b/contrib/sendmail/cf/ostype/solaris8.m4
index 22e8205..10b9d37 100644
--- a/contrib/sendmail/cf/ostype/solaris8.m4
+++ b/contrib/sendmail/cf/ostype/solaris8.m4
@@ -15,7 +15,7 @@ divert(-1)
#
divert(0)
-VERSIONID(`$Id: solaris8.m4,v 8.1.2.2 2000/08/23 16:10:01 gshapiro Exp $')
+VERSIONID(`$Id: solaris8.m4,v 8.2 2000/08/23 16:10:49 gshapiro Exp $')
divert(-1)
ifdef(`UUCP_MAILER_ARGS',, `define(`UUCP_MAILER_ARGS', `uux - -r -a$g $h!rmail ($u)')')
diff --git a/contrib/sendmail/cf/sendmail.schema b/contrib/sendmail/cf/sendmail.schema
new file mode 100644
index 0000000..bab47e8
--- /dev/null
+++ b/contrib/sendmail/cf/sendmail.schema
@@ -0,0 +1,216 @@
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: sendmail.schema,v 8.14 2001/08/31 17:18:18 gshapiro Exp $
+
+# Note that this schema is experimental at this point as it has had little
+# public review. Therefore, it may change in future versions. Feedback
+# via sendmail@sendmail.org is encouraged.
+
+# OID arcs for Sendmail
+# enterprise: 1.3.6.1.4.1
+# sendmail: enterprise.6152
+# sendmail-at: sendmail.3.1
+# sendmail-oc: sendmail.3.2
+
+###########################################################################
+#
+# The Sendmail MTA attributes and objectclass
+#
+###########################################################################
+
+# attribute sendmailMTACluster cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.10
+ NAME 'sendmailMTACluster'
+ DESC 'cluster name associated with a set of MTAs'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# attribute sendmailMTAHost cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.11
+ NAME 'sendmailMTAHost'
+ DESC 'host name associated with a MTA cluster'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+#objectClass sendmailMTA
+# requires
+# objectClass
+# allows
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.10
+ NAME 'sendmailMTA'
+ SUP top STRUCTURAL
+ DESC 'Sendmail MTA definition'
+ MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+###########################################################################
+#
+# The Sendmail MTA shared attributes
+#
+###########################################################################
+
+# attribute sendmailMTAKey cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.13
+ NAME 'sendmailMTAKey'
+ DESC 'key (left hand side) of an aliases or map entry'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+###########################################################################
+#
+# The Sendmail MTA Map attributes and objectclasses
+#
+###########################################################################
+
+# attribute sendmailMTAMapName cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.14
+ NAME 'sendmailMTAMapName'
+ DESC 'identifier for the particular map'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
+
+# attribute sendmailMTAMapValue cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.16
+ NAME 'sendmailMTAMapValue'
+ DESC 'value (right hand side) of a map entry'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+#objectClass sendmailMTAMap
+# requires
+# objectClass,
+# sendmailMTAMapName,
+# allows
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.11
+ NAME 'sendmailMTAMap'
+ SUP sendmailMTA STRUCTURAL
+ DESC 'Sendmail MTA map definition'
+ MUST sendmailMTAMapName
+ MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+#objectClass sendmailMTAObject
+# requires
+# objectClass,
+# sendmailMTAMapName,
+# sendmailMTAKey,
+# sendmailMTAMapValue,
+# allows
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.12
+ NAME 'sendmailMTAMapObject'
+ SUP sendmailMTAMap STRUCTURAL
+ DESC 'Sendmail MTA map object'
+ MUST ( sendmailMTAMapName $ sendmailMTAKey $ sendmailMTAMapValue )
+ MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+
+###########################################################################
+#
+# The Sendmail MTA Alias attributes and objectclasses
+#
+###########################################################################
+
+# attribute sendmailMTAAliasGrouping cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.18
+ NAME 'sendmailMTAAliasGrouping'
+ DESC 'name that identifies a particular aliases grouping'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+# attribute sendmailMTAAliasValue cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.20
+ NAME 'sendmailMTAAliasValue'
+ DESC 'value (right hand side) of an alias'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+#objectClass sendmailMTAAlias
+# requires
+# objectClass,
+# allows
+# sendmailMTAAliasGrouping,
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.13
+ NAME 'sendmailMTAAlias'
+ SUP sendmailMTA STRUCTURAL
+ DESC 'Sendmail MTA alias definition'
+ MAY ( sendmailMTAAliasGrouping $
+ sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+#objectClass sendmailMTAAliasObject
+# requires
+# objectClass,
+# sendmailMTAKey,
+# sendmailMTAAliasValue,
+# allows
+# sendmailMTAAliasGrouping,
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.14
+ NAME 'sendmailMTAAliasObject'
+ SUP sendmailMTAAlias STRUCTURAL
+ DESC 'Sendmail MTA alias object'
+ MUST ( sendmailMTAKey $ sendmailMTAAliasValue )
+ MAY ( sendmailMTAAliasGrouping $
+ sendmailMTACluster $ sendmailMTAHost $ Description ) )
+
+###########################################################################
+#
+# The Sendmail MTA Class attributes and objectclass
+#
+###########################################################################
+
+# attribute sendmailMTAClassName cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.22
+ NAME 'sendmailMTAClassName'
+ DESC 'identifier for the class'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
+
+# attribute sendmailMTAClassValue cis
+attributetype ( 1.3.6.1.4.1.6152.10.3.1.23
+ NAME 'sendmailMTAClassValue'
+ DESC 'member of a class'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+#objectClass sendmailMTAClass
+# requires
+# objectClass,
+# sendmailMTAClassName,
+# sendmailMTAClassValue,
+# allows
+# sendmailMTACluster,
+# sendmailMTAHost,
+# Description
+
+objectclass ( 1.3.6.1.4.1.6152.10.3.2.15
+ NAME 'sendmailMTAClass'
+ SUP sendmailMTA STRUCTURAL
+ DESC 'Sendmail MTA class definition'
+ MUST ( sendmailMTAClassName $ sendmailMTAClassValue )
+ MAY ( sendmailMTACluster $ sendmailMTAHost $ Description ) )
diff --git a/contrib/sendmail/contrib/buildvirtuser b/contrib/sendmail/contrib/buildvirtuser
index 3ea2d66..2fe469b 100755
--- a/contrib/sendmail/contrib/buildvirtuser
+++ b/contrib/sendmail/contrib/buildvirtuser
@@ -27,7 +27,7 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
-# $Id: buildvirtuser,v 1.1.2.3 2001/02/12 02:57:13 gshapiro Exp $
+# $Id: buildvirtuser,v 1.3 2001/02/12 02:58:20 gshapiro Exp $
=head1 NAME
diff --git a/contrib/sendmail/contrib/dnsblaccess.m4 b/contrib/sendmail/contrib/dnsblaccess.m4
new file mode 100644
index 0000000..8eb5ae6
--- /dev/null
+++ b/contrib/sendmail/contrib/dnsblaccess.m4
@@ -0,0 +1,94 @@
+divert(-1)
+#
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+dnl ## This is a modified enhdnsbl, loosely based on the
+dnl ## original.
+dnl ##
+dnl ## Use it as follows
+dnl ##
+dnl ## HACK(dnsblaccess, domain, optional-message, tempfail-message, keytag)
+dnl ##
+dnl ## The first argument (domain) is required. The other arguments
+dnl ## are optional and have reasonable defaults. The
+dnl ## optional-message is the error message given in case of a
+dnl ## match. The default behavior for a tempfail is to accept the
+dnl ## email. A tempfail-message value of `t' temporarily rejects
+dnl ## with a default message. Otherwise the value should be your
+dnl ## own message. The keytag is used to lookup the access map to
+dnl ## further refine the result. I recommend a qualified keytag
+dnl ## (containing a ".") as less likely to accidently conflict with
+dnl ## other access tags.
+dnl ##
+dnl ## This is best illustrated with an example. Please do not use
+dnl ## the example, as it refers to a bogus lookup list.
+dnl ##
+dnl ## Suppose that you use
+dnl ##
+dnl ## HACK(dnsblaccess, `rbl.bogus.org',`',`t',bogus.tag)
+dnl ##
+dnl ## and suppose that your access map contains the entries
+dnl ##
+dnl ## bogus.tag:127.0.0.2 REJECT
+dnl ## bogus.tag:127.0.0.3 error:dialup mail from %1 rejected by %2
+dnl ## bogus.tag:127.0.0.4 OK
+dnl ## bogus.tag:127 REJECT
+dnl ## bogus.tag: OK
+dnl ##
+dnl ## If an SMTP connection is received from 123.45.6.7, sendmail
+dnl ## will lookup the A record for 7.6.45.123.bogus.org. If there
+dnl ## is a temp failure for the lookup, sendmail will generate a
+dnl ## temporary failure with a default message. If there is no
+dnl ## A-record for this lookup, then the mail is treated as if the
+dnl ## HACK line were not present. If the lookup returns 127.0.0.2,
+dnl ## then a default message rejects the mail. If it returns
+dnl ## 127.0.0.3, then the message
+dnl ## "dialup mail from 123.45.6.7 rejected by rbl.bogus.org"
+dnl ## is used to reject the mail. If it returns 127.0.0.4, the
+dnl ## mail is processed as if there were no HACK line. If the
+dnl ## address returned is something else beginning with 127.*, the
+dnl ## mail is rejected with a default error message. If the
+dnl ## address returned does not begin 127, then the mail is
+dnl ## processed as if the HACK line were not present.
+
+divert(0)
+VERSIONID(`$Id: dnsblaccess.m4,v 1.2 2001/07/23 00:24:04 ca Exp $')
+ifdef(`_ACCESS_TABLE_', `dnl',
+ `errprint(`*** ERROR: dnsblaccess requires FEATURE(`access_db')
+')')
+ifdef(`_EDNSBL_R_',`dnl',`dnl
+define(`_EDNSBL_R_', `1')dnl ## prevent multiple redefines of the map.
+LOCAL_CONFIG
+# map for enhanced DNS based blacklist lookups
+Kednsbl dns -R A -a. -T<TMP> -r`'ifdef(`EDNSBL_TO',`EDNSBL_TO',`5')
+')
+divert(-1)
+define(`_EDNSBL_SRV_', `ifelse(len(X`'_ARG_),`1',`blackholes.mail-abuse.org',_ARG_)')dnl
+define(`_EDNSBL_MSG_', `ifelse(len(X`'_ARG2_),`1',`"550 Mail from " $`'&{client_addr} " refused by blackhole site '_EDNSBL_SRV_`"',`_ARG2_')')dnl
+define(`_EDNSBL_MSG_TMP_', `ifelse(_ARG3_,`t',`"451 Temporary lookup failure of " $`'&{client_addr} " at '_EDNSBL_SRV_`"',`_ARG3_')')dnl
+define(`_EDNSBL_KEY_', `ifelse(len(X`'_ARG4_),`1',`dnsblaccess',_ARG4_)')dnl
+divert(8)
+# DNS based IP address spam list _EDNSBL_SRV_
+R$* $: $&{client_addr}
+dnl IPv6?
+R$-.$-.$-.$- $: <?> $(ednsbl $4.$3.$2.$1._EDNSBL_SRV_. $: OK $) <>$1.$2.$3.$4
+R<?>OK<>$* $: OKSOFAR
+R<?>$+<TMP><>$* $: <? <TMPF>>
+R<?>$* $- .<>$* <$(access _EDNSBL_KEY_`:'$1$2 $@$3 $@`'_EDNSBL_SRV_ $: ? $)> $1 <>$3
+R<?>$* <>$* $:<$(access _EDNSBL_KEY_`:' $@$2 $@`'_EDNSBL_SRV_ $: ? $)> <>$2
+ifelse(len(X`'_ARG3_),`1',
+`R<$*<TMPF>>$* $: TMPOK',
+`R<$*<TMPF>>$* $#error $@ 4.7.1 $: _EDNSBL_MSG_TMP_')
+R<$={Accept}>$* $: OKSOFAR
+R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
+R<ERROR:$+> $* $#error $: $1
+R<DISCARD> $* $#discard $: discard
+R<$*> $* $#error $@ 5.7.1 $: _EDNSBL_MSG_
+divert(-1)
diff --git a/contrib/sendmail/contrib/domainmap.m4 b/contrib/sendmail/contrib/domainmap.m4
index fbaf62c..540beff 100644
--- a/contrib/sendmail/contrib/domainmap.m4
+++ b/contrib/sendmail/contrib/domainmap.m4
@@ -46,7 +46,7 @@ divert(-1)changequote(<<, >>)<<
in the sendmail source tree. For more information, please see the
following URL:
- http://www-wsg.cso.uiuc.edu/sendmail/patches/domainmap.html
+ http://www-dev.cso.uiuc.edu/sendmail/domainmap/
Feedback is welcome.
@@ -69,14 +69,16 @@ LOCAL_RULESETS
SDomainMapLookup
R $=L <@ $=w .> $@ $1 <@ $2 .> weed out local users, in case
# Cw contains a mapped domain
+R $+ <@ $+> $: $1 <@ $2 > <$&{addr_type}> check if sender
+R $+ <@ $+> <e s> $#smtp $@ $2 $: $1 @ $2 do not process sender
ifdef(`DOMAINMAP_NO_REGEX',`dnl
-R $+ <@ $+> $: $1 <@ $2> <$2> find domain
+R $+ <@ $+> <$*> $: $1 <@ $2> <$2> find domain
R $+ <$+> <$+ . $+> $1 <$2> < $(dequote $3 "_" $4 $) >
# change "." to "_"
R $+ <$+> <$+ .> $: $1 <$2> < $(dequote "domain_" $3 $) >
# prepend "domain_"
dnl',`dnl
-R $+ <@ $+> $: $1 <@ $2> <$2 :NOTDONE:> find domain
+R $+ <@ $+> <$*> $: $1 <@ $2> <$2 :NOTDONE:> find domain
R $+ <$+> <$+ . :NOTDONE:> $1 <$2> < $(domainmap_regex $3 $: $3 $) >
# change "." and "-" to "_"
R $+ <$+> <$+> $: $1 <$2> < $(dequote "domain_" $3 $) >
diff --git a/contrib/sendmail/contrib/link_hash.sh b/contrib/sendmail/contrib/link_hash.sh
index e07104d..843c920 100644
--- a/contrib/sendmail/contrib/link_hash.sh
+++ b/contrib/sendmail/contrib/link_hash.sh
@@ -3,7 +3,7 @@
## Copyright (c) 2000 Sendmail, Inc. and its suppliers.
## All rights reserved.
##
-## $Id: link_hash.sh,v 1.1.2.1 2000/04/25 00:10:47 ca Exp $
+## $Id: link_hash.sh,v 1.2 2000/04/25 00:12:28 ca Exp $
##
#
# ln a certificate to its hash
diff --git a/contrib/sendmail/contrib/qtool.8 b/contrib/sendmail/contrib/qtool.8
index 1106d07..5c40142 100644
--- a/contrib/sendmail/contrib/qtool.8
+++ b/contrib/sendmail/contrib/qtool.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\"
.\" By using this file, you agree to the terms and conditions set
@@ -6,18 +6,18 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: qtool.8,v 8.9.16.2 2000/12/15 19:50:41 gshapiro Exp $
+.\" $Id: qtool.8,v 8.16 2001/11/21 19:21:20 gshapiro Exp $
.\"
-.TH QTOOL 8 "$Date: 2000/12/15 19:50:41 $"
+.TH QTOOL 8 "$Date: 2001/11/21 19:21:20 $"
.SH NAME
qtool
\- manipulate sendmail queues
.SH SYNOPSIS
.B qtool.pl
-.RB [options]
+.RB [options]
target_directory source [source ...]
.PP
-.B qtool.pl [-d/-b]
+.B qtool.pl [-Q][-d|-b]
.RB [options]
source [source ...]
.SH DESCRIPTION
@@ -28,8 +28,8 @@ running.
.PP
With no options,
.B qtool
-will move any queue files as specified by \fIsource\fP into
-\fItarget_directory\fP. \fISource\fP can be either an individual
+will move any queue files as specified by \fIsource\fP into
+\fItarget_directory\fP. \fISource\fP can be either an individual
queue control file, a queue file id, or a queue directory.
.PP
If the -d option is specified, qtool will delete the messages specified by
@@ -38,19 +38,27 @@ source instead of moving them.
If the -b option is specified, the selected messages will be bounced by
running sendmail with the -OTimeout.queuereturn=now option.
.SS Options
-.TP
+.TP
\fB\-b\fP
Bounce all of the messages specified by source. The messages will be bounced
immediately. No attempt will be made to deliver the messages.
.TP
+\fB\-C\fP configfile
+Specify the sendmail config file.
+Defaults to /etc/mail/sendmail.cf.
+.TP
\fB\-d\fP
Delete all of the messages specified by source.
-.TP
+.TP
\fB\-e\fP \fIperl_expression\fP
-Evalute \fIperl_expression\fP for each queue file as specified
-by \fIsource\fP. If \fIperl_expression\fP evaluates to true, then that
+Evalute \fIperl_expression\fP for each queue file as specified
+by \fIsource\fP. If \fIperl_expression\fP evaluates to true, then that
queue file is moved. See below for more detail on \fIperl_expression\fP.
-.TP
+.TP
+\fB\-Q\fP
+Operate on quarantined items
+(queue control file begins with hf instead of qf).
+.TP
\fB\-s\fP \fIseconds\fP
Move only the queue files specified by \fIsource\fP that have a
modification time older than \fIseconds\fP.
@@ -74,9 +82,6 @@ The last time the body was modified since the epoch in seconds.
\fBbody_size\fP
The size of the body file in bytes.
.TP
-\fBcharset\fP
-Character set (for future use).
-.TP
\fBcontent-length\fP
Content-Length: header value (Solaris sendmail only).
.TP
@@ -84,7 +89,7 @@ Content-Length: header value (Solaris sendmail only).
The controlling user.
.TP
\fBcontrol_last_mod_time\fP
-The last time the body was modified since the epoch in seconds.
+The last time the control file was modified since the epoch in seconds.
.TP
\fBcontrol_size\fP
The size of the control file in bytes.
@@ -92,15 +97,24 @@ The size of the control file in bytes.
\fBcreation_time\fP
The time when the control file was created.
.TP
+\fBcurrent_delay\fP
+Current delay for queue delay algorithm if _FFR_QUEUEDELAY is enabled.
+.TP
\fBdata_file_name\fP
The data file name (deprecated).
.TP
+\fBdeliver_by\fP
+Deliver by flag and deadline for DELIVERBY ESMTP extension.
+.TP
\fBenvid\fP
Original envelope id form ESMTP.
.TP
\fBerror_recipient\fP
The error recipient (deprecated).
.TP
+\fBfinal_recipient\fP
+Final recipient (for DSNs).
+.TP
\fBflags\fP
Array of characters that can be the following values:
.PD 0
@@ -110,7 +124,7 @@ w
warning message has been sent
.TP 8
r
-This is an error respone or DSN
+This is an error response or DSN
.TP 8
8
has 8 bit data in body
@@ -153,6 +167,13 @@ Original recipient (ORCPT= parameter).
\fBpriority\fP
Adjusted priority of message.
.TP
+\fBquarantine_reason\fP
+Quarantine reason for quarantined (held) envelopes if _FFR_QUARANTINE is
+enabled.
+.TP
+\fBqueue_delay\fP
+Queue delay algorithm if _FFR_QUEUEDELAY is enabled.
+.TP
\fBrecipient\fP
Array of character flags followed by colon and recipient name. Flags:
.PD 0
@@ -191,16 +212,19 @@ Moves the message with id d6CLQh100847 in queue q1 to queue q2.
\fBqtool.pl q2 q1/qfd6CLQh100847\fP
Moves the message with id d6CLQh100847 in queue q1 to queue q2.
.TP
-\fBqtool.pl q2 q1/dfd6CLQh100847\fP
-Moves the message with id d6CLQh100847 in queue q1 to queue q2.
-.TP
\fBqtool.pl -e '$msg{num_delivery_attempts} == 3' /q2 /q1\fP
Moves all of the queue files that have had three attempted deliveries from
queue q1 to queue q2.
+.SH BUGS
+In sendmail 8.12, it is possible for a message's queue and data files (df)
+to be stored in different queues.
+In this situation, you must give qtool the pathname of the queue file,
+not of the data file (df).
+To be safe, never feed qtool the pathname of a data file (df).
.SH SEE ALSO
sendmail(8)
.SH HISTORY
The
.B qtool
-command appeared in
+command appeared in
sendmail 8.10.
diff --git a/contrib/sendmail/contrib/qtool.pl b/contrib/sendmail/contrib/qtool.pl
index f4d36f3..d93f743a 100755
--- a/contrib/sendmail/contrib/qtool.pl
+++ b/contrib/sendmail/contrib/qtool.pl
@@ -1,9 +1,9 @@
#!/usr/bin/env perl
##
-## Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
-## All rights reserved.
+## Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+## All rights reserved.
##
-## $Id: qtool.pl,v 8.15.16.4 2000/11/30 07:14:01 gshapiro Exp $
+## $Id: qtool.pl,v 8.26 2001/11/21 19:26:17 gshapiro Exp $
##
use strict;
use File::Basename;
@@ -43,7 +43,7 @@ use Getopt::Std;
## queue message. This lets you check for any value in the message
## headers or the control file. Here's an example:
##
-## ./qtool.pl -e '$msg->{num_delivery_attempts} >= 2' /q1 /q2
+## ./qtool.pl -e '$msg{num_delivery_attempts} >= 2' /q1 /q2
##
## This would move any queue files whose number of delivery attempts
## is greater than or equal to 2 from the queue 'q2' to the queue 'q1'.
@@ -61,9 +61,10 @@ my $source;
my $result;
my $action;
my $new_condition;
+my $qprefix;
my $conditions = new Compound();
-Getopt::Std::getopts('bde:s:', \%opts);
+Getopt::Std::getopts('bC:de:Qs:', \%opts);
sub move_action
{
@@ -113,6 +114,15 @@ if (defined $opts{e})
$conditions->add($new_condition);
}
+if (defined $opts{Q})
+{
+ $qprefix = "hf";
+}
+else
+{
+ $qprefix = "qf";
+}
+
if ($action == \&move_action)
{
$dst_name = shift(@ARGV);
@@ -126,6 +136,37 @@ if ($action == \&move_action)
$destination = new Queue($dst_name);
}
+# determine queue_root by reading config file
+my $queue_root;
+{
+ my $config_file = "/etc/mail/sendmail.cf";
+ if (defined $opts{C})
+ {
+ $config_file = $opts{C};
+ }
+
+ my $line;
+ open(CONFIG_FILE, $config_file) or die "$config_file: $!";
+ while ($line = <CONFIG_FILE>)
+ {
+ chomp $line;
+ if ($line =~ m/^O QueueDirectory=(.*)/)
+ {
+ $queue_root = $1;
+ if ($queue_root =~ m/(.*)\/[^\/]+\*$/)
+ {
+ $queue_root = $1;
+ }
+ last;
+ }
+ }
+ close(CONFIG_FILE);
+ if (!defined $queue_root)
+ {
+ die "QueueDirectory option not defined in $config_file";
+ }
+}
+
while (@ARGV)
{
$source_name = shift(@ARGV);
@@ -157,13 +198,18 @@ while (($source_name, $source) = each(%sources))
sub usage
{
- print("Usage: $0 [options] directory source ...\n");
- print(" $0 [-d|-b] source ...\n");
- print("options:\n");
- print(" -b Bounce the messages specified by source.\n");
- print(" -d Delete the messages specified by source.\n");
- print(" -e [perl expression] Move only messages for which perl expression returns true.\n");
- print(" -s [seconds] Move only messages whose qf file is older than seconds.\n");
+ print("Usage:\t$0 [options] directory source ...\n");
+ print("\t$0 [-Q][-d|-b] source ...\n");
+ print("Options:\n");
+ print("\t-b\t\tBounce the messages specified by source.\n");
+ print("\t-C configfile\tSpecify sendmail config file.\n");
+ print("\t-d\t\tDelete the messages specified by source.\n");
+ print("\t-e [perl expression]\n");
+ print("\t\t\tMove only messages for which perl expression\n");
+ print("\t\t\treturns true.\n");
+ print("\t-Q\t\tOperate on quarantined files.\n");
+ print("\t-s [seconds]\tMove only messages whose queue file is older\n");
+ print("\t\t\tthan seconds.\n");
}
##
@@ -204,10 +250,10 @@ sub add_source
$data_dir_name = $source_dir_name;
$source_prefix = substr($source_base_name, 0, 2);
- if (!-d $source_name && $source_prefix ne 'qf' &&
+ if (!-d $source_name && $source_prefix ne $qprefix &&
$source_prefix ne 'df')
{
- $source_base_name = "qf$source_base_name";
+ $source_base_name = "$qprefix$source_base_name";
$source_name = File::Spec->catfile("$source_dir_name",
"$source_base_name");
}
@@ -216,12 +262,16 @@ sub add_source
if (!-e $source_name)
{
$source_name = File::Spec->catfile("$source_dir_name", "qf",
- "qf$source_id");
+ "$qprefix$source_id");
if (!-e $source_name)
{
return "'$source_name' does not exist";
}
$data_dir_name = File::Spec->catfile("$source_dir_name", "df");
+ if (!-d $data_dir_name)
+ {
+ $data_dir_name = $source_dir_name;
+ }
$source_dir_name = File::Spec->catfile("$source_dir_name",
"qf");
}
@@ -377,7 +427,7 @@ sub initialize
my $queue_dir = shift;
$self->{id} = shift;
- $self->{file_name} = $queue_dir . '/qf' . $self->{id};
+ $self->{file_name} = $queue_dir . '/' . $qprefix . $self->{id};
$self->{headers} = {};
}
@@ -402,9 +452,11 @@ sub parse
'B' => 'body_type',
'C' => 'controlling_user',
'D' => 'data_file_name',
+ 'd' => 'data_file_directory',
'E' => 'error_recipient',
'F' => 'flags',
'H' => 'parse_header',
+ 'G' => 'queue_delay',
'I' => 'inode_number',
'K' => 'next_delivery_time',
'L' => 'content-length',
@@ -413,11 +465,14 @@ sub parse
'P' => 'priority',
'Q' => 'original_recipient',
'R' => 'recipient',
+ 'q' => 'quarantine_reason',
+ 'r' => 'final_recipient',
'S' => 'sender',
'T' => 'creation_time',
'V' => 'version',
- 'X' => 'charset',
+ 'Y' => 'current_delay',
'Z' => 'envid',
+ '!' => 'deliver_by',
'$' => 'macro'
);
my $line;
@@ -488,7 +543,7 @@ sub parse_header
if (ref($headers->{$last_header}) eq 'ARRAY')
{
$headers->{$last_header}[-1] =
- $headers->{$last_header}[-1] . $line;
+ $headers->{$last_header}[-1] . $line;
}
else
{
@@ -621,10 +676,21 @@ sub new
sub initialize
{
my $self = shift;
- my $queue_dir = shift;
+ my $data_dir = shift;
$self->{id} = shift;
-
- $self->{file_name} = $queue_dir . '/df' . $self->{id};
+ my $control_file = shift;
+
+ $self->{file_name} = $data_dir . '/df' . $self->{id};
+ return if -e $self->{file_name};
+ $control_file->parse();
+ return if !defined $control_file->{data_file_directory};
+ $data_dir = $queue_root . '/' . $control_file->{data_file_directory};
+ chomp $data_dir;
+ if (-d ($data_dir . '/df'))
+ {
+ $data_dir .= '/df';
+ }
+ $self->{file_name} = $data_dir . '/df' . $self->{id};
}
sub do_stat
@@ -694,14 +760,11 @@ sub initialize
$self->{id} = $id;
$self->{control_file} = new ControlFile($queue_dir, $id);
- if ($data_dir)
- {
- $self->{data_file} = new DataFile($data_dir, $id);
- }
- else
+ if (!$data_dir)
{
- $self->{data_file} = new DataFile($queue_dir, $id);
+ $data_dir = $queue_dir;
}
+ $self->{data_file} = new DataFile($data_dir, $id, $self->{control_file});
}
sub last_modified_time
@@ -780,7 +843,7 @@ sub move
$df_dest = $destination;
}
- if (-e File::Spec->catfile($qf_dest, "qf$self->{id}"))
+ if (-e File::Spec->catfile($qf_dest, "$qprefix$self->{id}"))
{
$result = "There is already a queued message with id '$self->{id}' in '$destination'";
}
@@ -884,7 +947,8 @@ sub initialize
## READ - Loads the queue with all of the objects that reside in it.
##
## This reads the queue's directory and creates QueuedMessage objects
-## for every file in the queue that starts with 'qf'.
+## for every file in the queue that starts with 'qf' or 'hf'
+## (depending on the -Q option).
##
sub read
@@ -920,7 +984,7 @@ sub read
return "Unable to open directory '$control_dir'";
}
- @control_files = grep { /^qf.*/ && -f "$control_dir/$_" } readdir(QUEUE_DIR);
+ @control_files = grep { /^$qprefix.*/ && -f "$control_dir/$_" } readdir(QUEUE_DIR);
closedir(QUEUE_DIR);
foreach $file_name (@control_files)
{
diff --git a/contrib/sendmail/doc/op/Makefile b/contrib/sendmail/doc/op/Makefile
index e339113..09f4592 100644
--- a/contrib/sendmail/doc/op/Makefile
+++ b/contrib/sendmail/doc/op/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 8.7.8.4 2001/07/01 18:34:56 gshapiro Exp $
+# $Id: Makefile,v 8.14 2002/01/07 22:24:36 gshapiro Exp $
DIR= smm/08.sendmailop
SRCS= op.me
@@ -8,12 +8,14 @@ ROFF_CMD= groff
PIC_CMD= pic
EQN_CMD= eqn
UL_CMD= ul
+PS2PDF_CMD= ps2pdf
PIC= ${PIC_CMD} -C
EQNASCII= ${EQN_CMD} -C -Tascii
EQNPS= ${EQN_CMD} -C -Tps
ROFFASCII= ${ROFF_CMD} -Tascii ${MACROS}
ROFFPS= ${ROFF_CMD} -Tps -mps ${MACROS}
ULASCII= ${UL_CMD} -t dumb
+PS2PDF= ${PS2PDF_CMD}
all: ${OBJS}
@@ -25,7 +27,11 @@ op.txt: ${SRCS}
rm -f $@
${PIC} ${SRCS} | ${EQNASCII} | ${ROFFASCII} | ${ULASCII} > $@
+op.pdf: op.ps
+ rm -f $@
+ ${PS2PDF} op.ps op.pdf
+
clean:
- rm -f op.ps op.txt
+ rm -f op.ps op.txt op.pdf
install: ${OBJS}
diff --git a/contrib/sendmail/doc/op/op.me b/contrib/sendmail/doc/op/op.me
index 802e3b7..8c7beb6 100644
--- a/contrib/sendmail/doc/op/op.me
+++ b/contrib/sendmail/doc/op/op.me
@@ -9,7 +9,7 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: op.me,v 8.317.4.71 2001/08/14 15:26:00 ca Exp $
+.\" $Id: op.me,v 8.592 2001/12/26 03:44:39 ca Exp $
.\"
.\" eqn op.me | pic | troff -me
.\"
@@ -81,16 +81,17 @@ This documentation is under modification.
.sp
.r
Eric Allman
+Gregory Neil Shapiro
+Claus Assmann
Sendmail, Inc.
-eric@Sendmail.COM
.sp
.de Ve
Version \\$2
..
-.Ve $Revision: 8.317.4.71 $
+.Ve $Revision: 8.592 $
.rm Ve
.sp
-For Sendmail Version 8.11
+For Sendmail Version 8.12
.)l
.(f
Sendmail is a trademark of Sendmail, Inc.
@@ -127,9 +128,9 @@ RFC821 (Simple Mail Transport Protocol),
RFC822 (Internet Mail Headers Format),
RFC974 (MX routing),
RFC1123 (Internet Host Requirements),
-RFC2045 (MIME),
-RFC1869 (SMTP Service Extensions),
+RFC1413 (Identification server),
RFC1652 (SMTP 8BITMIME Extension),
+RFC1869 (SMTP Service Extensions),
RFC1870 (SMTP SIZE Extension),
RFC1891 (SMTP Delivery Status Notifications),
RFC1892 (Multipart/Report),
@@ -138,10 +139,15 @@ RFC1894 (Delivery Status Notifications),
RFC1985 (SMTP Service Extension for Remote Message Queue Starting),
RFC2033 (Local Message Transmission Protocol),
RFC2034 (SMTP Service Extension for Returning Enhanced Error Codes),
+RFC2045 (MIME),
RFC2476 (Message Submission),
RFC2487 (SMTP Service Extension for Secure SMTP over TLS),
+RFC2554 (SMTP Service Extension for Authentication),
+RFC2821 (Simple Mail Transfer Protocol),
+RFC2822 (Internet Message Format),
+RFC2852 (Deliver By SMTP Service Extension),
and
-RFC2554 (SMTP Service Extension for Authentication).
+RFC2920 (SMTP Service Extension for Command Pipelining).
However, since
.i sendmail
is designed to work in a wider world,
@@ -169,9 +175,9 @@ for you to install
.i sendmail
and keep it happy.
Section three
-describes some parameters that may be safely tweaked.
-Section four
has information regarding the command line arguments.
+Section four
+describes some parameters that may be safely tweaked.
Section five
contains the nitty-gritty information about the configuration
file.
@@ -203,6 +209,11 @@ and the settings of various options.
Although the configuration file can be quite complex,
a configuration can usually be built
using an M4-based configuration language.
+Assuming you have the standard
+.i sendmail
+distribution, see
+.i cf/README
+for further information.
.pp
The remainder of this section will describe the installation of
.i sendmail
@@ -214,10 +225,11 @@ are given from the root of the
subtree,
normally
.i /usr/src/usr.\*(SD/sendmail
-on 4.4BSD.
+on 4.4BSD-based systems.
.pp
-If you are loading this off the tape,
-continue with the next section.
+Continue with the next section if you need/want to compile
+.i sendmail
+yourself.
If you have a running binary already on your system,
you should probably skip to section 1.2.
.sh 2 "Compiling Sendmail"
@@ -248,6 +260,8 @@ command.
In most cases these are only used when the
.i obj.*
directory is first created.
+To restart from scratch, use
+.i -c .
These commands include:
.nr ii 0.5i
.ip "\-L \fIlibdirs\fP"
@@ -285,9 +299,10 @@ will avoid auto-detecting libraries if this is set.
All libraries and map definitions must be specified
in the site configuration file.
.lp
-Any other parameters are passed to the
+Most other parameters are passed to the
.i make
-program.
+program; for details see
+.i $BUILDTOOLS/README .
.sh 3 "Creating a Site Configuration File"
.\"XXX
.pp
@@ -343,6 +358,8 @@ If neither of these are defined,
reads the alias file into memory on every invocation.
This can be slow and should be avoided.
There are also several methods for remote database access:
+.ip LDAP
+Lightweight Directory Access Protocol.
.ip NIS
Sun's Network Information Services (formerly YP).
.ip NISPLUS
@@ -352,9 +369,12 @@ NeXT's NetInfo service.
.ip HESIOD
Hesiod service (from Athena).
.lp
-Other compilation flags are set in conf.h
+Other compilation flags are set in
+.i conf.h
and should be predefined for you
unless you are porting to a new environment.
+For more options see
+.i sendmail/README .
.sh 3 "Compilation and installation"
.pp
After making the local system configuration described above,
@@ -382,7 +402,14 @@ and
/usr/\*(SB/mailq
to
/usr/\*(SD/sendmail.
-On 4.4BSD systems it will also format and install man pages.
+On most systems it will also format and install man pages.
+Notice: as of version 8.12
+.i sendmail
+will no longer be installed set-user-ID root by default.
+If you really want to use the old method, you can specify it as target:
+.(b
+\&./Build install-set-user-id
+.)b
.sh 2 "Configuration Files"
.pp
.i Sendmail
@@ -401,24 +428,9 @@ The world is complex,
and the mail configuration reflects that.
The distribution includes an m4-based configuration package
that hides a lot of the complexity.
-.pp
-These configuration files are simpler than old versions
-largely because the world has become simpler;
-in particular,
-text-based host files are officially eliminated,
-obviating the need to
-.q hide
-hosts behind a registered internet gateway.
-.pp
-These files also assume that most of your neighbors
-use domain-based UUCP addressing;
-that is,
-instead of naming hosts as
-.q host!user
-they will use
-.q host.domain!user .
-The configuration files can be customized to work around this,
-but it is more complex.
+See
+.i cf/README
+for details.
.pp
Our configuration files are processed by
.i m4
@@ -444,7 +456,7 @@ as a general description of an SMTP-connected host
running Solaris 2.x.
Files ending
.b \&.mc
-(``Master Configuration'')
+(``M4 Configuration'')
are the input descriptions;
the output is in the corresponding
.b \&.cf
@@ -521,6 +533,7 @@ Local UUCP connectivity information.
This directory has been supplanted by the mailertable feature;
any new configurations should use that feature to do UUCP
(and other) routing.
+The use of this directory is deprecated.
.pp
If you are in a new domain
(e.g., a company),
@@ -580,7 +593,8 @@ many systems install it in
I understand it is in /usr/ucblib
on System V Release 4.
.)f
-It should be setuid root.
+It should be set-group-ID smmsp as described in
+sendmail/SECURITY.
For security reasons,
/, /usr, and /usr/\*(SD
should be owned by root, mode 755\**.
@@ -594,7 +608,7 @@ and permissions are
.)f
.sh 3 "/etc/mail/sendmail.cf"
.pp
-This is the configuration file for
+This is the main configuration file for
.i sendmail \**.
.(f
\**Actually, the pathname varies depending on the operating system;
@@ -609,8 +623,9 @@ to the flags passed to the C compiler.
Moving this file is not recommended:
other programs and scripts know of this location.
.)f
-This is the only non-library file name compiled into
-.i sendmail \**.
+This is one of the two non-library file names compiled into
+.i sendmail \**,
+the other is /etc/mail/submit.cf.
.(f
\**The system libraries can reference other files;
in particular, system library subroutines that
@@ -627,6 +642,32 @@ If you have a particularly unusual system configuration
you may need to create a special version.
The format of this file is detailed in later sections
of this document.
+.sh 3 "/etc/mail/submit.cf"
+.pp
+This is the configuration file for
+.i sendmail
+when it is used for initial mail submission, in which case
+it is also called ``Mail Submission Program'' (MSP)
+in contrast to ``Mail Transfer Agent'' (MTA).
+Starting with version 8.12,
+.i sendmail
+uses one of two different configuration files based on its operation mode
+(or the new
+.b \-A
+option).
+For initial mail submission, i.e., if one of the options
+.b \-bm
+(default),
+.b \-bs ,
+or
+.b \-t
+is specified, submit.cf is used (if available),
+for other operations sendmail.cf is used.
+Details can be found in
+.i sendmail/SECURITY .
+submit.cf is shipped with sendmail (in cf/cf/) and is installed by default.
+If changes to the configuration need to be made, start with
+cf/cf/submit.mc and follow the instruction in cf/README.
.sh 3 "/usr/\*(SB/newaliases"
.pp
The
@@ -670,8 +711,8 @@ This directory should be mode 700
and owned by root.
.pp
The actual path of this directory
-is defined in the
-.b Q
+is defined by the
+.b QueueDirectory
option of the
.i sendmail.cf
file.
@@ -692,6 +733,40 @@ queue file types.
That is, the data files are stored in the `df' subdirectory,
the transcript files are stored in the `xf' subdirectory, and
all others are stored in the `qf' subdirectory.
+.pp
+If shared memory support is compiled in,
+.i sendmail
+stores the available diskspace in a shared memory segment
+to make the values readily available to all children without
+incurring system overhead.
+In this case, only the daemon updates the data;
+i.e., the sendmail daemon creates the shared memory segment
+and deletes it if it is terminated.
+To use this,
+.i sendmail
+must have been compiled with support for shared memory
+(-DSM_CONF_SHM)
+and the option
+.b SharedMemoryKey
+must be set.
+Notice: do not use the same key for
+.i sendmail
+invocations with different queue directories
+or different queue group declarations.
+.sh 3 "/var/spool/clientmqueue"
+.pp
+The directory
+.i /var/spool/clientmqueue
+should be created to hold the mail queue.
+This directory should be mode 770
+and owned by user smmsp, group smmsp.
+.pp
+The actual path of this directory
+is defined by the
+.b QueueDirectory
+option of the
+.i submit.cf
+file.
.sh 3 "/var/spool/mqueue/.hoststat"
.pp
This is a typical value for the
@@ -711,7 +786,7 @@ which includes some aliases which
.i must
be defined:
.(b
-cp lib/aliases /etc/mail/aliases
+cp sendmail/aliases /etc/mail/aliases
.i "edit /etc/mail/aliases"
.)b
You should extend this file with any aliases that are apropos to your system.
@@ -743,7 +818,7 @@ it listens on the SMTP socket for connections
and it processes the queue periodically
to insure that mail gets delivered when hosts come up.
.pp
-Add the following lines to
+If necessary, add the following lines to
.q /etc/rc
(or
.q /etc/rc.local
@@ -755,7 +830,7 @@ in one of the startup files, typically
.q /etc/init.d/sendmail :
.(b
if [ \-f /usr/\*(SD/sendmail \-a \-f /etc/mail/sendmail.cf ]; then
- (cd /var/spool/mqueue; rm \-f [lnx]f*)
+ (cd /var/spool/mqueue; rm \-f xf*)
/usr/\*(SD/sendmail \-bd \-q30m &
echo \-n ' sendmail' >/dev/console
fi
@@ -764,8 +839,8 @@ The
.q cd
and
.q rm
-commands insure that all lock files have been removed;
-extraneous lock files may be left around
+commands insure that all transcript files have been removed;
+extraneous transcript files may be left around
if the system goes down in the middle of processing a message.
The line that actually invokes
.i sendmail
@@ -834,12 +909,6 @@ done
Figure 1 \(em A complex startup script
.hl
.)z
-.pp
-If you are not running a version of UNIX
-that supports Berkeley TCP/IP,
-do not include the
-.b \-bd
-flag.
.sh 3 "/etc/mail/helpfile"
.pp
This is the help file used by the SMTP
@@ -944,10 +1013,10 @@ The number of envelope recipients for this message
The message id of the message (from the header).
.ip proto
The protocol used to receive this message (e.g., ESMTP or UUCP)
-.ip daemon
-The daemon name from the
-.b DaemonPortOptions
-setting.
+.ip daemon
+The daemon name from the
+.b DaemonPortOptions
+setting.
.ip relay
The machine from which it was received.
.lp
@@ -976,7 +1045,7 @@ The enhanced error code (RFC2034) if available.
The delivery status.
.lp
Not all fields are present in all messages;
-for example, the relay is not listed for local deliveries.
+for example, the relay is usually not listed for local deliveries.
.sh 3 "Levels"
.pp
If you have
@@ -1015,13 +1084,109 @@ signal.
The results are logged at
.sm LOG_DEBUG
priority.
-.sh 2 "The Mail Queue"
+.sh 2 "The Mail Queues"
+.pp
+Mail messages may either be delivered immediately or be held for later
+delivery.
+Held messages are placed into a holding directory called a mail queue.
.pp
-Sometimes a host cannot handle a message immediately.
-For example, it may be down or overloaded, causing it to refuse connections.
-The sending host is then expected to save this message in
-its mail queue
-and attempt to deliver it later.
+A mail message may be queued for these reasons:
+.bu
+If a mail message is temporarily undeliverable, it is queued
+and delivery is attempted later.
+If the message is addressed to multiple recipients, it is queued
+only for those recipients to whom delivery is not immediately possible.
+.bu
+If the SuperSafe option is set to true,
+all mail messages are queued while delivery is attempted.
+.bu
+If the DeliveryMode option is set to queue-only or defer,
+all mail is queued, and no immediate delivery is attempted.
+.bu
+If the load average becomes higher than the value of the QueueLA option
+and the
+.b QueueFactor
+(\c
+.b q )
+option divided by the difference in the current load average and the
+.b QueueLA
+option plus one
+is less than the priority of the message,
+messages are queued rather than immediately delivered.
+.sh 3 "Queue Groups and Queue Directories"
+.pp
+There are one or more mail queues.
+Each mail queue belongs to a queue group.
+There is always a default queue group that is called ``mqueue''
+(which is where messages go by default unless otherwise specified).
+The directory or directories which comprise the default queue group
+are specified by the QueueDirectory option.
+There are zero or more
+additional named queue groups declared using the
+.b Q
+command in the configuration file.
+.pp
+By default, a queued message is placed in the queue group
+associated with the first recipient in the recipient list.
+A recipient address is mapped to a queue group as follows.
+First, if there is a ruleset called ``queuegroup'',
+and if this ruleset maps the address to a queue group name,
+then that queue group is chosen.
+That is, the argument for the ruleset is the recipient address
+and the result should be
+.b $#
+followed by the name of a queue group.
+Otherwise, if the mailer associated with the address specifies
+a queue group, then that queue group is chosen.
+Otherwise, the default queue group is chosen.
+.pp
+A message with multiple recipients will be split
+if different queue groups are chosen
+by the mapping of recipients to queue groups.
+.pp
+When a message is placed in a queue group, and the queue group has
+more than one queue, a queue is selected randomly.
+.pp
+If a message with multiple recipients is placed into a queue group
+with the 'r' option (maximum number of recipients per message)
+set to a positive value
+.i N ,
+and if there are more than
+.i N
+recipients
+in the message, then the message will be split into multiple messages,
+each of which have at most
+.i N
+recipients.
+.sh 3 "Queue Runs"
+.pp
+.i sendmail
+has two different ways to process the queue(s).
+The first one is to start queue runners after certain intervals
+(``normal'' queue runners),
+the second one is to keep queue runner processes around
+(``persistent'' queue runners).
+How to select either of these types is discussed in the appendix
+``COMMAND LINE FLAGS''.
+Persistent queue runners have the advantage that no new processes
+need to be spawned at certain intervals; they just sleep for
+a specified time after they finished a queue run.
+Another advantage of persistent queue runners is that only one process
+belonging to a workgroup (a workgroup is a set of queue groups)
+collects the data for a queue run
+and then multiple queue runner may go ahead using that data.
+This can significantly reduce the disk I/O necessary to read the
+queue files compared to starting multiple queue runners directly.
+Their disadvantage is that a new queue run is only started
+after all queue runners belonging to a group finished their tasks.
+In case one of the queue runners tries delivery to a slow recipient site
+at the end of a queue run, the next queue run may be substantially delayed.
+In general this should be smoothed out due to the distribution of
+those slow jobs, however, for sites with small number of
+queue entries this might introduce noticable delays.
+In general, persistent queue runners are only useful for
+sites with big queues.
+.sh 3 "Manual Intervention"
.pp
Under normal conditions the mail queue will be processed transparently.
However, you may find that manual intervention is sometimes necessary.
@@ -1032,9 +1197,11 @@ Although
.i sendmail
ought to recover gracefully when the host comes up,
you may find performance unacceptably bad in the meantime.
+In that case you want to check the content of the queue
+and manipulate it as explained in the next two sections.
.sh 3 "Printing the queue"
.pp
-The contents of the queue can be printed
+The contents of the queue(s) can be printed
using the
.i mailq
command
@@ -1049,13 +1216,17 @@ This will produce a listing of the queue id's,
the size of the message,
the date the message entered the queue,
and the sender and recipients.
+If shared memory support is compiled in,
+the flag
+.b \-bP
+can be used to print the number of entries in the queue(s),
+provided a process updates the data.
.sh 3 "Forcing the queue"
.pp
.i Sendmail
-should run the queue automatically
-at intervals.
+should run the queue automatically at intervals.
When using multiple queues,
-a separate process will be created to
+a separate process will by default be created to
run each of the queues
unless the queue run is initiated by a user
with the verbose flag.
@@ -1107,17 +1278,34 @@ You should then kill the existing daemon
(since it will still be processing in the old queue directory)
and create a new daemon.
.pp
-To run the old mail queue,
-run the following command:
+To run the old mail queue, issue the following command:
.(b
-/usr/\*(SD/sendmail \-oQ/var/spool/omqueue \-q
+/usr/\*(SD/sendmail \-C /etc/mail/queue.cf \-q
.)b
The
-.b \-oQ
-flag specifies an alternate queue directory
+.b \-C
+flag specifies an alternate configuration file
+.b queue.cf
+which should refer to the moved queue directory
+.(b
+O QueueDirectory=/var/spool/omqueue
+.)b
and the
.b \-q
flag says to just run every job in the queue.
+You can also specify the moved queue directory on the command line
+.(b
+/usr/\*(SD/sendmail \-oQ/var/spool/omqueue \-q
+.)b
+but this requires that you do not have
+queue groups in the configuration file,
+because those are not subdirectories of the moved directory.
+See the section about "Queue Group Declaration" for details;
+you most likely need a different configuration file to correctly deal
+with this problem.
+However, a proper configuration of queue groups should avoid
+filling up queue directories, so you shouldn't run into
+this problem.
If you have a tendency toward voyeurism,
you can use the
.b \-v
@@ -1132,7 +1320,7 @@ rmdir /var/spool/omqueue
.pp
.i Sendmail
stores a large amount of information about each remote system it
-has connected to in memory. It is now possible to preserve some
+has connected to in memory. It is possible to preserve some
of this information on disk as well, by using the
.b HostStatusDirectory
option, so that it may be shared between several invocations of
@@ -1241,13 +1429,23 @@ aliases files nis
will ask
.i sendmail
to look for hosts in the Domain Name System first.
-If the requested host name is not found,
-it tries local files,
+If the requested host name is not found, it tries local files,
and if that fails it tries NIS.
-Similarly,
-when looking for aliases
-it will try the local files first
-followed by NIS.
+Similarly, when looking for aliases
+it will try the local files first followed by NIS.
+.pp
+Notice: since
+.i sendmail
+must access MX records for correct operation, it will use
+DNS if it is configured in the
+.b ServiceSwitchFile
+file.
+Hence an entry like
+.(b
+hosts files dns
+.)b
+will not avoid DNS lookups even if a host can be found
+in /etc/hosts.
.pp
Service switches are not completely integrated.
For example, despite the fact that the host entry listed in the above example
@@ -1255,14 +1453,6 @@ specifies to look in NIS,
on SunOS this won't happen because the system implementation of
.i gethostbyname \|(3)
doesn't understand this.
-If there is enough demand
-.i sendmail
-may reimplement
-.i gethostbyname \|(3),
-.i gethostbyaddr \|(3),
-.i getpwent \|(3),
-and the other system routines that would be necessary
-to make this work seamlessly.
.sh 2 "The Alias Database"
.pp
After recipient addresses are read from the SMTP connection
@@ -1422,28 +1612,6 @@ flag:
/usr/\*(SD/sendmail \-bi
.)b
.pp
-If the
-.b RebuildAliases
-(old
-.b D )
-option is specified in the configuration,
-.i sendmail
-will rebuild the alias database automatically
-if possible
-when it is out of date.
-Auto-rebuild can be dangerous
-on heavily loaded machines
-with large alias files;
-if it might take more than the rebuild timeout
-(option
-.b AliasWait ,
-old
-.b a ,
-which is normally five minutes)
-to rebuild the database,
-there is a chance that several processes will start the rebuild process
-simultaneously.
-.pp
If you have multiple aliases databases specified,
the
.b \-bi
@@ -1534,6 +1702,9 @@ of using ``\c
as the return address.
.sh 2 "User Information Database"
.pp
+This option is deprecated, use virtusertable and genericstable instead
+as explained in
+.i cf/README .
If you have a version of
.i sendmail
with the user information database
@@ -1582,7 +1753,7 @@ defined by the configuration file.
Others have interpretations built into
.i sendmail
that cannot be changed without changing the code.
-These builtins are described here.
+These built-ins are described here.
.sh 3 "Errors-To:"
.pp
If errors occur anywhere during processing,
@@ -1617,7 +1788,7 @@ One of the possible actions is to add an
header line for any recipients it is aware of.
.pp
The Apparently-To: header is non-standard
-and is deprecated.
+and is both deprecated and strongly discouraged.
.sh 3 "Precedence"
.pp
The Precedence: header can be used as a crude control of message priority.
@@ -1693,27 +1864,32 @@ Some important arguments are described here.
.sh 2 "Queue Interval"
.pp
The amount of time between forking a process
-to run through the queue
-is defined by the
+to run through the queue is defined by the
.b \-q
flag.
If you run with delivery mode set to
.b i
or
.b b
-this can be relatively large,
-since it will only be relevant
+this can be relatively large, since it will only be relevant
when a host that was down comes back up.
If you run in
.b q
-mode
-it should be relatively short,
+mode it should be relatively short,
since it defines the maximum amount of time that a message
may sit in the queue.
(See also the MinQueueAge option.)
.pp
RFC 1123 section 5.3.1.1 says that this value should be at least 30 minutes
(although that probably doesn't make sense if you use ``queue-only'' mode).
+.pp
+Notice: the meaning of the interval time depends on whether normal
+queue runners or persistent queue runners are used.
+For the former, it is the time between subsequent starts of a queue run.
+For the latter, it is the time sendmail waits after a persistent queue
+runner has finished its work to start the next one.
+Hence for persistent queue runners this interval should be very low,
+typically no more than two minutes.
.sh 2 "Daemon Mode"
.pp
If you allow incoming mail over an IPC connection,
@@ -1735,8 +1911,9 @@ flag may be combined in one call:
An alternative approach is to invoke sendmail from
.i inetd (8)
(use the
-.b \-bs
-flag to ask sendmail to speak SMTP on its standard input and output).
+.b \-bs \ \-Am
+flags to ask sendmail to speak SMTP on its standard input and output
+and to run as MTA).
This works and allows you to wrap
.i sendmail
in a TCP wrapper program,
@@ -1764,7 +1941,7 @@ when this is done to watch what happens:
.)b
.pp
You can also limit the jobs to those with a particular queue identifier,
-sender, or recipient
+recipient, sender, or queue group
using one of the queue modifiers.
For example,
.q \-qRberkeley
@@ -1773,40 +1950,77 @@ restricts the queue run to jobs that have the string
somewhere in one of the recipient addresses.
Similarly,
.q \-qSstring
-limits the run to particular senders and
+limits the run to particular senders,
.q \-qIstring
-limits it to particular queue identifiers.
+limits it to particular queue identifiers, and
+.q \-qGstring
+limits it to a particular queue group.
+You may also place an
+.b !
+before the
+.b I
+or
+.b R
+or
+.b S
+to indicate that jobs are limited to not including a particular queue
+identifier, recipient or sender.
+For example,
+.q \-q!Rseattle
+limits the queue run to jobs that do not have the string
+.q seattle
+somewhere in one of the recipient addresses.
+Should you need to terminate the queue jobs currently active then a SIGTERM
+to the parent of the process (or processes) will cleanly stop the jobs.
.sh 2 "Debugging"
.pp
There are a fairly large number of debug flags
built into
.i sendmail .
-Each debug flag has a number and a level,
-where higher levels means to print out more information.
+Each debug flag has a category and a level.
+Higher levels increase the level of debugging activity;
+in most cases, this means to print out more information.
The convention is that levels greater than nine are
.q absurd,
i.e.,
they print out so much information that you wouldn't normally
want to see them except for debugging that particular piece of code.
+.pp
+A debug category is either an integer, like 42,
+or a name, like ANSI.
+You can specify a range of numeric debug categories
+using the syntax 17-42.
+You can specify a set of named debug categories using
+a glob pattern like
+.q sm_trace_* .
+At present, only
+.q *
+and
+.q ?
+are supported in these glob patterns.
+.pp
Debug flags are set using the
.b \-d
option;
the syntax is:
.(b
-.ta \w'debug-option 'u
+.ta \w'debug-categories:M 'u
debug-flag: \fB\-d\fP debug-list
debug-list: debug-option [ , debug-option ]*
-debug-option: debug-range [ . debug-level ]
-debug-range: integer | integer \- integer
+debug-option: debug-categories [ . debug-level ]
+debug-categories: integer | integer \- integer | category-pattern
+category-pattern: [a-zA-Z_*?][a-zA-Z0-9_*?]*
debug-level: integer
.)b
where spaces are for reading ease only.
For example,
.(b
-\-d12 Set flag 12 to level 1
-\-d12.3 Set flag 12 to level 3
-\-d3\-17 Set flags 3 through 17 to level 1
-\-d3\-17.4 Set flags 3 through 17 to level 4
+\-d12 Set category 12 to level 1
+\-d12.3 Set category 12 to level 3
+\-d3\-17 Set categories 3 through 17 to level 1
+\-d3\-17.4 Set categories 3 through 17 to level 4
+\-dANSI Set category ANSI to level 1
+\-dsm_trace_*.3 Set all named categories matching sm_trace_* to level 3
.)b
For a complete list of the available debug flags
you will have to look at the code
@@ -1814,6 +2028,10 @@ and the
.i TRACEFLAGS
file in the sendmail distribution
(they are too dynamic to keep this document up to date).
+For a list of named debug categories in the sendmail binary, use
+.(b
+ident /usr/sbin/sendmail | grep Debug
+.)b
.sh 2 "Changing the Values of Options"
.pp
Options can be overridden using the
@@ -1836,7 +2054,7 @@ the equivalent line using the long option name is
.pp
Some options have security implications.
Sendmail allows you to set these,
-but relinquishes its setuid root permissions thereafter\**.
+but relinquishes its set-user-ID or set-group-ID permissions thereafter\**.
.(f
\**That is, it sets its effective uid to the real uid;
thus, if you are executing as root,
@@ -1864,7 +2082,8 @@ it defaults to
in the current directory.
.pp
.i Sendmail
-gives up its setuid root permissions
+gives up set-user-ID root permissions
+(if it has been installed set-user-ID root)
when you use this flag, so it is common to use a publicly writable directory
(such as /tmp)
as the queue directory (QueueDirectory or Q option) while testing.
@@ -1965,8 +2184,8 @@ This version requires that you use:
.pp
As of version 8.7,
some other syntaxes are available in test mode:
-.bu
-\&.D\|x\|value
+.nr ii 1i
+.ip \&.D\|x\|value
defines macro
.i x
to have the indicated
@@ -1975,18 +2194,47 @@ This is useful when debugging rules that use the
.b $& \c
.i x
syntax.
-.bu
-\&.C\|c\|value
+.ip \&.C\|c\|value
adds the indicated
.i value
to class
.i c .
-.bu
-\&.S\|ruleset
+.ip \&=S\|ruleset
dumps the contents of the indicated ruleset.
-.bu
-\-d\|debug-spec
+.ip \-d\|debug-spec
is equivalent to the command-line flag.
+.lp
+Version 8.9 introduced more features:
+.nr ii 1i
+.ip ?
+shows a help message.
+.ip =M
+display the known mailers.
+.ip $m
+print the value of macro m.
+.ip $=c
+print the contents of class c.
+.ip /mx\ host
+returns the MX records for `host'.
+.ip /parse\ address
+parse address, returning the value of
+.i crackaddr ,
+and the parsed address.
+.ip /try\ mailer\ addr
+rewrite address into the form it will have when
+presented to the indicated mailer.
+.ip /tryflags\ flags
+set flags used by parsing. The flags can be `H' for
+Header or `E' for Envelope, and `S' for Sender or `R'
+for Recipient. These can be combined, `HR' sets
+flags for header recipients.
+.ip /canon\ hostname
+try to canonify hostname.
+.ip /map\ mapname\ key
+look up `key' in the indicated `mapname'.
+.ip /quit
+quit address test mode.
+.lp
.sh 2 "Persistent Host Status Information"
.pp
When
@@ -2072,22 +2320,22 @@ w weeks
.pp
The argument to the
.b \-q
-flag
-specifies how often a sub-daemon will run the queue.
-This is typically set to between fifteen minutes
-and one hour.
-If not set,
-or set to zero,
+flag specifies how often a sub-daemon will run the queue.
+This is typically set to between fifteen minutes and one hour.
+If not set, or set to zero,
the queue will not be run automatically.
RFC 1123 section 5.3.1.1 recommends that this be at least 30 minutes.
+Should you need to terminate the queue jobs currently active then a SIGTERM
+to the parent of the process (or processes) will cleanly stop the jobs.
.sh 3 "Read timeouts"
.pp
Timeouts all have option names
.q Timeout.\fIsuboption\fP .
+Most of these control SMTP operations.
The recognized
.i suboption s,
their default values, and the minimum values
-allowed by RFC 1123 section 5.3.2 are:
+allowed by RFC 2821 section 4.5.3.2 (or RFC 1123 section 5.3.2) are:
.nr ii 1i
.ip connect
The time to wait for an SMTP connection to open
@@ -2110,6 +2358,18 @@ The concept is that this should be very short (a few seconds);
hosts that are well connected and responsive will thus be serviced immediately.
Hosts that are slow will not hold up other deliveries in the initial
delivery attempt.
+.ip aconnect
+[0, unspecified]
+The overall timeout waiting for all connection for a single delivery
+attempt to succeed.
+If 0, no overall limit is applied.
+This can be used to restrict the total amount of time trying to connect to
+a long list of host that could accept an e-mail for the recipient.
+This timeout does not apply to
+.b FallbackMXhost ,
+i.e., if the time is exhausted, the
+.b FallbackMXhost
+is tried next.
.ip initial
The wait for the initial 220 greeting message
[5m, 5m].
@@ -2162,10 +2422,19 @@ the time to wait for another command.
[1h, 5m].
.ip ident\(dd
The timeout waiting for a reply to an IDENT query
-[30s\**, unspecified].
+[5s\**, unspecified].
.(f
\**On some systems the default is zero to turn the protocol off entirely.
.)f
+.ip lhlo
+The wait for a reply to an LMTP LHLO command
+[2m, unspecified].
+.ip auth
+The timeout for a reply in an SMTP AUTH dialogue
+[10m, unspecified].
+.ip starttls
+The timeout for a reply to an SMTP STARTTLS command and the TLS handshake
+[1h, unspecified].
.ip fileopen\(dd
The timeout for opening .forward and :include: files [60s, none].
.ip control\(dd
@@ -2175,7 +2444,7 @@ How long status information about a host
(e.g., host down)
will be cached before it is considered stale
[30m, unspecified].
-.ip resolver.retrans
+.ip resolver.retrans\(dd
The resolver's
retransmission time interval
(in seconds)
@@ -2184,21 +2453,21 @@ Sets both
.i Timeout.resolver.retrans.first
and
.i Timeout.resolver.retrans.normal .
-.ip resolver.retrans.first
+.ip resolver.retrans.first\(dd
The resolver's
retransmission time interval
(in seconds)
for the first attempt to
deliver a message
[varies].
-.ip resolver.retrans.normal
+.ip resolver.retrans.normal\(dd
The resolver's
retransmission time interval
(in seconds)
for all resolver lookups
except the first delivery attempt
[varies].
-.ip resolver.retry
+.ip resolver.retry\(dd
The number of times
to retransmit a resolver query.
Sets both
@@ -2206,13 +2475,13 @@ Sets both
and
.i Timeout.resolver.retry.normal
[varies].
-.ip resolver.retry.first
+.ip resolver.retry.first\(dd
The number of times
to retransmit a resolver query
for the first attempt
to deliver a message
[varies].
-.ip resolver.retry.normal
+.ip resolver.retry.normal\(dd
The number of times
to retransmit a resolver query
for all resolver lookups
@@ -2230,32 +2499,6 @@ All but those marked with
.DD
(\(dd) apply to client SMTP.
.pp
-Many of the RFC 1123 minimum values
-may well be too short.
-.i Sendmail
-was designed to the RFC 822 protocols,
-which did not specify read timeouts;
-hence, versions of
-.i sendmail
-prior to version 8.1 did not guarantee to reply to messages promptly.
-In particular, a
-.q RCPT
-command specifying a mailing list
-will expand and verify the entire list;
-a large list on a slow system
-may easily take more than five minutes\**.
-.(f
-\**This verification includes looking up every address
-with the name server;
-this involves network delays,
-and can in some cases can be considerable.
-.)f
-I recommend a one hour timeout \*-
-since a communications failure during the RCPT phase is rare,
-a long timeout is not onerous
-and may ultimately help reduce network load
-and duplicated messages.
-.pp
For example, the lines:
.(b
O Timeout.command=25m
@@ -2266,7 +2509,7 @@ and the input data block timeout to three hours.
.sh 3 "Message timeouts"
.pp
After sitting in the queue for a few days,
-a message will time out.
+an undeliverable message will time out.
This is to insure that at least the sender is aware
of the inability to send a message.
The timeout is typically set to five days.
@@ -2313,7 +2556,7 @@ to return entries immediately during a queue run,
e.g., to bounce messages independent of their time in the queue.
.pp
Since these options are global,
-and since you can not know
+and since you cannot know
.i "a priori"
how long another host outside your domain will be down,
a five day timeout is recommended.
@@ -2347,11 +2590,13 @@ option,
.i sendmail
will fork before each individual message
while running the queue.
-This will prevent
+This option was used with earlier releases to prevent
.i sendmail
-from consuming large amounts of memory,
-so it may be useful in memory-poor environments.
-However, if the
+from consuming large amounts of memory.
+It should no longer be necessary with
+.i sendmail
+8.12.
+If the
.b ForkEachJob
option is not set,
.i sendmail
@@ -2362,7 +2607,7 @@ If the
.b ForkEachJob
option is set,
.i sendmail
-can not use connection caching.
+cannot use connection caching.
.sh 2 "Queue Priorities"
.pp
Every message is assigned a priority when it is first instantiated,
@@ -2430,27 +2675,23 @@ option defaults to 90000.
.sh 2 "Load Limiting"
.pp
.i Sendmail
-can be asked to queue (but not deliver)
-mail if the system load average gets too high
-using the
+can be asked to queue (but not deliver) mail
+if the system load average gets too high using the
.b QueueLA
(\c
.b x )
option.
When the load average exceeds the value of the
.b QueueLA
-option,
-the delivery mode is set to
+option, the delivery mode is set to
.b q
-(queue only)
-if the
+(queue only) if the
.b QueueFactor
(\c
.b q )
option divided by the difference in the current load average and the
.b QueueLA
-option
-plus one
+option plus one
is less than the priority of the message \(em
that is, the message is queued iff:
.EQ
@@ -2459,22 +2700,22 @@ pri > { bold QueueFactor } over { LA - { bold QueueLA } + 1 }
The
.b QueueFactor
option defaults to 600000,
-so each point of load average is worth 600000
-priority points
+so each point of load average is worth 600000 priority points
(as described above).
.pp
-For drastic cases,
-the
+For drastic cases, the
.b RefuseLA
(\c
.b X )
option defines a load average at which
.i sendmail
-will refuse
-to accept network connections.
-Locally generated mail
-(including incoming UUCP mail)
+will refuse to accept network connections.
+Locally generated mail, i.e., mail which is not submitted via SMTP
+(including incoming UUCP mail),
is still accepted.
+Notice that the MSP submits mail to the MTA via SMTP, and hence
+mail will be queued in the client queue in such a case.
+Therefore it is necessary to run the client mail queue periodically.
.sh 2 "Delivery Mode"
.pp
There are a number of delivery modes that
@@ -2514,7 +2755,9 @@ Mode
.q d
is identical to mode
.q q
-except that it also prevents all the early map lookups from working;
+except that it also prevents lookups in maps including the
+.b -D
+flag from working during the initial queue phase;
it is intended for ``dial on demand'' sites where DNS lookups
might cost real money.
Some simple error messages
@@ -2538,7 +2781,7 @@ upon initial receipt of the mail.
This speeds up the response to RCPT commands.
Mode
.q i
-cannot be used by the SMTP server.
+should not be used by the SMTP server.
.sh 2 "Log Level"
.pp
The level of logging can be set for
@@ -2610,9 +2853,18 @@ option to turn off some of these checks.
.sh 3 "To suid or not to suid?"
.pp
.i Sendmail
-is normally installed
-setuid to root.
-At the point where it is about to
+is no longer installed
+set-user-ID to root.
+sendmail/SECURITY
+explains how to configure and install
+.i sendmail
+without set-user-ID to root but set-group-ID
+which is the default configuration starting with 8.12.
+.pp
+The daemon usually runs as root, unless other measures are taken.
+At the point where
+.i sendmail
+is about to
.i exec \|(2)
a mailer,
it checks to see if the userid is zero (root);
@@ -2638,36 +2890,7 @@ to be accounted
to root
rather than to the user sending the mail.
.pp
-If you don't make
-.i sendmail
-setuid to root, it will still run but you lose a lot of functionality
-and a lot of privacy, since you'll have to make the queue directory
-world readable.
-You could also make
-.i sendmail
-setuid to some pseudo-user
-(e.g., create a user called
-.q sendmail
-and make
-.i sendmail
-setuid to that)
-which will fix the privacy problems
-but not the functionality issues.
-It also introduces problems on some operating systems
-if sendmail needs to give up the setuid special privileges.
-Also, this isn't a guarantee of security:
-for example,
-root occasionally sends mail,
-and the daemon often runs as root.
-Note however that
-.i sendmail
-must run as root or the trusted user in order to create the SMTP listener
-socket.
-.pp
-A middle ground is to make
-.i sendmail
-setuid to root,
-but set the
+A middle ground is to set the
.b RunAsUser
option.
This causes
@@ -2714,6 +2937,11 @@ that are group writable
on the grounds that they might have been tampered with
by someone other than the owner;
it will even refuse to read files in group writable directories.
+Also, sendmail will refuse to create a new aliases database in an
+unsafe directory. You can get around this by manually creating the
+database file as a trusted user ahead of time and then rebuilding the
+aliases database with
+.b newaliases .
.pp
If you are
.i quite
@@ -2772,6 +3000,10 @@ Allow a
.i \&.forward
file that is in an unsafe directory to include references
to program and files.
+.ip GroupReadableKeyFile
+Accept a group-readable key file for STARTTLS.
+.ip GroupReadableSASLDBFile
+Accept a group-readable Cyrus SASL password file.
.ip GroupWritableAliasFile
Allow group-writable alias files.
.ip GroupWritableDirPathSafe
@@ -2779,14 +3011,24 @@ Change the definition of
.q "unsafe directory"
to consider group-writable directories to be safe.
World-writable directories are always unsafe.
+.ip GroupWritableForwardFile
+Allow group writable
+.i \&.forward
+files.
.ip GroupWritableForwardFileSafe
Accept group-writable
.i \&.forward
files as safe for program and file delivery.
+.ip GroupWritableIncludeFile
+Allow group wriable
+.i :include:
+files.
.ip GroupWritableIncludeFileSafe
Accept group-writable
.i :include:
files as safe for program and file delivery.
+.ip GroupWritableSASLDBFile
+Accept a group-writable Cyrus SASL password file.
.ip HelpFileInUnsafeDirPath
Allow the file named in the
.b HelpFile
@@ -2821,6 +3063,7 @@ Allow
files that are links in writable directories.
.ip LinkedMapInWritableDir
Allow map files that are links in writable directories.
+This includes alias database files.
.ip LinkedServiceSwitchFileInWritableDir
Allow the service switch file to be a link
even if the directory is writable.
@@ -2832,13 +3075,14 @@ and
.i dbm
files)
in unsafe directories.
+This includes alias database files.
.ip NonRootSafeAddr
Do not mark file and program deliveries as unsafe
if sendmail is not running with root privileges.
.ip RunProgramInUnsafeDirPath
-Go ahead and run programs that are in writable directories.
+Run programs that are in writable directories without logging a warning.
.ip RunWritableProgram
-Go ahead and run programs that are group- or world-writable.
+Run programs that are group- or world-writable without logging a warning.
.ip TrustStickyBit
Allow group or world writable directories
if the sticky bit is set on the directory.
@@ -2846,6 +3090,14 @@ Do not set this on systems which do not honor
the sticky bit on directories.
.ip WorldWritableAliasFile
Accept world-writable alias files.
+.ip WorldWritableForwardfile
+Allow world writable
+.i \&.forward
+files.
+.ip WorldWritableIncludefile
+Allow world wriable
+.i :include:
+files.
.ip WriteMapToHardLink
Allow writes to maps that are hard links.
.ip WriteMapToSymLink
@@ -2980,13 +3232,24 @@ turns on the AAONLY (accept authoritative answers only)
and turns off the DNSRCH (search the domain path) options.
Most resolver libraries default DNSRCH, DEFNAMES, and RECURSE
flags on and all others off.
+If NETINET6 is enabled, most libraries default to USE_INET6 as well.
You can also include
.q HasWildcardMX
to specify that there is a wildcard MX record matching your domain;
this turns off MX matching when canonifying names,
which can lead to inappropriate canonifications.
-.pp
-Version level 1 configurations
+Use
+.q WorkAroundBrokenAAAA
+when faced with a a broken nameservers that returns SERVFAIL
+(a temporary failure)
+on T_AAAA (IPv6) lookups
+during hostname canonification.
+Notice: it might be necessary to apply the same (or similar) options to
+.i submit.cf
+too.
+.pp
+Version level 1 configurations (see the section about
+Configuration Version Level)
turn DNSRCH and DEFNAMES off when doing delivery lookups,
but leave them on everywhere else.
Version 8 of
@@ -3026,7 +3289,8 @@ when linking.
Some sites mount each user's home directory
from a local disk on their workstation,
so that local access is fast.
-However, the result is that .forward file lookups are slow.
+However, the result is that .forward file lookups
+from a central mail server are slow.
In some cases,
mail can even be delivered on machines inappropriately
because of a file server being down.
@@ -3056,14 +3320,13 @@ it should be mode 1777
(that is, the sticky bit should be set).
Users should create the files mode 644.
Note that you must use the
-forwardfileinunsafedirpath and
-forwardfileinunsafedirpathsafe
-flags with the DontBlameSendmail option
-to allow forward files in a world
-writable directory.
-This might also be used as a
-denial of service
-attack (users could create forward files for other users);
+ForwardFileInUnsafeDirPath and
+ForwardFileInUnsafeDirPathSafe
+flags with the
+.b DontBlameSendmail
+option to allow forward files in a world writable directory.
+This might also be used as a denial of service attack
+(users could create forward files for other users);
a better approach might be to create
/var/forward
mode 755
@@ -3162,10 +3425,11 @@ since this is done every time
.i sendmail
starts up,
rather than easy for a human to read or write.
-On the
-.q "future project"
-list is a
-configuration-file compiler.
+The configuration file should be generated via the method described in
+.b cf/README ,
+it should not be edited directly unless someone is familiar
+with the internals of the syntax described here and it is
+not possible to achieve the desired result via the default method.
.pp
The configuration file is organized as a series of lines,
each of which begins with a single character
@@ -3432,7 +3696,7 @@ and
may be multi-part.
If the
.i mailer
-is the builtin IPC mailer,
+is the built-in IPC mailer,
the
.i host
may be a colon-separated list of hosts
@@ -3653,7 +3917,12 @@ Many of these can also resolve to the special mailer name
this accepts the message as though it were successful
but then discards it without delivery.
Note,
-this mailer can not be chosen as a mailer in ruleset 0.
+this mailer cannot be chosen as a mailer in ruleset 0.
+Note also that all
+.q check_*
+rulesets have to deal with temporary failures, especially for map lookups,
+themselves, i.e., they should return a temporary error code
+or at least they should make a proper decision in those cases.
.sh 4 "check_relay"
.pp
The
@@ -3686,6 +3955,14 @@ ruleset is passed the user name parameter of the
.sm "SMTP RCPT"
command.
It can accept or reject the address.
+.sh 4 "check_data"
+.pp
+The
+.i check_data
+ruleset is called after the
+.sm "SMTP DATA"
+command, its parameter is the number of recipients.
+It can accept or reject the command.
.sh 4 "check_compat"
.pp
The
@@ -3817,6 +4094,103 @@ If the ruleset does resolve to the
.q error
mailer, the connection is aborted
(treated as non-deliverable with a permanent or temporary error).
+.sh 4 "tls_rcpt"
+.pp
+The
+.i tls_rcpt
+ruleset is called each time before a RCPT TO command is sent.
+The parameter is the current recipient.
+If the ruleset does resolve to the
+.q error
+mailer, the RCPT TO command is suppressed
+(treated as non-deliverable with a permanent or temporary error).
+This ruleset allows to require encryption or verification of
+the recipient's MTA even if the mail is somehow redirected
+to another host.
+For example, sending mail to
+.i luke@endmail.org
+may get redirected to a host named
+.i death.star
+and hence the tls_server ruleset won't apply.
+By introducing per recipient restrictions such attacks
+(e.g., via DNS spoofing) can be made impossible.
+See
+.i cf/README
+how this ruleset can be used.
+.sh 4 "srv_features"
+.pp
+The
+.i srv_features
+ruleset is called when a client connects to sendmail.
+This ruleset should return
+.b $#
+followed by a list of options (single characters
+delimited by white space).
+If the return value starts with anything else it is silently ignored.
+Generally upper case characters turn off a feature
+while lower case characters turn it on.
+The option `S' causes the server not to offer STARTTLS.
+This is useful to interact with MTAs/MUAs that have broken
+STARTTLS implementations by simply not offering it.
+`V' turns off the request for a client certificate
+during the TLS handshake.
+Option `A' and `P' suppress SMTP AUTH and PIPELINING, respectively.
+The ruleset may return `$#temp' to indicate that there is a temporary
+problem determining the correct features, e.g., if a map is unavailable.
+In that case, the SMTP server issues a temporary failure and does not
+accept email.
+.sh 4 "try_tls"
+.pp
+The
+.i try_tls
+ruleset is called when sendmail connects to another MTA.
+If the ruleset does resolve to the
+.q error
+mailer, sendmail does not try STARTTLS even if it is offered.
+This is useful to interact with MTAs that have broken
+STARTTLS implementations by simply not using it.
+.sh 4 "authinfo"
+.pp
+The
+.i authinfo
+ruleset is called when sendmail tries to authenticate to another MTA.
+It should return
+.b $#
+followed by a list of tokens that are used for SMTP AUTH.
+If the return value starts with anything else it is silently ignored.
+Each token is a tagged string of the form:
+"TDstring"
+(including the quotes), where
+.(b
+.ta 9n
+T Tag which describes the item
+D Delimiter: ':' simple text follows
+ '=' string is base64 encoded
+string Value of the item
+.)b
+Valid values for the tag are:
+.(b
+.ta 9n
+U user (authorization) id
+I authentication id
+P password
+R realm
+M list of mechanisms delimited by spaces
+.)b
+If this ruleset is defined, the option
+.b DefaultAuthInfo
+is ignored (even if the ruleset does not return a ``useful'' result).
+.sh 4 "queuegroup"
+.pp
+The
+.i queuegroup
+ruleset is used to map an address to a queue group name.
+It should return
+.b $#
+followed by the name of a queue group.
+If the return value starts with anything else it is silently ignored.
+See the section about Queue Groups and Queue Directories
+for further information.
.sh 3 "IPC mailers"
.pp
Some special processing occurs
@@ -3831,11 +4205,16 @@ The host name passed after
has MX expansion performed if not delivering via a named socket;
this looks the name up in DNS to find alternate delivery sites.
.pp
-The host name can also be provided as a dotted quad in square brackets;
+The host name can also be provided as a dotted quad
+or an IPv6 address in square brackets;
for example:
.(b
[128.32.149.78]
.)b
+or
+.(b
+[IPv6:2002:c0a8:51d2::23f4]
+.)b
This causes direct conversion of the numeric value
to an IP host address.
.pp
@@ -3934,19 +4313,6 @@ The
.b $| )
clause may be omitted.
.pp
-Lower case macro names are reserved to have
-special semantics,
-used to pass information in or out of
-.i sendmail ,
-and special characters are reserved to
-provide conditionals, etc.
-Upper case names
-(that is,
-.b $A
-through
-.b $Z )
-are specifically reserved for configuration file authors.
-.pp
The following macros are defined and/or used internally by
.i sendmail
for interpolation into argv's for mailers
@@ -4005,7 +4371,7 @@ This is set in ruleset 0 from the $@ field of a parsed address.
.ip $i
The queue id,
e.g.,
-.q HAA12345 .
+.q f344MXxp018717 .
.ip $j\(dd
The \*(lqofficial\*(rq domain name for this site.
This is fully qualified if the full qualification can be found.
@@ -4106,15 +4472,28 @@ The full name of the sender.
The home directory of the recipient.
.ip $_
The validated sender address.
+See also
+.b ${client_resolve} .
+.ip ${addr_type}
+The type of the address which is currently being rewritten.
+This macro contains up to three characters, the first
+is either `e' or `h' for envelope/header address,
+the second is a space,
+and the third is either `s' or `r' for sender/recipient address.
+Notice: for header addresses no distinction is currently made
+between sender and recipient addresses, i.e., the macro contains
+only `h'.
.ip ${auth_authen}
The client's authentication credentials as determined by authentication
(only set if successful).
+The format depends on the mechanism used, it might be just `user',
+or `user@realm', or something similar (SMTP AUTH only).
.ip ${auth_author}
The authorization identity, i.e. the AUTH= parameter of the
.sm "SMTP MAIL"
command if supplied.
.ip ${auth_type}
-The mechanism used for authentication
+The mechanism used for SMTP authentication
(only set if successful).
.ip ${auth_ssf}
The keylength (in bits) of the symmetric encryption algorithm
@@ -4125,44 +4504,74 @@ The message body type
as determined from the envelope.
.ip ${cert_issuer}
The DN (distinguished name) of the CA (certificate authority)
-that signed the presented certificate (the cert issuer).
+that signed the presented certificate (the cert issuer)
+(STARTTLS only).
+.ip ${cert_md5}
+The MD5 hash of the presented certificate (STARTTLS only).
.ip ${cert_subject}
-The DN of the presented certificate (called the cert subject).
+The DN of the presented certificate (called the cert subject)
+(STARTTLS only).
.ip ${cipher}
The cipher suite used for the connection, e.g., EDH-DSS-DES-CBC3-SHA,
-EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA.
+EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA
+(STARTTLS only).
.ip ${cipher_bits}
The keylength (in bits) of the symmetric encryption algorithm
used for a TLS connection.
.ip ${client_addr}
The IP address of the SMTP client.
+IPv6 addresses are tagged with "IPv6:" before the address.
Defined in the SMTP server only.
.ip ${client_name}
The host name of the SMTP client.
This may be the client's bracketed IP address
-in the form [ nnn.nnn.nnn.nnn ] if the client's
+in the form [ nnn.nnn.nnn.nnn ] for IPv4
+and [ IPv6:nnnn:...:nnnn ] for IPv6
+if the client's
IP address is not resolvable, or if it is resolvable
but the IP address of the resolved hostname
doesn't match the original IP address.
Defined in the SMTP server only.
+See also
+.b ${client_resolve} .
.ip ${client_port}
The port number of the SMTP client.
Defined in the SMTP server only.
.ip ${client_resolve}
Holds the result of the resolve call for
-.b ${client_name}
-: OK, FAIL, FORGED, TEMP.
+.b ${client_name} .
+Possible values are:
+.(b
+.ta 10n
+OK resolved successfully
+FAIL permanent lookup failure
+FORGED forward lookup doesn't match reverse lookup
+TEMP temporary lookup failure
+.)b
Defined in the SMTP server only.
+.i sendmail
+performs a hostname lookup on the IP address of the connecting client.
+Next the IP addresses of that hostname are looked up.
+If the client IP address does not appear in that list,
+then the hostname is maybe forged.
+This is reflected as the value FORGED for
+.b ${client_resolve}
+and it also shows up in
+.b $_
+as "(may be forged)".
+.ip ${cn_issuer}
+The CN (common name) of the CA that signed the presented certificate
+(STARTTLS only).
+.ip ${cn_subject}
+The CN (common name) of the presented certificate
+(STARTTLS only).
.ip ${currHeader}
Header value as quoted string
(possibly truncated to
.b MAXNAME ).
+This macro is only available in header check rulesets.
.ip ${daemon_addr}
The IP address the daemon is listening on for connections.
-Unless
-.b DaemonPortOptions
-is set, this will be
-.q 0.0.0.0 .
.ip ${daemon_family}
The network family
if the daemon is accepting network connections.
@@ -4208,32 +4617,43 @@ It is initially set to the value of the
.b DeliveryMode
option.
.ip ${envid}
-The envelope id passed to sendmail as part of the envelope.
+The envelope id parameter (ENVID=) passed to sendmail as part of the envelope.
.ip ${hdrlen}
The length of the header value which is stored in
${currHeader} (before possible truncation).
-If this value is greater than or equal
+If this value is greater than or equal to
.b MAXNAME
the header has been truncated.
.ip ${hdr_name}
The name of the header field for which the current header
check ruleset has been called.
This is useful for a default header check ruleset to get
-the name of the header.
+the name of the header;
+the macro is only available in header check rulesets.
.ip ${if_addr}
The IP address of the interface of an incoming connection
unless it is in the loopback net.
+IPv6 addresses are tagged with "IPv6:" before the address.
+.ip ${if_addr_out}
+The IP address of the interface of an outgoing connection
+unless it is in the loopback net.
+IPv6 addresses are tagged with "IPv6:" before the address.
.ip ${if_family}
The IP family of the interface of an incoming connection
unless it is in the loopback net.
+.ip ${if_family_out}
+The IP family of the interface of an outgoing connection
+unless it is in the loopback net.
.ip ${if_name}
-The name of the interface of an incoming connection.
+The hostname associated with the interface of an incoming connection.
This macro can be used for
SmtpGreetingMessage and HReceived for virtual hosting.
For example:
.(b
O SmtpGreetingMessage=$?{if_name}${if_name}$|$j$. MTA
.)b
+.ip ${if_name_out}
+The name of the interface of an outgoing connection.
.ip ${mail_addr}
The address part of the resolved triple of the address given for the
.sm "SMTP MAIL"
@@ -4256,6 +4676,12 @@ before the message has been collected, thereafter
the message size as computed by
.i sendmail
(and can be used in check_compat).
+.ip ${nrcpts}
+The number of validated recipients for a single message.
+Note: since recipient validation happens after
+.i check_rcpt
+has been called, the value in this ruleset
+is one less than what might be expected.
.ip ${ntries}
The number of delivery attempts.
.ip ${opMode}
@@ -4276,36 +4702,40 @@ to
The address part of the resolved triple of the address given for the
.sm "SMTP RCPT"
command.
-Defined in the SMTP server only.
+Defined in the SMTP server only after a RCPT command.
.ip ${rcpt_host}
The host from the resolved triple of the address given for the
.sm "SMTP RCPT"
command.
-Defined in the SMTP server only.
+Defined in the SMTP server only after a RCPT command.
.ip ${rcpt_mailer}
The mailer from the resolved triple of the address given for the
.sm "SMTP RCPT"
command.
-Defined in the SMTP server only.
+Defined in the SMTP server only after a RCPT command.
.ip ${server_addr}
The address of the server of the current outgoing SMTP connection.
+For LMTP delivery the macro is set to the name of the mailer.
.ip ${server_name}
-The name of the server of the current outgoing SMTP connection.
+The name of the server of the current outgoing SMTP or LMTP connection.
.ip ${tls_version}
-The TLS/SSL version used for the connection, e.g., TLSv1, SSLv3, SSLv2.
+The TLS/SSL version used for the connection, e.g., TLSv1, SSLv3, SSLv2;
+defined after STARTTLS has been used.
.ip ${verify}
-The result of the verification of the presented cert.
+The result of the verification of the presented cert;
+only defined after STARTTLS has been used.
Possible values are:
.(b
-.ta 9n
+.ta 13n
OK verification succeeded.
NO no cert presented.
+NOT no cert requested.
FAIL cert presented but could not be verified,
e.g., the signing CA is missing.
NONE STARTTLS has not been performed.
TEMP temporary error occurred.
-PROTOCOL some protocol error occurred.
-SOFTWARE STARTTLS handshake failed,
+PROTOCOL some protocol error occurred.
+SOFTWARE STARTTLS handshake failed,
which is a fatal error for this session,
the e-mail will be queued.
.)b
@@ -4552,6 +4982,9 @@ The syntax is:
.br
.b F \c
.i c\||program
+.br
+.b F \c
+.i c\|[mapkey]@mapclass:mapspec
.)b
The first form defines the class
.i c
@@ -4582,18 +5015,47 @@ The ``F'' forms
read the elements of the class
.i c
from the named
-.i file
+.i file ,
+.i program ,
or
-.i program .
+.i "map specification" .
Each element should be listed on a separate line.
-To specify an optional file, use ``-o'' between the class
+To specify an optional file, use ``\-o'' between the class
name and the file name, e.g.,
.(b
-Fc -o /path/to/file
+Fc \-o /path/to/file
.)b
If the file can't be used,
.i sendmail
will not complain but silently ignore it.
+The map form should be an optional map key, an at sign,
+and a map class followed by the specification for that map.
+Examples include:
+.(b
+F{VirtHosts}@ldap:\-k (&(objectClass=virtHosts)(host=*)) \-v host
+F{MyClass}foo@hash:/etc/mail/classes
+.)b
+will fill the class
+.b $={VirtHosts}
+from an LDAP map lookup and
+.b $={MyClass}
+from a hash database map lookup of the
+.b foo .
+There is also a built-in schema that can be accessed by only specifying:
+.(b
+F{\c
+.i ClassName }@LDAP
+.)b
+This will tell sendmail to use the default schema:
+.(b
+\-k (&(objectClass=sendmailMTAClass)
+ (sendmailMTAClassName=\c
+.i ClassName )
+ (|(sendmailMTACluster=${sendmailMTACluster})
+ (sendmailMTAHost=$j)))
+\-v sendmailMTAClassValue
+.)b
+Note that the lookup is only done when sendmail is initially started.
.pp
Elements of classes can be accessed in rules using
.b $=
@@ -4729,6 +5191,7 @@ Path The pathname of the mailer
Flags Special flags for this mailer
Sender Rewriting set(s) for sender addresses
Recipient Rewriting set(s) for recipient addresses
+recipients Maximum number of recipients per connection
Argv An argument vector to pass to this mailer
Eol The end-of-line string for this mailer
Maxsize The maximum message length to this mailer
@@ -4740,9 +5203,11 @@ Nice The nice(2) increment for the mailer
Charset The default character set for 8-bit characters
Type Type information for DSN diagnostics
Wait The maximum time to wait for the mailer
+Queuegroup The default queue group for the mailer
/ The root directory for the mailer
.)b
-Only the first character of the field name is checked.
+Only the first character of the field name is checked
+(it's case-sensitive).
.pp
The following flags may be set in the mailer description.
Any other flags may be used freely
@@ -4870,10 +5335,10 @@ to another
.i sendmail
\*-
as such it can use special protocol features.
-This option is not required
-(i.e.,
-if this option is omitted the transmission will still operate successfully,
-although perhaps not as efficiently as possible).
+This flag should not be used except for debugging purposes
+because it uses
+.b VERB
+as SMTP command.
.ip j
Do User Database rewriting on recipients as well as senders.
.ip k
@@ -4972,6 +5437,8 @@ Secure ports aren't
(secure, that is)
except on UNIX machines,
so it is unclear that this adds anything.
+.i sendmail
+must be running as root to be able to use this flag.
.ip s
Strip quote characters (" and \e) off of the address
before calling the mailer.
@@ -5001,10 +5468,12 @@ on the end.
.ip w
The user must have a valid account on this machine,
i.e.,
-getpwnam
+.i getpwnam
must succeed.
-If not,
-the mail is bounced.
+If not, the mail is bounced.
+See also the
+.b MailBoxDatabase
+option.
This is required to get
.q \&.forward
capability.
@@ -5013,11 +5482,8 @@ This mailer wants a
.q Full-Name:
header line.
.ip X
-This mailer want to use the hidden dot algorithm
-as specified in RFC821;
-basically,
-any line beginning with a dot
-will have an extra dot prepended
+This mailer wants to use the hidden dot algorithm as specified in RFC821;
+basically, any line beginning with a dot will have an extra dot prepended
(to be stripped at the other end).
This insures that lines in the message containing a dot
will not terminate the message prematurely.
@@ -5029,8 +5495,19 @@ and the local mailer.
This is a variant on SMTP
defined in RFC 2033
that is specifically designed for delivery to a local mailbox.
+.ip Z
+Apply DialDelay (if set) to this mailer.
.ip 0
-Don't look up MX records for hosts sent via SMTP.
+Don't look up MX records for hosts sent via SMTP/LMTP.
+Do not apply
+.b FallbackMXhost
+either.
+.ip 1
+Don't send null characters ('\\0') to this mailer.
+.ip 2
+Don't use ESMTP even if offered; this is useful for broken
+systems that offer ESMTP but fail on EHLO (without recovering
+when HELO is tried next).
.ip 3
Extend the list of characters converted to =XX notation
when converting to Quoted-Printable
@@ -5124,7 +5601,7 @@ The mailer with the special name
.q discard
causes any mail sent to it to be discarded
but otherwise treated as though it were successfully delivered.
-This mailer can not be used in ruleset 0,
+This mailer cannot be used in ruleset 0,
only in the various address checking rulesets.
.pp
The mailer named
@@ -5148,13 +5625,31 @@ M*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE $u
M*include*, P=/dev/null, F=su, A=INCLUDE $u
.)b
.pp
+Builtin pathnames are [FILE] and [IPC], the former is used for
+delivery to files, the latter for delivery via interprocess communication.
+For mailers that use [IPC] as pathname the argument vector (A=)
+must start with TCP or FILE for delivery via a TCP or a Unix domain socket.
+If TCP is used, the second argument must be the name of the host
+to contact.
+Optionally a third argument can be used to specify a port,
+the default is smtp (port 25).
+If FILE is used, the second argument must be the name of
+the Unix domain socket.
+.pp
+If the argument vector does not contain $u then
+.i sendmail
+will speak SMTP (or LMTP if the mailer flag z is specified) to the mailer.
+.pp
+If no Eol field is defined, then the default is "\\r\\n" for
+SMTP mailers and "\\n" of others.
+.pp
The Sender and Recipient rewriting sets
may either be a simple ruleset id
or may be two ids separated by a slash;
if so, the first rewriting set is applied to envelope
addresses
and the second is applied to headers.
-Setting any value zero disables corresponding mailer-specific rewriting.
+Setting any value to zero disables corresponding mailer-specific rewriting.
.pp
The Directory
is actually a colon-separated path of directories to try.
@@ -5168,7 +5663,7 @@ This is intended to be used only on the
mailer,
since some shells (such as
.i csh )
-refuse to execute if they cannot read the home directory.
+refuse to execute if they cannot read the current directory.
Since the queue directory is not normally readable by unprivileged users
.i csh
scripts as recipients can fail.
@@ -5232,8 +5727,13 @@ or begin with
The default is
.q dns/rfc822/smtp .
.pp
-The m= field specifies the maximum number of messages to attempt to deliver
-on a single SMTP or LMTP connection.
+The m= field specifies the maximum number of messages
+to attempt to deliver on a single SMTP or LMTP connection.
+The default is infinite.
+.pp
+The r= field specifies the maximum number of recipients
+to attempt to deliver in a single envelope.
+It defaults to 100.
.pp
The /= field specifies a new root directory for the mailer. The path is
macro expanded and then passed to the
@@ -5245,6 +5745,11 @@ The Wait= field specifies the maximum time to wait for the
mailer to return after sending all data to it.
This applies to mailers that have been forked by
.i sendmail .
+.pp
+The Queuegroup= field specifies the default queue group in which
+received mail should be queued.
+This can be overridden by other means as explained in section
+``Queue Groups and Queue Directories''.
.sh 2 "H \*- Define Header"
.pp
The format of the header lines that
@@ -5272,8 +5777,8 @@ The syntax of this line is one of the following:
.)b
.(b F
.b H [\c
-.b ? \c
-.i ${macro} \c
+.b ?$ \c
+.i {macro} \c
.b ? \c
.b ]\c
.i hname \c
@@ -5305,6 +5810,12 @@ storage map in a ruleset.
If one of these headers is in the input
it is reflected to the output
regardless of these flags or macros.
+Notice:
+If a
+.i ${macro}
+is used to set a header, then it is useful to add that macro to class
+.i $={persistentMacros}
+which consists of the macros that should be saved across queue runs.
.pp
Some headers have special semantics
that will be described later.
@@ -5378,13 +5889,10 @@ or
.)b
.sh 2 "O \*- Set Option"
.pp
-There are a number of
-global
-options that
+There are a number of global options that
can be set from a configuration file.
Options are represented by full words;
-some are also representable as single characters
-for back compatibility.
+some are also representable as single characters for back compatibility.
The syntax of this line is:
.(b F
.b O \0
@@ -5421,6 +5929,11 @@ the default is TRUE),
or
a time interval.
.pp
+All filenames used in options should be absolute paths,
+i.e., starting with '/'.
+Relative filenames most likely cause surprises during operation
+(unless otherwise noted).
+.pp
The options supported (with the old, one character names in brackets) are:
.nr ii 1i
.ip "AliasFile=\fIspec, spec, ...\fP"
@@ -5437,6 +5950,29 @@ where
.i class \c
.b :
is optional and defaults to ``implicit''.
+Note that
+.i info
+is required for all
+.i class es
+except
+.q ldap .
+For the
+.q ldap
+class,
+if
+.i info
+is not specified,
+a default
+.i info
+value is used as follows:
+.(b
+\-k (&(objectClass=sendmailMTAAliasObject)
+ (sendmailMTAAliasName=aliases)
+ (|(sendmailMTACluster=${sendmailMTACluster})
+ (sendmailMTAHost=$j))
+ (sendmailMTAKey=%0))
+\-v sendmailMTAAliasValue
+.)b
Depending on how
.i sendmail
is compiled, valid classes are
@@ -5487,47 +6023,72 @@ entry to exist in the alias database
before starting up.
If it does not appear in the
.i timeout
-interval
-rebuild the database
-(if the
-.b AutoRebuildAliases
-option is also set)
-or issue a warning.
+interval issue a warning.
.ip AllowBogusHELO
[no short name]
If set, allow HELO SMTP commands that don't include a host name.
Setting this violates RFC 1123 section 5.2.5,
but is necessary to interoperate with several SMTP clients.
If there is a value, it is still checked for legitimacy.
+.ip AuthMaxBits=\fIN\fP
+[no short name]
+Limit the maximum encryption strength for the security layer in
+SMTP AUTH (SASL). Default is essentially unlimited.
+This allows to turn off additional encryption in SASL if
+STARTTLS is already encrypting the communication, because the
+existing encryption strength is taken into account when choosing
+an algorithm for the security layer.
+For example, if STARTTLS is used and the symmetric cipher is 3DES,
+then the the keylength (in bits) is 168.
+Hence setting
+.b AuthMaxBits
+to 168 will disable any encryption in SASL.
.ip AuthMechanisms
[no short name]
List of authentication mechanisms for AUTH (separated by spaces).
The advertised list of authentication mechanisms will be the
intersection of this list and the list of available mechanisms as
determined by the Cyrus SASL library.
+If STARTTLS is active, EXTERNAL will be added to this list.
+In that case, the value of {cert_subject} is used as authentication id.
.ip AuthOptions
[no short name]
-When to use the AUTH= parameter for the MAIL FROM command;
+List of options for SMTP AUTH consisting of single characters
+with intervening white space or commas.
.(b
-.ta 1i
-A Only when authentication succeeded.
-.)b
-The default is to try whenever SMTP AUTH is available.
-.ip AutoRebuildAliases
-[D]
-If set,
-rebuild the alias database if necessary and possible.
-The rebuild will happen the next time an alias is looked up.
-If this option is not set,
-.i sendmail
-will never rebuild the alias database
-unless explicitly requested
-using
-.b \-bi .
-.b NOTE :
-There is a potential for a denial of service attack if this is set.
-This option is deprecated and
-will be removed from a future version.
+.ta 4n
+A Use the AUTH= parameter for the MAIL FROM
+ command only when authentication succeeded.
+ This can be used as a workaround for broken
+ MTAs that do not implement RFC2554 correctly.
+a protection from active (non-dictionary) attacks
+ during authentication exchange.
+c require mechanisms which pass client credentials,
+ and allow mechanisms which can pass credentials
+ to do so.
+d don't permit mechanisms susceptible to passive
+ dictionary attack.
+f require forward secrecy between sessions
+ (breaking one won't help break next).
+p don't permit mechanisms susceptible to simple
+ passive attack (e.g., PLAIN, LOGIN).
+y don't permit mechanisms that allow anonymous login.
+.)b
+The first option applies to sendmail as a client, the others to a server.
+Example:
+.(b
+O AuthOptions=p,y
+.)b
+would disallow ANONYMOUS as AUTH mechanism and would
+allow PLAIN only if a security layer (e.g.,
+provided by STARTTLS) is already active.
+The options 'a', 'c', 'd', 'f', 'p', and 'y' refer to properties of the
+selected SASL mechanisms.
+Explanations of these properties can be found in the Cyrus SASL documentation.
+.ip BadRcptThrottle=\fIN\fP
+[no short name]
+If set and more than the specified number of recipients in a single SMTP
+envelope are rejected, sleep for one second after each rejected RCPT command.
.ip BlankSub=\fIc\fP
[B]
Set the blank substitution character to
@@ -5541,7 +6102,8 @@ This directory directory must contain the hashes of each CA certificate
as filenames (or as links to them).
.ip CACERTFile
[no short name]
-File containing one CA certificate.
+File containing one or more CA certificates;
+see section about STARTTLS for more information.
.ip CheckAliases
[n]
Validate the RHS of aliases when rebuilding the alias database.
@@ -5570,7 +6132,15 @@ Defaults to 1800.
.ip ClientCertFile
[no short name]
File containing the certificate of the client, i.e., this certificate
-is used when sendmail acts as client.
+is used when
+.i sendmail
+acts as client (for STARTTLS).
+.ip ClientKeyFile
+[no short name]
+File containing the private key belonging to the client certificate
+(for STARTTLS if
+.i sendmail
+runs as client).
.ip ClientPortOptions=\fIoptions\fP
[O]
Set client SMTP options.
@@ -5596,13 +6166,21 @@ can be the following character:
.(b
.ta 1i
h use name of interface for HELO command
+A don't use AUTH when sending e-mail
+S don't use STARTTLS when sending e-mail
.)b
If ``h'' is set, the name corresponding to the outgoing interface
address (whether chosen via the Connection parameter or
the default) is used for the HELO/EHLO command.
-.ip ClientKeyFile
-[no short name]
-File containing the private key belonging to the client certificate.
+However, the name must not start with a square bracket
+and it must contain at least one dot.
+This is a simple test whether the name is not
+an IP address (in square brackets) but a qualified hostname.
+Note that multiple ClientPortOptions settings are allowed
+in order to give settings for each protocol family
+(e.g., one for Family=inet and one for Family=inet6).
+A restriction placed on one family only affects
+outgoing connections on that particular family.
.ip ColonOkInAddr
[no short name]
If set, colons are acceptable in e-mail addresses
@@ -5661,7 +6239,7 @@ override the connection address (for testing purposes).
If set to a positive value,
allow no more than
.i N
-incoming daemon connections in a one second period.
+incoming connections in a one second period per daemon.
This is intended to flatten out peaks
and allow the load average checking to cut in.
Defaults to zero (no limits).
@@ -5687,7 +6265,9 @@ If not set, no control socket will be available.
Solaris and pre-4.4BSD kernel users should see the note in sendmail/README .
.ip DHParameters
File with DH parameters for STARTTLS.
-This is only required if DSA/DH is used.
+This is only required if a ciphersuite containing DSA/DH is used.
+This is only for people with a good knowledge of TLS, all others
+can ignore this option.
.ip DaemonPortOptions=\fIoptions\fP
[O]
Set server SMTP options.
@@ -5729,8 +6309,11 @@ b bind to interface through which mail has been received
c perform hostname canonification (.cf)
f require fully qualified hostname (.cf)
u allow unqualified addresses (.cf)
+A disable AUTH (overrides 'a' modifier)
C don't perform hostname canonification
E disallow ETRN (see RFC 2476)
+O optional; if opening the socket fails ignore it
+S don't offer STARTTLS
.)b
That is, one way to specify a message submission agent (MSA) that
always requires authentication is:
@@ -5756,7 +6339,8 @@ See the relevant documentation for
The modifier ``f'' disallows addresses of the form
.b user@host
unless they are submitted directly.
-The flag ``u'' allows unqualified sender addresses.
+The flag ``u'' allows unqualified sender addresses,
+i.e., those without @host.
``b'' forces sendmail to bind to the interface
through which the e-mail has been
received for the outgoing connection.
@@ -5773,16 +6357,29 @@ Note,
will listen on a new socket
for each occurence of the DaemonPortOptions option
in a configuration file.
+The modifier ``O'' causes sendmail to ignore a socket
+if it can't be opened.
+This applies to failures from the socket(2) and bind(2) calls.
.ip DefaultAuthInfo
[no short name]
Filename that contains default authentication information for outgoing
connections. This file must contain the user id, the authorization id,
-the password (plain text), and the realm to use
+the password (plain text), the realm and the list of mechanisms to use
on separate lines and must be readable by
root (or the trusted user) only.
If no realm is specified,
.b $j
is used.
+If no mechanisms are specified, the list given by
+.b AuthMechanisms
+is used.
+Notice: this option is deprecated and will be removed in future versions.
+Moreover, it doesn't work for the MSP since it can't read the file
+(the file must not be group/world-readable otherwise
+.i sendmail
+will complain).
+Use the authinfo ruleset instead which provides more control over
+the usage of the data anyway.
.ip DefaultCharSet=\fIcharset\fP
[no short name]
When a message that has 8-bit characters but is not in MIME format
@@ -5811,7 +6408,7 @@ formerly hardcoded to /usr/tmp/dead.letter.
If this option is not set (the default),
sendmail will not attempt to save to a system-wide dead.letter file
in the event
-it can not bounce the mail to the user or postmaster.
+it cannot bounce the mail to the user or postmaster.
Instead, it will rename the qf file
as it has in the past
when the dead.letter file could not be opened.
@@ -5845,6 +6442,19 @@ option has been combined into the
.b DefaultUser
option.
.)f
+.ip DelayLA=\fILA\fP
+[no short name]
+When the system load average exceeds
+.i LA ,
+.i sendmail
+will sleep for one second on most SMTP commands and
+before accepting connections.
+.ip DeliverByMin=\fItime\fP
+[0]
+Set minimum time for Deliver By SMTP Service Extension (RFC 2852).
+If 0, no time is listed, if less than 0, the extension is not offered,
+if greater than 0, it is listed as minimum time
+for the EHLO keyword DELIVERBY.
.ip DeliveryMode=\fIx\fP
[d]
Deliver in mode
@@ -5879,6 +6489,17 @@ Units default to seconds, so
uses a five second delay.
Defaults to zero
(no retry).
+This delay only applies to mailers which have the
+Z flag set.
+.ip DirectSubmissionModifiers=\fImodifiers\fP
+Defines
+.b ${daemon_flags}
+for direct (command line) submissions.
+If not set,
+.b ${daemon_flags}
+is either "CC f" if the option
+.b \-G
+is used or "c u" otherwise.
.ip DontBlameSendmail=\fIoption,option,...\fP
[no short name]
In order to avoid possible cracking attempts
@@ -5892,46 +6513,7 @@ a group-writable
directory,
then you will have to turn off this checking
(at the cost of making your system more vulnerable to attack).
-The arguments are individual options that turn off checking:
-.(b
-Safe
-AssumeSafeChown
-ClassFileInUnsafeDirPath
-DontWarnForwardFileInUnsafeDirPath
-ErrorHeaderInUnsafeDirPath
-FileDeliveryToHardLink
-FileDeliveryToSymLink
-ForwardFileInUnsafeDirPath
-ForwardFileInUnsafeDirPathSafe
-ForwardFileIngroupWritableDirPath
-GroupWritableAliasFile
-GroupWritableDirPathSafe
-GroupWritableForwardFileSafe
-GroupWritableIncludeFileSafe
-HelpFileinUnsafeDirPath
-IncludeFileInUnsafeDirPath
-IncludeFileInUnsafeDirPathSafe
-IncludeFileIngroupWritableDirPath
-InsufficientEntropy
-LinkedAliasFileInWritableDir
-LinkedClassFileInWritableDir
-LinkedForwardFileInWritableDir
-LinkedIncludeFileInWritableDir
-LinkedMapInWritableDir
-LinkedServiceSwitchFileInWritableDir
-MapInUnsafeDirPath
-NonRootSafeAddr
-RunProgramInUnsafeDirPath
-RunWritableProgram
-TrustStickyBit
-WorldWritableAliasFile
-WriteMapToHardLink
-WriteMapToSymLink
-WriteStatsToHardLink
-WriteStatsToSymLink
-.)b
-.b Safe
-is the default.
+The possible arguments have been described earlier.
The details of these flags are described above.
.\"XXX should have more here!!! XXX
.b "Use of this option is not recommended."
@@ -5981,6 +6563,9 @@ However, you will need to be certain to include all variant names
in the
.b $=w
class by some other mechanism.
+If set to
+.b loopback ,
+loopback interfaces (e.g., lo0) will not be probed.
.ip DontPruneRoutes
[R]
Normally,
@@ -6018,6 +6603,7 @@ The address is macro expanded
at the time of delivery.
If not set, defaults to
.q postmaster .
+If set to an empty string, double bounces are dropped.
.ip EightBitMode=\fIaction\fP
[8]
Set handling of eight-bit data.
@@ -6092,17 +6678,34 @@ If specified, the
.i fallbackhost
acts like a very low priority MX
on every host.
+MX records will be looked up for this host,
+unless the name is surrounded by square brackets.
This is intended to be used by sites with poor network connectivity.
Messages which are undeliverable due to temporary address failures
(e.g., DNS failure)
-also go to the FallBackMX host.
+also go to the FallbackMXhost.
+.ip FastSplit
+[no short name]
+If set to a value greater than zero (the default is one),
+it suppresses the MX lookups on addresses
+when they are initially sorted, i.e., for the first delivery attempt.
+This usually results in faster envelope splitting unless the MX records
+are readily available in a local DNS cache.
+To enforce initial sorting based on MX records set
+.b FastSplit
+to zero.
+If the mail is submitted directly from the command line, then
+the value also limits the number of processes to deliver the envelopes;
+if more envelopes are created they are only queued up
+and must be taken care of by a queue run.
+Since the default submission method is via SMTP (either from a MUA
+or via the MSP), the value of
+.b FastSplit
+is seldom used to limit the number of processes to deliver the envelopes.
.ip ForkEachJob
[Y]
If set,
deliver each job that is run from the queue in a separate process.
-Use this option if you are short of memory,
-since the default tends to consume considerable amounts of memory
-while the queue is being processed.
.ip ForwardPath=\fIpath\fP
[J]
Set the path for searching for users' .forward files.
@@ -6174,6 +6777,11 @@ A suggested value for sites desiring persistent host status is
Ignore dots in incoming messages.
This is always disabled (that is, dots are always accepted)
when reading SMTP mail.
+.ip InputMailFilters=\fIname,name,...\fP
+A comma separated list of filters which determines which filters
+(see the "X \*- Mail Filter (Milter) Definitions" section)
+and the invocation sequence are contacted for incoming SMTP messages.
+If none are set, no filters will be contacted.
.ip LDAPDefaultSpec=\fIspec\fP
[no short name]
Sets a default map specification for LDAP maps.
@@ -6198,6 +6806,21 @@ This is intended only for use from the command line.
The
.b \-M
flag is preferred.
+.ip MailboxDatabase
+[no short name]
+Type of lookup to find information about local mailboxes,
+defaults to ``pw'' which uses
+.i getpwnam .
+Other types can be introduced by adding them to the source code,
+see libsm/mbdb.c for details.
+.ip UseMSP
+[no short name]
+Use as mail submission program, i.e.,
+allow group writable queue files
+if the group is the same as that of a set-group-ID sendmail binary.
+See the file
+.b sendmail/SECURITY
+in the distribution tarball.
.ip MatchGECOS
[G]
Allow fuzzy matching on the GECOS field.
@@ -6243,10 +6866,12 @@ to be advertised in the ESMTP EHLO response.
Messages larger than this will be rejected.
.ip MaxMimeHeaderLength=\fIN[/M]\fP
[no short name]
-Sets the maximum length of certain MIME header field values
-to
+Sets the maximum length of certain MIME header field values to
.i N
characters.
+These MIME header fields are determined by being a member of
+class {checkMIMETextHeaders}, which currently contains only
+the header Content-Description.
For some of these headers which take parameters,
the maximum length of each parameter is set to
.i M
@@ -6257,6 +6882,21 @@ is not specified, one half of
will be used.
By default,
these values are 0, meaning no checks are done.
+.ip MaxQueueChildren=\fIN\fP
+[no short name]
+When set, this limits the number of concurrent queue runner processes to
+.i N.
+This helps to control the amount of system resources used when processing
+the queue. When there are multiple queue groups defined and the total number
+of queue runners for these queue groups would exceed
+.i MaxQueueChildren
+then the queue groups will not all run concurrently. That is, some portion
+of the queue groups will run concurrently such that
+.i MaxQueueChildren
+will not be exceeded, while the remaining queue groups will be run later (in
+round robin order). See also
+.i MaxRunnersPerQueue
+and the section \fBQueue Group Declaration\fP.
.ip MaxQueueRunSize=\fIN\fP
[no short name]
The maximum number of jobs that will be processed
@@ -6279,12 +6919,52 @@ in an SMTP transaction.
Note: setting this too low can interfere with sending mail from
MUAs that use SMTP for initial submission.
If not set, there is no limit on the number of recipients per envelope.
+.ip MaxRunnersPerQueue=\fIN\fP
+[no short name]
+This sets the default maximum number of queue runners for queue groups.
+Up to
+.i N
+queue runners will work in parallel on a queue group's messages.
+This is useful where the processing of a message in the queue might
+delay the processing of subsequent messages. Such a delay may be the result
+of non-erroneous situations such as a low bandwidth connection.
+May be overridden on a per queue group basis by setting the
+.i Runners
+option; see the section \fBQueue Group Declaration\fP.
+The default is 1 when not set.
.ip MeToo
[m]
Send to me too,
even if I am in an alias expansion.
This option is deprecated
and will be removed from a future version.
+.ip Milter
+[no short name]
+This option has several sub(sub)options.
+The names of the suboptions are separated by dots.
+At the first level the following options are available:
+.(b
+.ta \w'LogLevel'u+3n
+LogLevel Log level for input mail filter actions, defaults to LogLevel.
+macros Specifies list of macro to transmit to filters.
+ See list below.
+.)b
+The ``macros'' option has the following suboptions
+which specify the list of macro to transmit to milters
+after a certain event occurred.
+.(b
+.ta \w'envfrom'u+3n
+connect After session connection start
+helo After HELO command
+envfrom After MAIL FROM command
+envrcpt After RCPT TO command
+.)b
+By default the lists of macros are empty.
+Example:
+.(b
+O Milter.LogLevel=12
+O Milter.macros.connect=j, _, {daemon_name}
+.)b
.ip MinFreeBlocks=\fIN\fP
[b]
Insist on at least
@@ -6310,6 +6990,9 @@ Sets the list of characters that must be quoted if used in a full name
that is in the phrase part of a ``phrase <address>'' syntax.
The default is ``\'.''.
The characters ``@,;:\e()[]'' are always added to this list.
+.ip NiceQueueRun
+[no short name]
+The priority of queue runners (nice(3)).
.ip NoRecipientAction
[no short name]
The action to take when you receive a message that has no valid
@@ -6411,6 +7094,7 @@ noetrn Disallow ETRN entirely
noverb Disallow VERB entirely
restrictmailq Restrict mailq command
restrictqrun Restrict \-q command line flag
+restrictexpand Restrict \-bv and \-v command line flags
noreceipts Don't return success DSNs\**
nobodyreturn Don't return the body of a message with DSNs
goaway Disallow essentially all SMTP status queries
@@ -6430,6 +7114,7 @@ pseudo-flag sets all flags except
.q noreceipts ,
.q restrictmailq ,
.q restrictqrun ,
+.q restrictexpand ,
.q noetrn ,
and
.q nobodyreturn .
@@ -6439,6 +7124,22 @@ can print the queue.
If queue runs are restricted,
only root and the owner of the queue directory
can run the queue.
+The
+.q restrictexpand
+pseudo-flag instructs
+.i sendmail
+to drop privileges when the
+.b \-bv
+option is given by users who are neither root nor the TrustedUser
+so users cannot read private aliases, forwards, or :include: files.
+It will add the
+.q NonRootSafeAddr
+to the
+.q DontBlameSendmail
+option to prevent misleading unsafe address warnings.
+It also overrides the
+.b \-v
+(verbose) command line option to prevent information leakage.
Authentication Warnings add warnings about various conditions
that may indicate attempts to spoof the mail system,
such as using a non-standard queue directory.
@@ -6451,18 +7152,27 @@ The
will be macro processed.
.ip QueueDirectory=\fIdir\fP
[Q]
-Use the named
-.i dir
-as the queue directory.
-To use multiple queues, supply a value ending with an asterisk.
-For example,
-.i /var/spool/mqueue/q*
-will use all of the directories or symbolic links to directories
-beginning with
-.i q
-in
+The QueueDirectory option serves two purposes.
+First, it specifies the directory or set of directories that comprise
+the default queue group.
+Second, it specifies the directory D which is the ancestor of all queue
+directories, and which sendmail uses as its current working directory.
+When sendmail dumps core, it leaves its core files in D.
+There are two cases.
+If \fIdir\fR ends with an asterisk (eg, \fI/var/spool/mqueue/qd*\fR),
+then all of the directories or symbolic links to directories
+beginning with `qd' in
.i /var/spool/mqueue
-as queue directories.
+will be used as queue directories of the default queue group,
+and
+.i /var/spool/mqueue
+will be used as the working directory D.
+Otherwise,
+\fIdir\fR must name a directory (usually \fI/var/spool/mqueue\fR):
+the default queue group consists of the single queue directory \fIdir\fR,
+and the working directory D is set to \fIdir\fR.
+To define additional groups of queue directories,
+use the configuration file `Q' command.
Do not change the queue directory structure
while sendmail is running.
.ip QueueFactor=\fIfactor\fP
@@ -6496,6 +7206,11 @@ just queue messages
Defaults to 8 multiplied by
the number of processors online on the system
(if that can be determined).
+.ip QueueFileMode=\fImode\fP
+[no short name]
+Default permissions for queue files (octal).
+If not set, sendmail uses 0600 unless its real
+and effective uid are different in which case it uses 0644.
.ip QueueSortOrder=\fIalgorithm\fP
[no short name]
Sets the
@@ -6508,7 +7223,11 @@ Legal values are
.q filename
(to order by the name of the queue file name),
.q time
-(to order by the submission time),
+(to order by the submission/creation time),
+.q random
+(to order randomly),
+.q modification
+(to order by the modification time of the qf file (older entries first)),
and
.q priority
(to order by message priority).
@@ -6517,13 +7236,16 @@ but may tend to process low priority messages
that go to a single host
over high priority messages that go to several hosts;
it probably shouldn't be used on slow network links.
-Filename ordering saves the overhead of
+Filename and modification time ordering saves the overhead of
reading all of the queued items
before starting the queue run.
-Time ordering is almost always a bad idea,
+Creation (submission) time ordering is almost always a bad idea,
since it allows large, bulk mail to go out
before smaller, personal mail,
but may have applicability on some hosts with very fast connections.
+Random is useful if several queue runners are started by hand
+which try to drain the same queue since odds are they will be working
+on different parts of the queue at the same time.
Priority ordering is the default.
.ip QueueTimeout=\fItimeout\fP
[T]
@@ -6559,6 +7281,7 @@ can be
.q recurse ,
.q defnames ,
.q stayopen ,
+.q use_inet6 ,
or
.q dnsrch .
The string
@@ -6569,16 +7292,17 @@ or
.b \- )
can be specified to turn off matching against MX records
when doing name canonifications.
-.b N.B.
-Prior to 8.7,
-this option indicated that the name server be responding
-in order to accept addresses.
-This has been replaced by checking to see
-if the
-.q dns
-method is listed in the service switch entry for the
-.q hosts
-service.
+The string
+.q WorkAroundBrokenAAAA
+(without a
+.b +
+or
+.b \- )
+can be specified to work around some broken nameservers
+which return SERVFAIL (a temporary failure) on T_AAAA (IPv6) lookups.
+Notice: it might be necessary to apply the same (or similar) options to
+.i submit.cf
+too.
.ip RrtImpliesDsn
[R]
If this option is set, a
@@ -6693,6 +7417,20 @@ UNIX-style
lines at the front of headers.
Normally they are assumed redundant
and discarded.
+.ip SharedMemoryKey
+[no short name]
+Key to use for shared memory segment;
+if not set (or 0), shared memory will not be used.
+Requires support for shared memory to be compiled into
+.i sendmail .
+If this option is set,
+.i sendmail
+can share some data between different instances.
+For example, the number of entries in a queue directory
+or the available space in a file system.
+This allows for more efficient program execution, since only
+one process needs to update the data instead of each individual
+process gathering the data each time it is required.
.ip SendMimeErrors
[j]
If set, send error messages in MIME format
@@ -6705,10 +7443,12 @@ RFC1891.
.ip ServerCertFile
[no short name]
File containing the certificate of the server, i.e., this certificate
-is used when sendmail acts as server.
+is used when sendmail acts as server
+(used for STARTTLS).
.ip ServerKeyFile
[no short name]
-File containing the private key belonging to the server certificate.
+File containing the private key belonging to the server certificate
+(used for STARTTLS).
.ip ServiceSwitchFile=\fIfilename\fP
[no short name]
If your host operating system has a service switch abstraction
@@ -6799,9 +7539,11 @@ It can be printed using the
program.
.ip SuperSafe
[s]
-Be super-safe when running things,
-i.e.,
-always instantiate the queue file,
+This option can be set to True, False, or Interactive.
+If set to True,
+.i sendmail
+will be super-safe when running things,
+i.e., always instantiate the queue file,
even if you are going to attempt immediate delivery.
.i Sendmail
always instantiates the queue file
@@ -6809,10 +7551,23 @@ before returning control to the client
under any circumstances.
This should really
.i always
-be set.
+be set to True.
+The Interactive value has been introduced in 8.12 and can
+be used together with
+.b DeliveryMode=i .
+It skips some synchronization calls which are effectively
+doubled in the code execution path for this mode.
+.ip TLSSrvOptions
+[no short name]
+List of options for SMTP STARTTLS for the server
+consisting of single characters
+with intervening white space or commas.
+The flag ``V'' disables client verification, and hence
+it is not possible to use a client certificate for relaying.
+Currently there are no other flags available.
.ip TempFileMode=\fImode\fP
[F]
-The file mode for queue files, files to which
+The file mode for transcript files, files to which
.i sendmail
delivers directly, and files in the
.b HostStatusDirectory .
@@ -6890,6 +7645,9 @@ that is,
they cannot reference programs or write directly to files.
World writable :include: and .forward files
are always unsafe.
+Note: use
+.b DontBlameSendmail
+instead; this option is deprecated.
.ip UseErrorsTo
[l]
If there is an
@@ -6939,7 +7697,7 @@ All options can be specified on the command line using the
\-O or \-o flag,
but most will cause
.i sendmail
-to relinquish its setuid permissions.
+to relinquish its set-user-ID permissions.
The options that will not cause this are
SevenBitInput [7],
EightBitMode [8],
@@ -7038,7 +7796,7 @@ to do with the version
on the files.
For example,
as of this writing
-version 8 config files
+version 10 config files
(specifically, 8.10)
used version level 9 configurations.
.pp
@@ -7143,6 +7901,9 @@ Version level nine configuration files allow
parentheses in rulesets, i.e. they are not treated
as comments and hence removed.
.pp
+Version level ten configuration files allow
+queue group definitions.
+.pp
The
.b V
line may have an optional
@@ -7241,7 +8002,7 @@ Note that
.i default
clauses never do this mapping.
.pp
-The built in map with both name and class
+The built-in map with both name and class
.q host
is the host name canonicalization lookup.
Thus,
@@ -7381,6 +8142,13 @@ If the
.b \-z
flag is given, then all MX names are returned,
separated by the given delimiter.
+.ip dns
+This map requires the option -R to specify the DNS resource record
+type to lookup. The following types are supported:
+A, AAAA, AFSDB, CNAME, MX, NS, PTR, SRV, and TXT.
+A map lookup will return only one record.
+Hence for some types, e.g., MX records, the return value might be a random
+element of the list due to randomizing in the DNS resolver.
.ip sequence
The arguments on the `K' line are a list of maps;
the resulting map searches the argument maps in order
@@ -7470,15 +8238,14 @@ or the string specified with the the
.b \-d
flag. The flags available for the map are
.(b
+.ta 4n
-n not
-f case sensitive
--b basic regular expressions
- (default is extended)
+-b basic regular expressions (default is extended)
-s substring match
-d set the delimiter used for -s
-a append string to key
--m match only, do not
- replace/discard value
+-m match only, do not replace/discard value
-D perform no lookup in deferred delivery mode.
.)b
The
@@ -7530,7 +8297,8 @@ R$\- $: $(storage {MyMacro} $) $1
.)b
.ip arith
Perform simple arithmetic operations.
-The operation is given as key, currently +, -, *, /,
+The operation is given as key, currently +, -, *, /, %,
+|, & (bitwise OR, AND),
l (for less than), and = are supported.
The two operands are given as arguments.
The lookup returns the result of the computation,
@@ -7714,6 +8482,12 @@ in the presence of the
.b \-A
flag.
.pp
+Some additional flags are available for the host and dns maps:
+.ip "\-d"
+delay: specify the resolver's retransmission time interval (in seconds).
+.ip "\-r"
+retry: specify the number of times to retransmit a resolver query.
+.pp
The following additional flags are present in the ldap map only:
.ip "\-R"
Do not auto chase referrals. sendmail must be compiled with
@@ -7721,6 +8495,10 @@ Do not auto chase referrals. sendmail must be compiled with
to use this flag.
.ip "\-n"
Retrieve attribute names only.
+.ip "\-V\fIsep\fP"
+Retrieve both attributes name and value(s),
+separated by
+.i sep .
.ip "\-r\fIderef\fP"
Set the alias dereference option to one of never, always, search, or find.
.ip "\-s\fIscope\fP"
@@ -7811,8 +8589,245 @@ New classes can be added in the routine
.b setupmaps
in file
.b conf.c .
+.sh 2 "Q \*- Queue Group Declaration"
+.pp
+In addition to the option
+.i QueueDirectory,
+queue groups can be declared that define a (group of) queue directories
+under a common name.
+The syntax is as follows:
+.(b F
+.b Q \c
+.i name
+{, \c
+.i field =\c
+.i value \|}+
+.)b
+where
+.i name
+is the symbolic name of the queue group under which
+it can be referenced in various places
+and the
+.q field=name
+pairs define attributes of the queue group.
+Fields are:
+.ip Flags
+Flags for this queue group.
+.ip Nice
+The nice(2) increment for the queue group.
+.ip Interval
+The time between two queue runs.
+.ip Path
+The queue directory of the group (required).
+.ip Runners
+The number of parallel runners processing the queue.
+.ip Jobs
+The maximum number of jobs (messages delivered) per queue run.
+.ip recipients
+The maximum number of recipients per envelope.
+Envelopes with more than this number of recipients will be split
+into multiple envelopes in the same queue directory.
+The default value 0 means no limit.
+.lp
+Only the first character of the field name is checked.
+.pp
+By default, a queue group named
+.i mqueue
+is defined that uses the value of the
+.i QueueDirectory
+option as path.
+Notice: all paths that are used for queue groups must
+be subdirectories of
+.i QueueDirectory .
+Since they can be symbolic links, this isn't a real restriction,
+If
+.i QueueDirectory
+uses a wildcard, then the directory one level up is considered
+the ``base'' directory which all other queue directories must share.
+Please make sure that the queue directories do not overlap,
+e.g., do not specify
+.(b
+O QueueDirectory=/var/spool/mqueue/*
+Qone, P=/var/spool/mqueue/dir1
+Qtwo, P=/var/spool/mqueue/dir2
+.)b
+because this also includes
+.q dir1
+and
+.q dir2
+in the default queue group.
+However,
+.(b
+O QueueDirectory=/var/spool/mqueue/main*
+Qone, P=/var/spool/mqueue/dir
+Qtwo, P=/var/spool/mqueue/other*
+.)b
+is a valid queue group specification.
+.pp
+Options listed in the ``Flags'' field can be used to modify
+the behavior of a queue group.
+The ``f'' flag must be set if multiple queue runners are
+supposed to work on the entries in a queue group.
+Otherwise
+.i sendmail
+will work on the entries strictly sequentially.
+.pp
+The ``Interval'' field sets the time between queue runs.
+If no queue group specific interval is set, then the parameter of the
+.b -q
+option from the command line is used.
+.pp
+To control the overall number of concurrently active queue runners
+the option
+.b MaxQueueChildren
+can be set.
+This limits the number of processes used for running the queues to
+.b MaxQueueChildren ,
+though at any one time fewer processes may be active
+as a result of queue options, completed queue runs, system load, etc.
+.pp
+The maximum number of queue runners for an individual queue group can be
+controlled via the
+.b Runners
+option.
+If set to 0, entries in the queue will not be processed, which
+is useful to ``quarantine'' queue files.
+The number of runners per queue group may also be set with the option
+.b MaxRunnersPerQueue ,
+which applies to queue groups that have no individual limit.
+That is, the default value for
+.b Runners
+is
+.b MaxRunnersPerQueue
+if set, otherwise 1.
+.pp
+The field Jobs describes the maximum number of jobs
+(messages delivered) per queue run, which is the queue group specific
+value of
+.b MaxQueueRunSize .
+.pp
+Notice: queue groups should be declared after all queue related options
+have been set because queue groups take their defaults from those options.
+If an option is set after a queue group declaration, the values of
+options in the queue group are set to the defaults of
+.i sendmail
+unless explicitly set in the declaration.
+.pp
+Each envelope is assigned to a queue group based on the algorithm
+described in section
+``Queue Groups and Queue Directories''.
+.sh 2 "X \*- Mail Filter (Milter) Definitions"
+.pp
+The
+.i sendmail
+Mail Filter API (Milter) is designed to allow third-party programs access
+to mail messages as they are being processed in order to filter
+meta-information and content.
+They are declared in the configuration file as:
+.(b F
+.b X \c
+.i name
+{, \c
+.i field =\c
+.i value \|}*
+.)b
+where
+.i name
+is the name of the filter
+(used internally only)
+and the
+.q field=name
+pairs define attributes of the filter.
+Also see the documentation for the
+.b InputMailFilters
+option for more information.
+.pp
+Fields are:
+.(b
+.ta 1i
+Socket The socket specification
+Flags Special flags for this filter
+Timeouts Timeouts for this filter
+.)b
+Only the first character of the field name is checked
+(it's case-sensitive).
+.pp
+The socket specification is one of the following forms:
+.(b F
+.b S= \c
+.b inet \c
+.b :
+.i port
+.b @
+.i host
+.)b
+.(b F
+.b S= \c
+.b inet6 \c
+.b :
+.i port
+.b @
+.i host
+.)b
+.(b F
+.b S= \c
+.b local \c
+.b :
+.i path
+.)b
+The first two describe an IPv4 or IPv6 socket listening on a certain
+.i port
+at a given
+.i host
+or IP address.
+The final form describes a named socket on the filesystem at the given
+.i path .
+.pp
+The following flags may be set in the filter description.
+.nr ii 4n
+.ip R
+Reject connection if filter unavailable.
+.ip T
+Temporary fail connection if filter unavailable.
+.pp
+The timeouts can be set using the four fields inside of the
+.b T=
+equate:
+.nr ii 4n
+.ip C
+Timeout for connecting to a filter.
+If set to 0, the system's
+.i connect()
+timeout will be used.
+.ip S
+Timeout for sending information from the MTA to a filter.
+.ip R
+Timeout for reading reply from the filter.
+.ip E
+Overall timeout between sending end-of-message to filter and waiting for
+the final acknowledgment.
+.pp
+Note the separator between each timeout field is a
+.b ';' .
+The default values (if not set) are:
+.b T=C:5m;S:10s;R:10s;E:5m
+where
+.b s
+is seconds and
+.b m
+is minutes.
+.pp
+Examples:
+.(b
+Xfilter1, S=local:/var/run/f1.sock, F=R
+Xfilter2, S=inet6:999@localhost, F=T, T=S:1s;R:1s;E:5m
+Xfilter3, S=inet:3333@localhost, T=C:2m
+.)b
.sh 2 "The User Database"
.pp
+The user database is deprecated in favor of ``virtusertable''
+and ``genericstable'' as explained in the file
+.b cf/README .
If you have a version of
.i sendmail
with the user database package
@@ -8028,6 +9043,10 @@ Compile in support for Hesiod.
Compile in support for IRIX NSD lookups.
.ip MAP_REGEX
Compile in support for regular expression matching.
+.ip DNSMAP
+Compile in support for DNS map lookups in the
+.i sendmail.cf
+file.
.ip PH_MAP
Compile in support for ph lookups.
.ip SASL
@@ -8038,15 +9057,18 @@ Compile in support for STARTTLS.
.ip EGD
Compile in support for the "Entropy Gathering Daemon"
to provide better random data for TLS.
-.ip SFIO
-Compile in support for sfio, which is required to enable encryption,
-e.g., STARTTLS.
.ip TCPWRAPPERS
Compile in support for TCP Wrappers.
.ip _PATH_SENDMAILCF
The pathname of the sendmail.cf file.
.ip _PATH_SENDMAILPID
The pathname of the sendmail.pid file.
+.ip SM_CONF_SHM
+Compile in support for shared memory, see section about
+"/var/spool/mqueue".
+.ip MILTER
+Compile in support for contacting external mail filters built with the
+Milter API.
.pp
There are also several compilation flags to indicate the environment
such as
@@ -8090,6 +9112,8 @@ since
.i sendmail
will break up a delivery into smaller batches as needed.
A higher number may reduce load on your system, however.
+.ip "MAXQUEUEGROUPS [50]"
+The maximum number of queue groups.
.ip "MAXATOM [1000]"
The maximum number of atoms
(tokens)
@@ -8123,9 +9147,6 @@ The maximum number of items in the user environment
that will be passed to subordinate mailers.
.ip "MAXMXHOSTS [100]"
The maximum number of MX records we will accept for any single host.
-.ip "MAXALIASDB [12]"
-The maximum number of alias databases that can be open at any time.
-Note that there may also be an open file limit.
.ip "MAXMAPSTACK [12]"
The maximum number of maps that may be "stacked" in a
.b sequence
@@ -8198,17 +9219,6 @@ you can set this flag to turn off special processing
of UNIX-style
.q "From "
lines.
-.ip QUEUE\(dg
-This flag should be set to compile in the queueing code.
-If this is not set,
-mailers must accept the mail immediately
-or it will be returned to the sender.
-.ip SMTP\(dg
-If set,
-the code to handle user and server SMTP will be compiled in.
-This is only necessary if your machine has some mailer
-that speaks SMTP
-(this means most machines everywhere).
.ip USERDB\(dg
Include the
.b experimental
@@ -8600,9 +9610,9 @@ is a pointer to the portion of the configuration file line
following the map class name;
flags and filenames can be extracted from this line.
The initialization function must return
-.sm TRUE
+.sm true
if it successfully opened the map,
-.sm FALSE
+.sm false
otherwise.
.pp
The lookup function is called as
@@ -8641,7 +9651,7 @@ shouldqueue(pri, ctime)
time_t ctime;
{
if (CurrentLA < QueueLA)
- return (FALSE);
+ return false;
return (pri > (QueueFactor / (CurrentLA \- QueueLA + 1)));
}
.)b
@@ -8656,7 +9666,7 @@ variable
.i QueueLA ),
.i shouldqueue
returns
-.sm FALSE
+.sm false
immediately
(that is, it should
.i not
@@ -8668,7 +9678,7 @@ variable
.i RefuseLA ),
.i shouldqueue
returns
-.sm TRUE
+.sm true
immediately.
Otherwise, it computes the function based on the message priority,
the queue factor
@@ -8699,7 +9709,7 @@ to ensure that messages are eventually processed.
The function
.i refuseconnections
returns
-.sm TRUE
+.sm true
if incoming SMTP connections should be refused.
The current implementation is based exclusively on the current load average
and the refuse load average option
@@ -8745,11 +9755,20 @@ if you wanted to generalize
.b $]
lookups.
We now recommend that you create a new keyed map instead.
-.sh 2 "Certificates for STARTTLS"
+.sh 2 "STARTTLS"
.pp
In this section we assume that
.i sendmail
has been compiled with support for STARTTLS.
+To properly understand the use of STARTTLS in
+.i sendmail ,
+it is necessary to understand at least some basics about X.509 certificates
+and public key cryptography.
+This information can be found in books about SSL/TLS
+or on WWW sites, e.g.,
+.q http://www.OpenSSL.org/ .
+.sh 3 "Certificates for STARTTLS"
+.pp
When acting as a server,
.i sendmail
requires X.509 certificates to support STARTTLS:
@@ -8764,6 +9783,14 @@ can contain several certificates of CAs.
The DNs of these certificates are sent
to the client during the TLS handshake (as part of the
CertificateRequest) as the list of acceptable CAs.
+However, do not list too many root CAs in that file, otherwise
+the TLS handshake may fail; e.g.,
+.(b
+error:14094417:SSL routines:SSL3_READ_BYTES:
+sslv3 alert illegal parameter:s3_pkt.c:964:SSL alert number 47
+.)b
+You should probably put only the CA cert into that file
+that signed your own cert(s), or at least only those you trust.
The CACERTPath directory must contain the hashes of each CA certificate
as filenames (or as links to them).
Symbolic links can be generated with the following
@@ -8785,7 +9812,7 @@ To allow for automatic startup of sendmail, private keys
must be stored unencrypted.
The keys are only protected by the permissions of the file system.
Never make a private key available to a third party.
-.sh 2 "PRNG for STARTTLS"
+.sh 3 "PRNG for STARTTLS"
.pp
STARTTLS requires a strong pseudo random number generator (PRNG)
to operate properly.
@@ -8917,6 +9944,26 @@ have freed me up to do other work.
.pp
Arguments must be presented with flags before addresses.
The flags are:
+.ip \-A\fIx\fP
+Select an alternative .cf file which is either
+.i sendmail.cf
+for
+.b \-Am
+or
+.i submit.cf
+for
+.b \-Ac .
+By default the .cf file is chosen based on the operation mode.
+For
+.b -bm
+(default),
+.b -bs ,
+and
+.b -t
+it is
+.i submit.cf
+if it exists, for all others it is
+.i sendmail.cf .
.ip \-b\fIx\fP
Set operation mode to
.i x .
@@ -8932,6 +9979,7 @@ t Run in test mode
v Just verify addresses, don't collect or deliver
i Initialize the alias database
p Print the mail queue
+P Print overview over the mail queue (requires shared memory)
h Print the persistent host status database
H Purge expired entries from the persistent host status database
.)b
@@ -9048,10 +10096,40 @@ Try to process the queued up mail.
If the time is given,
a
.i sendmail
-will run through the queue at the specified interval
-to deliver queued mail;
-otherwise, it only runs once.
-.ip \-q\fIXstring\fP
+will start one or more processes to run through the queue(s) at the specified
+time interval to deliver queued mail; otherwise, it only runs once.
+Each of these processes acts on a workgroup.
+These processes are also known as workgroup processes or WGP's for short.
+Each workgroup is responsible for controlling the processing of one or
+more queues; workgroups help manage the use of system resources by sendmail.
+Each workgroup may have one or more children concurrently processing
+queues depending on the setting of \fIMaxQueueChildren\fP.
+.ip \-qp\fItime\fP
+Similar to \-q with a time argument,
+except that instead of periodically starting WGP's
+sendmail starts persistent WGP's
+that alternate between processing queues and sleeping.
+The sleep time is specified by the time argument; it defaults to 1 second,
+except that a WGP always sleeps at least 5 seconds if their queues were
+empty in the previous run.
+Persistent processes are managed by a queue control process (QCP).
+The QCP is the parent process of the WGP's.
+Typically the QCP will be the sendmail daemon (when started with \-bd or \-bD)
+or a special process (named Queue control) (when started without \-bd or \-bD).
+If a persistent WGP ceases to be active for some reason
+another WGP will be started by the QCP for the same workgroup
+in most cases. When a persistent WGP has core dumped, the debug flag
+\fIno_persistent_restart\fP is set or the specific persistent WGP has been
+restarted too many times already then the WGP will not be started again
+and a message will be logged to this effect.
+To stop (SIGTERM) or restart (SIGHUP) persistent WGP's the appropriate
+signal should be sent to the QCP. The QCP will propagate the signal to all of
+the WGP's and if appropriate restart the persistent WGP's.
+.ip \-q\fIGname\fP
+Run the jobs in the queue group
+.i name
+once.
+.ip \-q[!]\fIXstring\fP
Run the queue once,
limiting the jobs to those matching
.i Xstring .
@@ -9068,6 +10146,7 @@ to limit based on sender.
A particular queued job is accepted if one of the corresponding addresses
contains the indicated
.i string .
+The optional ! character negates the condition tested.
Multiple
.i \-q\fIX\fP
flags are permitted,
@@ -9101,12 +10180,6 @@ The
line will be deleted before sending.
Any addresses in the argument vector will be deleted
from the send list.
-.ip "\-U"
-Indicate that this is an initial User Agent submission.
-This flag is deprecated.
-Future releases will ignore this flag and
-assume all submissions from the command line are
-initial submissions.
.ip "\-V envid"
The indicated
.i envid
@@ -9139,14 +10212,7 @@ running as daemon.
.+c "QUEUE FILE FORMATS"
.pp
This appendix describes the format of the queue files.
-These files live in the directory defined by the
-.b Q
-option in the
-.i sendmail.cf
-file, usually
-.i /var/spool/mqueue
-or
-.i /usr/spool/mqueue .
+These files live in a queue directory.
The individual qf, df, and xf files
may be stored in separate
.i qf/ ,
@@ -9156,28 +10222,15 @@ and
subdirectories
if they are present in the queue directory.
.pp
-To use multiple queues,
-supply a value ending with an asterisk.
-For example,
-.i /var/spool/mqueue/q*
-will use all of the directories or symbolic links to directories
-beginning with `q' in
-.i /var/spool/mqueue
-as queue directories.
-New messages will be randomly placed
-into one of the queues.
-Do not change the queue directory structure
-while sendmail is running.
-.pp
All queue files have the name
-\fIx\fP\|\fBf\fP\fIYMDhmsNPPPPP\fP
+.i ttYMDhmsNNppppp
where
-.i YMDhmsNPPPPP
+.i YMDhmsNNppppp
is the
.i id
for this message
and the
-.i x
+.i tt
is a type.
The individual letters in the
.i id
@@ -9195,37 +10248,58 @@ Encoded hour
Encoded minute
.ip s
Encoded second
-.ip N
-Envelope number
-.ip PPPPP
-At least five digits of the process ID
+.ip NN
+Encoded envelope number
+.ip ppppp
+At least five decimal digits of the process ID
.pp
All files with the same id collectively define one message.
-If memory-buffered files are available,
-some of these files may never appear
-on disk.
+Due to the use of memory-buffered files,
+some of these files may never appear on disk.
.pp
The types are:
.nr ii 0.5i
-.ip d
-The data file.
-The message body (excluding the header) is kept in this file.
-.ip q
+.ip qf
The queue control file.
This file contains the information necessary to process the job.
-.ip t
+.ip df
+The data file.
+The message body (excluding the header) is kept in this file.
+Sometimes the df file is not stored in the same directory as the qf file;
+in this case,
+the qf file contains a `d' record which names the queue directory
+that contains the df file.
+.ip tf
A temporary file.
-These are an image of the
+This is an image of the
.b qf
file when it is being rebuilt.
It should be renamed to a
.b qf
file very quickly.
-.ip x
+.ip xf
A transcript file,
existing during the life of a session
showing everything that happens
during that session.
+Sometimes the xf file must be generated before a queue group has been selected;
+in this case,
+the xf file will be stored in a directory of the default queue group.
+.ip Qf
+A ``lost'' queue control file.
+.i sendmail
+renames a
+.b qf
+file to
+.b Qf
+if there is a severe (configuration) problem that cannot be solved without
+human intervention.
+Search the logfile for the queue file id to figure out what happened.
+After you resolved the problem, you can rename the
+.b Qf
+file to
+.b qf
+and send it again.
.pp
The
.b qf
@@ -9239,7 +10313,7 @@ used to allow new
binaries to read queue files created by older versions.
Defaults to version zero.
Must be the first line of the file if present.
-For 8.10 the version number is 4.
+For 8.12 the version number is 6.
.ip A
The information given by the AUTH= parameter of the
.q "MAIL FROM:"
@@ -9267,13 +10341,16 @@ is the name of the alias that expanded to this address
The ``original recipient'',
specified by the ORCPT= field in an ESMTP transaction.
Used exclusively for Delivery Status Notifications.
-It applies only to the immediately following `R' line.
+It applies only to the following `R' line.
+.ip r
+The ``final recipient''
+used for Delivery Status Notifications.
+It applies only to the following `R' line.
.ip R
A recipient address.
This will normally be completely aliased,
but is actually realiased when the job is processed.
-There will be one line
-for each recipient.
+There will be one line for each recipient.
Version 1 qf files
also include a leading colon-terminated list of flags,
which can be
@@ -9319,6 +10396,10 @@ The total number of delivery attempts.
.ip K
The time (as seconds since January 1, 1970)
of the last delivery attempt.
+.ip d
+If the df file is in a different directory than the qf file,
+then a `d' record is present,
+specifying the directory in which the df file resides.
.ip I
The i-number of the data file;
this can be used to recover your mail queue
@@ -9475,7 +10556,7 @@ replace it with a blank sheet for double-sided output.
.\".sz 10
.\"Eric Allman
.\".sp
-.\"Version $Revision: 8.317.4.71 $
+.\"Version $Revision: 8.592 $
.\".ce 0
.bp 3
.ce
diff --git a/contrib/sendmail/editmap/Makefile b/contrib/sendmail/editmap/Makefile
new file mode 100644
index 0000000..965e029
--- /dev/null
+++ b/contrib/sendmail/editmap/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.1 2000/08/31 16:19:25 ca Exp $
+
+SHELL= /bin/sh
+BUILD= ./Build
+OPTIONS= $(CONFIG) $(FLAGS)
+
+all: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+clean: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+install: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+
+fresh: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) -c
+
+FRC:
diff --git a/contrib/sendmail/editmap/Makefile.m4 b/contrib/sendmail/editmap/Makefile.m4
new file mode 100644
index 0000000..906e198
--- /dev/null
+++ b/contrib/sendmail/editmap/Makefile.m4
@@ -0,0 +1,22 @@
+include(confBUILDTOOLSDIR`/M4/switch.m4')
+
+define(`confREQUIRE_LIBSM', `true')
+# sendmail dir
+SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
+PREPENDDEF(`confENVDEF', `confMAPDEF')
+PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
+
+bldPRODUCT_START(`executable', `editmap')
+define(`bldSOURCES', `editmap.c ')
+define(`bldINSTALL_DIR', `S')
+bldPUSH_SMLIB(`sm')
+bldPUSH_SMLIB(`smutil')
+bldPUSH_SMLIB(`smdb')
+APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
+bldPRODUCT_END
+
+bldPRODUCT_START(`manpage', `editmap')
+define(`bldSOURCES', `editmap.8')
+bldPRODUCT_END
+
+bldFINISH
diff --git a/contrib/sendmail/editmap/editmap.8 b/contrib/sendmail/editmap/editmap.8
new file mode 100644
index 0000000..9b450c5
--- /dev/null
+++ b/contrib/sendmail/editmap/editmap.8
@@ -0,0 +1,106 @@
+.\" Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+.\" All rights reserved.
+.\"
+.\" By using this file, you agree to the terms and conditions set
+.\" forth in the LICENSE file which can be found at the top level of
+.\" the sendmail distribution.
+.\"
+.\"
+.\" $Id: editmap.8,v 1.8 2001/06/15 21:33:19 ca Exp $
+.\"
+.TH EDITMAP 8 "$Date: 2001/06/15 21:33:19 $"
+.SH NAME
+.B editmap
+\- query and edit single records in database maps for sendmail
+.SH SYNOPSIS
+.B editmap
+.RB [ \-C
+.IR file ]
+.RB [ \-N ]
+.RB [ \-f ]
+.RB [ \-q|\-u|\-x ]
+maptype mapname
+key [ "value ..." ]
+.SH DESCRIPTION
+.B Editmap
+queries or edits one record in a database maps used by the keyed map lookups in
+sendmail(8).
+Arguments are passed on the command line and output (for queries) is
+directed to standard output.
+.PP
+Depending on how it is compiled,
+.B editmap
+handles up to three different database formats,
+selected using the
+.I maptype
+parameter.
+They may be
+.TP
+dbm
+DBM format maps.
+This requires the
+ndbm(3)
+library.
+.TP
+btree
+B-Tree format maps.
+This requires the new Berkeley DB
+library.
+.TP
+hash
+Hash format maps.
+This also requires the Berkeley DB
+library.
+.PP
+If the
+.I TrustedUser
+option is set in the sendmail configuration file and
+.B editmap
+is invoked as root, the generated files will be owned by
+the specified
+.IR TrustedUser.
+.SS Flags
+.TP
+.B \-C
+Use the specified
+.B sendmail
+configuration file for looking up the TrustedUser option.
+.TP
+.B \-N
+Include the null byte that terminates strings
+in the map (for alias maps).
+.TP
+.B \-f
+Normally all upper case letters in the key
+are folded to lower case.
+This flag disables that behaviour.
+This is intended to mesh with the
+\-f flag in the
+.B K
+line in sendmail.cf.
+The value is never case folded.
+.TP
+.B \-q
+Query the map for the specified key. If found, print value to standard
+output and exit with 0. If not found then print an error
+message to stdout and exit with EX_UNAVAILABLE.
+.TP
+.B \-u
+Update the record for
+.I key
+with
+.I value
+or inserts a new record if one doesn't exist. Exits with 0 on success
+or EX_IOERR on failure.
+.TP
+.B \-x
+Deletes the specific key from the map. Exits with 0 on success or
+EX_IOERR on failure.
+.TP
+.SH SEE ALSO
+sendmail(8),
+makemap(8)
+.SH HISTORY
+The
+.B editmap
+command has no history.
diff --git a/contrib/sendmail/editmap/editmap.c b/contrib/sendmail/editmap/editmap.c
new file mode 100644
index 0000000..45e3c07
--- /dev/null
+++ b/contrib/sendmail/editmap/editmap.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1992 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+#ifndef lint
+SM_UNUSED(static char copyright[]) =
+"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
+ All rights reserved.\n\
+ Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\
+ Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* ! lint */
+
+#ifndef lint
+SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.22 2002/01/11 23:52:27 gshapiro Exp $";
+#endif /* ! lint */
+
+
+#include <sys/types.h>
+#ifndef ISC_UNIX
+# include <sys/file.h>
+#endif /* ! ISC_UNIX */
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef EX_OK
+# undef EX_OK /* unistd.h may have another use for this */
+#endif /* EX_OK */
+#include <sysexits.h>
+#include <assert.h>
+#include <sendmail/sendmail.h>
+#include <sendmail/pathnames.h>
+#include <libsmdb/smdb.h>
+
+uid_t RealUid;
+gid_t RealGid;
+char *RealUserName;
+uid_t RunAsUid;
+uid_t RunAsGid;
+char *RunAsUserName;
+int Verbose = 2;
+bool DontInitGroups = false;
+uid_t TrustedUid = 0;
+BITMAP256 DontBlameSendmail;
+
+#define BUFSIZE 1024
+#define ISSEP(c) (isascii(c) && isspace(c))
+
+
+static void
+usage(progname)
+ char *progname;
+{
+ fprintf(stderr,
+ "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n",
+ progname);
+ exit(EX_USAGE);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ char *cfile;
+ bool verbose = false;
+ bool query = false;
+ bool update = false;
+ bool remove = false;
+ bool inclnull = false;
+ bool foldcase = true;
+ unsigned int nops = 0;
+ int exitstat;
+ int opt;
+ char *typename = NULL;
+ char *mapname = NULL;
+ char *keyname = NULL;
+ char *value = NULL;
+ int mode;
+ int smode;
+ int putflags = 0;
+ long sff = SFF_ROOTOK|SFF_REGONLY;
+ struct passwd *pw;
+ SMDB_DATABASE *database;
+ SMDB_DBENT db_key, db_val;
+ SMDB_DBPARAMS params;
+ SMDB_USER_INFO user_info;
+#if HASFCHOWN
+ FILE *cfp;
+ char buf[MAXLINE];
+#endif /* HASFCHOWN */
+ static char rnamebuf[MAXNAME]; /* holds RealUserName */
+ extern char *optarg;
+ extern int optind;
+
+ memset(&params, '\0', sizeof params);
+ params.smdbp_cache_size = 1024 * 1024;
+
+ progname = strrchr(argv[0], '/');
+ if (progname != NULL)
+ progname++;
+ else
+ progname = argv[0];
+ cfile = _PATH_SENDMAILCF;
+
+ clrbitmap(DontBlameSendmail);
+ RunAsUid = RealUid = getuid();
+ RunAsGid = RealGid = getgid();
+ pw = getpwuid(RealUid);
+ if (pw != NULL)
+ (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
+ else
+ (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
+ "Unknown UID %d", (int) RealUid);
+ RunAsUserName = RealUserName = rnamebuf;
+ user_info.smdbu_id = RunAsUid;
+ user_info.smdbu_group_id = RunAsGid;
+ (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
+ SMDB_MAX_USER_NAME_LEN);
+
+#define OPTIONS "C:fquxvN"
+ while ((opt = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch (opt)
+ {
+ case 'C':
+ cfile = optarg;
+ break;
+
+ case 'f':
+ foldcase = false;
+ break;
+
+ case 'q':
+ query = true;
+ nops++;
+ break;
+
+ case 'u':
+ update = true;
+ nops++;
+ break;
+
+ case 'x':
+ remove = true;
+ nops++;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'N':
+ inclnull = true;
+ break;
+
+ default:
+ usage(progname);
+ assert(0); /* NOTREACHED */
+ }
+ }
+
+ if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
+ sff |= SFF_NOSLINK;
+ if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
+ sff |= SFF_NOHLINK;
+ if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
+ sff |= SFF_NOWLINK;
+
+ argc -= optind;
+ argv += optind;
+ if ((nops != 1) ||
+ (query && argc != 3) ||
+ (remove && argc != 3) ||
+ (update && argc <= 3))
+ {
+ usage(progname);
+ assert(0); /* NOTREACHED */
+ }
+
+ typename = argv[0];
+ mapname = argv[1];
+ keyname = argv[2];
+ if (update)
+ value = argv[3];
+
+ if (foldcase)
+ {
+ char *p;
+
+ for (p = keyname; *p != '\0'; p++)
+ {
+ if (isascii(*p) && isupper(*p))
+ *p = tolower(*p);
+ }
+ }
+
+
+#if HASFCHOWN
+ /* Find TrustedUser value in sendmail.cf */
+ if ((cfp = fopen(cfile, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: %s: %s\n", progname,
+ cfile, sm_errstring(errno));
+ exit(EX_NOINPUT);
+ }
+ while (fgets(buf, sizeof(buf), cfp) != NULL)
+ {
+ register char *b;
+
+ if ((b = strchr(buf, '\n')) != NULL)
+ *b = '\0';
+
+ b = buf;
+ switch (*b++)
+ {
+ case 'O': /* option */
+ if (strncasecmp(b, " TrustedUser", 12) == 0 &&
+ !(isascii(b[12]) && isalnum(b[12])))
+ {
+ b = strchr(b, '=');
+ if (b == NULL)
+ continue;
+ while (isascii(*++b) && isspace(*b))
+ continue;
+ if (isascii(*b) && isdigit(*b))
+ TrustedUid = atoi(b);
+ else
+ {
+ TrustedUid = 0;
+ pw = getpwnam(b);
+ if (pw == NULL)
+ fprintf(stderr,
+ "TrustedUser: unknown user %s\n", b);
+ else
+ TrustedUid = pw->pw_uid;
+ }
+
+# ifdef UID_MAX
+ if (TrustedUid > UID_MAX)
+ {
+ fprintf(stderr,
+ "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
+ (long) TrustedUid,
+ (long) UID_MAX);
+ TrustedUid = 0;
+ }
+# endif /* UID_MAX */
+ break;
+ }
+
+
+ default:
+ continue;
+ }
+ }
+ (void) fclose(cfp);
+#endif /* HASFCHOWN */
+
+ if (query)
+ {
+ mode = O_RDONLY;
+ smode = S_IRUSR;
+ }
+ else
+ {
+ mode = O_RDWR | O_CREAT;
+ sff |= SFF_CREAT|SFF_NOTEXCL;
+ smode = S_IWUSR;
+ }
+
+ params.smdbp_num_elements = 4096;
+
+ errno = smdb_open_database(&database, mapname, mode, smode, sff,
+ typename, &user_info, &params);
+ if (errno != SMDBE_OK)
+ {
+ char *hint;
+
+ if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
+ (hint = smdb_db_definition(typename)) != NULL)
+ fprintf(stderr,
+ "%s: Need to recompile with -D%s for %s support\n",
+ progname, hint, typename);
+ else
+ fprintf(stderr,
+ "%s: error opening type %s map %s: %s\n",
+ progname, typename, mapname,
+ sm_errstring(errno));
+ exit(EX_CANTCREAT);
+ }
+
+ (void) database->smdb_sync(database, 0);
+
+ if (geteuid() == 0 && TrustedUid != 0)
+ {
+ errno = database->smdb_set_owner(database, TrustedUid, -1);
+ if (errno != SMDBE_OK)
+ {
+ fprintf(stderr,
+ "WARNING: ownership change on %s failed %s",
+ mapname, sm_errstring(errno));
+ }
+ }
+
+ exitstat = EX_OK;
+ if (query)
+ {
+ memset(&db_key, '\0', sizeof db_key);
+ memset(&db_val, '\0', sizeof db_val);
+
+ db_key.data = keyname;
+ db_key.size = strlen(keyname);
+ if (inclnull)
+ db_key.size++;
+
+ errno = database->smdb_get(database, &db_key, &db_val, 0);
+ if (errno != SMDBE_OK)
+ {
+ /* XXX - Need to distinguish between not found */
+ fprintf(stderr,
+ "%s: couldn't find key %s in map %s\n",
+ progname, keyname, mapname);
+ exitstat = EX_UNAVAILABLE;
+ }
+ else
+ {
+ printf("%.*s\n", (int) db_val.size,
+ (char *) db_val.data);
+ }
+ }
+ else if (update)
+ {
+ memset(&db_key, '\0', sizeof db_key);
+ memset(&db_val, '\0', sizeof db_val);
+
+ db_key.data = keyname;
+ db_key.size = strlen(keyname);
+ if (inclnull)
+ db_key.size++;
+ db_val.data = value;
+ db_val.size = strlen(value);
+ if (inclnull)
+ db_val.size++;
+
+ errno = database->smdb_put(database, &db_key, &db_val,
+ putflags);
+ if (errno != SMDBE_OK)
+ {
+ fprintf(stderr,
+ "%s: error updating (%s, %s) in map %s: %s\n",
+ progname, keyname, value, mapname,
+ sm_errstring(errno));
+ exitstat = EX_IOERR;
+ }
+ }
+ else if (remove)
+ {
+ memset(&db_key, '\0', sizeof db_key);
+ memset(&db_val, '\0', sizeof db_val);
+
+ db_key.data = keyname;
+ db_key.size = strlen(keyname);
+ if (inclnull)
+ db_key.size++;
+
+ errno = database->smdb_del(database, &db_key, 0);
+
+ switch (errno)
+ {
+ case SMDBE_NOT_FOUND:
+ fprintf(stderr,
+ "%s: key %s doesn't exist in map %s\n",
+ progname, keyname, mapname);
+ /* Don't set exitstat */
+ break;
+ case SMDBE_OK:
+ /* All's well */
+ break;
+ default:
+ fprintf(stderr,
+ "%s: couldn't remove key %s in map %s (error)\n",
+ progname, keyname, mapname);
+ exitstat = EX_IOERR;
+ break;
+ }
+ }
+ else
+ {
+ assert(0); /* NOT REACHED */
+ }
+
+ /*
+ ** Now close the database.
+ */
+
+ errno = database->smdb_close(database);
+ if (errno != SMDBE_OK)
+ {
+ fprintf(stderr, "%s: close(%s): %s\n",
+ progname, mapname, sm_errstring(errno));
+ exitstat = EX_IOERR;
+ }
+ smdb_free_database(database);
+
+ exit(exitstat);
+ /* NOTREACHED */
+ return exitstat;
+}
diff --git a/contrib/sendmail/include/libmilter/mfapi.h b/contrib/sendmail/include/libmilter/mfapi.h
index 2a64da7..506fcf3 100644
--- a/contrib/sendmail/include/libmilter/mfapi.h
+++ b/contrib/sendmail/include/libmilter/mfapi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -7,7 +7,7 @@
* the sendmail distribution.
*
*
- * $Id: mfapi.h,v 8.13.4.12 2000/09/09 02:11:48 ca Exp $
+ * $Id: mfapi.h,v 8.35 2001/10/09 19:05:24 gshapiro Exp $
*/
/*
@@ -17,13 +17,14 @@
#ifndef _LIBMILTER_MFAPI_H
# define _LIBMILTER_MFAPI_H 1
-# define LIBMILTER_API extern
+# include <sys/socket.h>
+# include "libmilter/mfdef.h"
+# define LIBMILTER_API extern
# include <sys/types.h>
#ifndef _SOCK_ADDR
-# include <sys/socket.h>
# define _SOCK_ADDR struct sockaddr
#endif /* ! _SOCK_ADDR */
@@ -42,24 +43,6 @@ typedef struct smfi_str *SMFICTX_PTR;
typedef struct smfiDesc smfiDesc_str;
typedef struct smfiDesc *smfiDesc_ptr;
-#define SMFI_VERSION 2 /* version number */
-
-/*
-** What the filter might do -- values to be ORed together for
-** smfiDesc.xxfi_flags.
-*/
-
-#define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */
-#define SMFIF_CHGBODY 0x00000002L /* filter may replace body */
-#define SMFIF_MODBODY SMFIF_CHGBODY /* backwards compatible */
-#define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */
-#define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */
-#define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */
-
-#define SMFI_V1_ACTS 0x0000000FL /* The actions of V1 filter */
-#define SMFI_V2_ACTS 0x0000001FL /* The actions of V2 filter */
-#define SMFI_CURR_ACTS SMFI_V2_ACTS /* The current version */
-
/*
** Type which callbacks should return to indicate message status.
** This may take on one of the SMFIS_* values listed below.
@@ -67,10 +50,6 @@ typedef struct smfiDesc *smfiDesc_ptr;
typedef int sfsistat;
-/*
-** structure describing one milter
-*/
-
#if defined(__linux__) && defined(__GNUC__) && defined(__cplusplus) && __GNUC_MINOR__ >= 8
# define SM__P(X) __PMT(X)
#else /* __linux__ && __GNUC__ && __cplusplus && _GNUC_MINOR__ >= 8 */
@@ -86,11 +65,15 @@ typedef int sfsistat;
# endif /* __STDC__ */
#endif /* __P */
+/*
+** structure describing one milter
+*/
+
struct smfiDesc
{
char *xxfi_name; /* filter name */
int xxfi_version; /* version code -- do not change */
- u_long xxfi_flags; /* flags */
+ unsigned long xxfi_flags; /* flags */
/* connection info filter */
sfsistat (*xxfi_connect) SM__P((SMFICTX *, char *, _SOCK_ADDR *));
@@ -111,7 +94,7 @@ struct smfiDesc
sfsistat (*xxfi_eoh) SM__P((SMFICTX *));
/* body block */
- sfsistat (*xxfi_body) SM__P((SMFICTX *, u_char *, size_t));
+ sfsistat (*xxfi_body) SM__P((SMFICTX *, unsigned char *, size_t));
/* end of message */
sfsistat (*xxfi_eom) SM__P((SMFICTX *));
@@ -130,6 +113,24 @@ LIBMILTER_API int smfi_settimeout __P((int));
LIBMILTER_API int smfi_setconn __P((char *));
LIBMILTER_API int smfi_stop __P((void));
+#define SMFI_VERSION 2 /* version number */
+
+/*
+** What the filter might do -- values to be ORed together for
+** smfiDesc.xxfi_flags.
+*/
+
+#define SMFIF_NONE 0x00000000L /* no flags */
+#define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */
+#define SMFIF_CHGBODY 0x00000002L /* filter may replace body */
+#define SMFIF_MODBODY SMFIF_CHGBODY /* backwards compatible */
+#define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */
+#define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */
+#define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */
+#if _FFR_QUARANTINE
+# define SMFIF_QUARANTINE 0x00000020L /* filter may quarantine envelope */
+#endif /* _FFR_QUARANTINE */
+
/*
** Continue processing message/connection.
*/
@@ -244,14 +245,14 @@ extern sfsistat xxfi_eoh __P((SMFICTX *));
*/
/* body block */
-extern sfsistat xxfi_body __P((SMFICTX *, u_char *, size_t));
+extern sfsistat xxfi_body __P((SMFICTX *, unsigned char *, size_t));
/*
** xxfi_body(ctx, bodyp, bodylen) Invoked for each body chunk. There may
** be multiple body chunks passed to the filter. End-of-lines are
** represented as received from SMTP (normally Carriage-Return/Line-Feed).
**
-** u_char *bodyp; Pointer to body data
+** unsigned char *bodyp; Pointer to body data
** size_t bodylen; Length of body data
*/
@@ -305,6 +306,15 @@ LIBMILTER_API char * smfi_getsymval __P((SMFICTX *, char *));
LIBMILTER_API int smfi_setreply __P((SMFICTX *, char *, char *, char *));
+#if _FFR_MULTILINE
+/*
+** Alternatively, smfi_setmlreply can be called if a multi-line SMTP reply
+** is needed.
+*/
+
+LIBMILTER_API int smfi_setmlreply __P((SMFICTX *, const char *, const char *, ...));
+#endif /* _FFR_MULTILINE */
+
/*
** Set the specific reply code to be used in response to the active
** command. If not specified, a generic reply code is used.
@@ -370,7 +380,7 @@ LIBMILTER_API int smfi_delrcpt __P((SMFICTX *, char *));
** not be deleted.
*/
-LIBMILTER_API int smfi_replacebody __P((SMFICTX *, u_char *, int));
+LIBMILTER_API int smfi_replacebody __P((SMFICTX *, unsigned char *, int));
/*
** Replace the body of the message. This routine may be called multiple
@@ -387,6 +397,16 @@ LIBMILTER_API int smfi_replacebody __P((SMFICTX *, u_char *, int));
** xxfi_abort is called. This can be used to reset state.
*/
+#if _FFR_QUARANTINE
+/*
+** Quarantine an envelope
+**
+** SMFICTX *ctx; Opaque context structure
+** char *reason: explanation
+*/
+
+LIBMILTER_API int smfi_quarantine __P((SMFICTX *ctx, char *reason));
+#endif /* _FFR_QUARANTINE */
/*
** Connection-private data (specific to an SMTP connection) can be
diff --git a/contrib/sendmail/include/libmilter/mfdef.h b/contrib/sendmail/include/libmilter/mfdef.h
new file mode 100644
index 0000000..649e98d
--- /dev/null
+++ b/contrib/sendmail/include/libmilter/mfdef.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ *
+ * $Id: mfdef.h,v 8.11 2001/09/12 18:02:19 gshapiro Exp $
+ */
+
+/*
+** mfdef.h -- Global definitions for mail filter and MTA.
+*/
+
+#ifndef _LIBMILTER_MFDEF_H
+# define _LIBMILTER_MFDEF_H 1
+
+/* Shared protocol constants */
+# define MILTER_LEN_BYTES 4 /* length of 32 bit integer in bytes */
+# define MILTER_OPTLEN (MILTER_LEN_BYTES * 3) /* length of options */
+# define MILTER_CHUNK_SIZE 65535 /* body chunk size */
+
+/* These apply to SMFIF_* flags */
+#define SMFI_V1_ACTS 0x0000000FL /* The actions of V1 filter */
+#if _FFR_QUARANTINE
+# define SMFI_V2_ACTS 0x0000003FL /* The actions of V2 filter */
+#else /* _FFR_QUARANTINE */
+# define SMFI_V2_ACTS 0x0000001FL /* The actions of V2 filter */
+#endif /* _FFR_QUARANTINE */
+#define SMFI_CURR_ACTS SMFI_V2_ACTS /* The current version */
+
+/* address families */
+# define SMFIA_UNKNOWN 'U' /* unknown */
+# define SMFIA_UNIX 'L' /* unix/local */
+# define SMFIA_INET '4' /* inet */
+# define SMFIA_INET6 '6' /* inet6 */
+
+/* commands: don't use anything smaller than ' ' */
+# define SMFIC_ABORT 'A' /* Abort */
+# define SMFIC_BODY 'B' /* Body chunk */
+# define SMFIC_CONNECT 'C' /* Connection information */
+# define SMFIC_MACRO 'D' /* Define macro */
+# define SMFIC_BODYEOB 'E' /* final body chunk (End) */
+# define SMFIC_HELO 'H' /* HELO/EHLO */
+# define SMFIC_HEADER 'L' /* Header */
+# define SMFIC_MAIL 'M' /* MAIL from */
+# define SMFIC_EOH 'N' /* EOH */
+# define SMFIC_OPTNEG 'O' /* Option negotiation */
+# define SMFIC_QUIT 'Q' /* QUIT */
+# define SMFIC_RCPT 'R' /* RCPT to */
+
+/* actions (replies) */
+# define SMFIR_ADDRCPT '+' /* add recipient */
+# define SMFIR_DELRCPT '-' /* remove recipient */
+# define SMFIR_ACCEPT 'a' /* accept */
+# define SMFIR_REPLBODY 'b' /* replace body (chunk) */
+# define SMFIR_CONTINUE 'c' /* continue */
+# define SMFIR_DISCARD 'd' /* discard */
+# define SMFIR_CHGHEADER 'm' /* change header */
+# define SMFIR_PROGRESS 'p' /* progress */
+# define SMFIR_REJECT 'r' /* reject */
+# define SMFIR_TEMPFAIL 't' /* tempfail */
+# define SMFIR_ADDHEADER 'h' /* add header */
+# define SMFIR_REPLYCODE 'y' /* reply code etc */
+# if _FFR_QUARANTINE
+# define SMFIR_QUARANTINE 'q' /* quarantine */
+# endif /* _FFR_QUARANTINE */
+
+/* What the MTA can send/filter wants in protocol */
+# define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */
+# define SMFIP_NOHELO 0x00000002L /* MTA should not send HELO info */
+# define SMFIP_NOMAIL 0x00000004L /* MTA should not send MAIL info */
+# define SMFIP_NORCPT 0x00000008L /* MTA should not send RCPT info */
+# define SMFIP_NOBODY 0x00000010L /* MTA should not send body */
+# define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */
+# define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */
+
+# define SMFI_V1_PROT 0x0000003FL /* The protocol of V1 filter */
+# define SMFI_V2_PROT 0x0000007FL /* The protocol of V2 filter */
+# define SMFI_CURR_PROT SMFI_V2_PROT /* The current version */
+
+#endif /* !_LIBMILTER_MFDEF_H */
diff --git a/contrib/sendmail/include/libmilter/milter.h b/contrib/sendmail/include/libmilter/milter.h
index ef54852..b714c3e 100644
--- a/contrib/sendmail/include/libmilter/milter.h
+++ b/contrib/sendmail/include/libmilter/milter.h
@@ -7,70 +7,18 @@
* the sendmail distribution.
*
*
- * $Id: milter.h,v 8.24.16.10 2001/07/20 04:19:35 gshapiro Exp $
+ * $Id: milter.h,v 8.35 2001/06/27 21:46:44 gshapiro Exp $
*/
/*
-** MILTER.H -- Global definitions for mail filter and MTA.
+** MILTER.H -- Global definitions for mail filter.
*/
#ifndef _LIBMILTER_MILTER_H
# define _LIBMILTER_MILTER_H 1
-#include "libmilter/mfapi.h"
#include "sendmail.h"
-
-/* Shared protocol constants */
-# define MILTER_LEN_BYTES 4 /* length of 32 bit integer in bytes */
-# define MILTER_OPTLEN (MILTER_LEN_BYTES * 3) /* length of options */
-# define MILTER_CHUNK_SIZE 65535 /* body chunk size */
-
-/* address families */
-# define SMFIA_UNKNOWN 'U' /* unknown */
-# define SMFIA_UNIX 'L' /* unix/local */
-# define SMFIA_INET '4' /* inet */
-# define SMFIA_INET6 '6' /* inet6 */
-
-/* commands: don't use anything smaller than ' ' */
-# define SMFIC_ABORT 'A' /* Abort */
-# define SMFIC_BODY 'B' /* Body chunk */
-# define SMFIC_CONNECT 'C' /* Connection information */
-# define SMFIC_MACRO 'D' /* Define macro */
-# define SMFIC_BODYEOB 'E' /* final body chunk (End) */
-# define SMFIC_HELO 'H' /* HELO/EHLO */
-# define SMFIC_HEADER 'L' /* Header */
-# define SMFIC_MAIL 'M' /* MAIL from */
-# define SMFIC_EOH 'N' /* EOH */
-# define SMFIC_OPTNEG 'O' /* Option negotiation */
-# define SMFIC_QUIT 'Q' /* QUIT */
-# define SMFIC_RCPT 'R' /* RCPT to */
-
-/* actions (replies) */
-# define SMFIR_ADDRCPT '+' /* add recipient */
-# define SMFIR_DELRCPT '-' /* remove recipient */
-# define SMFIR_ACCEPT 'a' /* accept */
-# define SMFIR_REPLBODY 'b' /* replace body (chunk) */
-# define SMFIR_CONTINUE 'c' /* continue */
-# define SMFIR_DISCARD 'd' /* discard */
-# define SMFIR_CHGHEADER 'm' /* change header */
-# define SMFIR_PROGRESS 'p' /* progress */
-# define SMFIR_REJECT 'r' /* reject */
-# define SMFIR_TEMPFAIL 't' /* tempfail */
-# define SMFIR_ADDHEADER 'h' /* add header */
-# define SMFIR_REPLYCODE 'y' /* reply code etc */
-
-/* What the MTA can send/filter wants in protocol */
-# define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */
-# define SMFIP_NOHELO 0x00000002L /* MTA should not send HELO info */
-# define SMFIP_NOMAIL 0x00000004L /* MTA should not send MAIL info */
-# define SMFIP_NORCPT 0x00000008L /* MTA should not send RCPT info */
-# define SMFIP_NOBODY 0x00000010L /* MTA should not send body */
-# define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */
-# define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */
-
-# define SMFI_V1_PROT 0x0000003FL /* The protocol of V1 filter */
-# define SMFI_V2_PROT 0x0000007FL /* The protocol of V2 filter */
-# define SMFI_CURR_PROT SMFI_V2_PROT /* The current version */
+#include "libmilter/mfapi.h"
/* socket and thread portability */
# include <pthread.h>
@@ -97,7 +45,7 @@ struct smfi_str
time_t ctx_timeout; /* timeout */
int ctx_state; /* state */
smfiDesc_ptr ctx_smfi; /* filter description */
- u_long ctx_pflags; /* protocol flags */
+ unsigned long ctx_pflags; /* protocol flags */
char **ctx_mac_ptr[MAX_MACROS_ENTRIES];
char *ctx_mac_buf[MAX_MACROS_ENTRIES];
char *ctx_reply; /* reply code */
diff --git a/contrib/sendmail/include/libsmdb/smdb.h b/contrib/sendmail/include/libsmdb/smdb.h
index db7fe8f..2315e32 100644
--- a/contrib/sendmail/include/libsmdb/smdb.h
+++ b/contrib/sendmail/include/libsmdb/smdb.h
@@ -1,28 +1,22 @@
/*
-** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
-** All rights reserved.
-**
-** By using this file, you agree to the terms and conditions set
-** forth in the LICENSE file which can be found at the top level of
-** the sendmail distribution.
-**
-** $Id: smdb.h,v 8.29.2.1.2.2 2000/10/05 22:23:55 gshapiro Exp $
-*/
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: smdb.h,v 8.38 2001/11/19 19:30:03 gshapiro Exp $
+ *
+ */
#ifndef _SMDB_H_
# define _SMDB_H_
# include <sys/types.h>
# include <sys/stat.h>
-# ifndef __P
-# include "sendmail/cdefs.h"
-# endif /* __P */
-
-# ifndef NDBM
-# ifndef NEWDB
-ERROR NDBM or NEWDB must be defined.
-# endif /* ! NEWDB */
-# endif /* ! NDBM */
+# include <sm/gen.h>
+# include <sm/errstring.h>
# ifdef NDBM
# include <ndbm.h>
@@ -36,28 +30,28 @@ ERROR NDBM or NEWDB must be defined.
# endif /* NEWDB */
/*
-** Some size constants
+** Some size constants
*/
+
#define SMDB_MAX_USER_NAME_LEN 1024
#define SMDB_MAX_NAME_LEN 1024
/*
-** This file defines the abstraction for database lookups. It is pretty
-** much a copy of the db2 interface with the exception that every function
-** returns 0 on success and non-zero on failure. The non-zero return code
-** is meaningful.
+** This file defines the abstraction for database lookups. It is pretty
+** much a copy of the db2 interface with the exception that every function
+** returns 0 on success and non-zero on failure. The non-zero return code
+** is meaningful.
**
-** I'm going to put the function comments in this file since the interface
-** MUST be the same for all inheritors of this interface.
+** I'm going to put the function comments in this file since the interface
+** MUST be the same for all inheritors of this interface.
*/
typedef struct database_struct SMDB_DATABASE;
typedef struct cursor_struct SMDB_CURSOR;
typedef struct entry_struct SMDB_DBENT;
-
/*
-** DB_CLOSE_FUNC -- close the database
+** DB_CLOSE_FUNC -- close the database
**
** Parameters:
** db -- The database to close.
@@ -66,12 +60,11 @@ typedef struct entry_struct SMDB_DBENT;
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_close_func) __P((SMDB_DATABASE *db));
+typedef int (*db_close_func) __P((SMDB_DATABASE *db));
-
/*
-** DB_DEL_FUNC -- removes a key and data pair from the database
+** DB_DEL_FUNC -- removes a key and data pair from the database
**
** Parameters:
** db -- The database to close.
@@ -83,13 +76,12 @@ typedef int (*db_close_func) __P((SMDB_DATABASE *db));
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_del_func) __P((SMDB_DATABASE *db,
- SMDB_DBENT *key, u_int flags));
+typedef int (*db_del_func) __P((SMDB_DATABASE *db,
+ SMDB_DBENT *key, unsigned int flags));
-
/*
-** DB_FD_FUNC -- Returns a pointer to a file used for the database.
+** DB_FD_FUNC -- Returns a pointer to a file used for the database.
**
** Parameters:
** db -- The database to close.
@@ -99,12 +91,11 @@ typedef int (*db_del_func) __P((SMDB_DATABASE *db,
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_fd_func) __P((SMDB_DATABASE *db, int* fd));
+typedef int (*db_fd_func) __P((SMDB_DATABASE *db, int* fd));
-
/*
-** DB_GET_FUNC -- Gets the data associated with a key.
+** DB_GET_FUNC -- Gets the data associated with a key.
**
** Parameters:
** db -- The database to close.
@@ -117,14 +108,13 @@ typedef int (*db_fd_func) __P((SMDB_DATABASE *db, int* fd));
** 0 - Success, otherwise errno.
**
*/
+
typedef int (*db_get_func) __P((SMDB_DATABASE *db,
SMDB_DBENT *key,
- SMDB_DBENT *data, u_int flags));
-
+ SMDB_DBENT *data, unsigned int flags));
-
/*
-** DB_PUT_FUNC -- Sets some data according to the key.
+** DB_PUT_FUNC -- Sets some data according to the key.
**
** Parameters:
** db -- The database to close.
@@ -139,13 +129,13 @@ typedef int (*db_get_func) __P((SMDB_DATABASE *db,
** 0 - Success, otherwise errno.
**
*/
+
typedef int (*db_put_func) __P((SMDB_DATABASE *db,
SMDB_DBENT *key,
- SMDB_DBENT *data, u_int flags));
+ SMDB_DBENT *data, unsigned int flags));
-
/*
-** DB_SYNC_FUNC -- Flush any cached information to disk.
+** DB_SYNC_FUNC -- Flush any cached information to disk.
**
** Parameters:
** db -- The database to sync.
@@ -155,11 +145,11 @@ typedef int (*db_put_func) __P((SMDB_DATABASE *db,
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_sync_func) __P((SMDB_DATABASE *db, u_int flags));
-
+typedef int (*db_sync_func) __P((SMDB_DATABASE *db, unsigned int flags));
+
/*
-** DB_SET_OWNER_FUNC -- Set the owner and group of the database files.
+** DB_SET_OWNER_FUNC -- Set the owner and group of the database files.
**
** Parameters:
** db -- The database to set.
@@ -170,12 +160,11 @@ typedef int (*db_sync_func) __P((SMDB_DATABASE *db, u_int flags));
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_set_owner_func) __P((SMDB_DATABASE *db, uid_t uid,
- gid_t gid));
-
+typedef int (*db_set_owner_func) __P((SMDB_DATABASE *db, uid_t uid, gid_t gid));
+
/*
-** DB_CURSOR -- Obtain a cursor for sequential access
+** DB_CURSOR -- Obtain a cursor for sequential access
**
** Parameters:
** db -- The database to use.
@@ -186,8 +175,9 @@ typedef int (*db_set_owner_func) __P((SMDB_DATABASE *db, uid_t uid,
** 0 - Success, otherwise errno.
**
*/
+
typedef int (*db_cursor_func) __P((SMDB_DATABASE *db,
- SMDB_CURSOR **cursor, u_int flags));
+ SMDB_CURSOR **cursor, unsigned int flags));
typedef int (*db_lockfd_func) __P((SMDB_DATABASE *db));
@@ -204,11 +194,8 @@ struct database_struct
db_lockfd_func smdb_lockfd;
void *smdb_impl;
};
-
-
-
/*
-** DB_CURSOR_CLOSE -- Close a cursor
+** DB_CURSOR_CLOSE -- Close a cursor
**
** Parameters:
** cursor -- The cursor to close.
@@ -217,11 +204,11 @@ struct database_struct
** 0 - Success, otherwise errno.
**
*/
+
typedef int (*db_cursor_close_func) __P((SMDB_CURSOR *cursor));
-
/*
-** DB_CURSOR_DEL -- Delete the key/value pair of this cursor
+** DB_CURSOR_DEL -- Delete the key/value pair of this cursor
**
** Parameters:
** cursor -- The cursor.
@@ -231,11 +218,12 @@ typedef int (*db_cursor_close_func) __P((SMDB_CURSOR *cursor));
** 0 - Success, otherwise errno.
**
*/
-typedef int (*db_cursor_del_func) __P((SMDB_CURSOR *cursor, u_int flags));
-
+typedef int (*db_cursor_del_func) __P((SMDB_CURSOR *cursor,
+ unsigned int flags));
+
/*
-** DB_CURSOR_GET -- Get the key/value of this cursor.
+** DB_CURSOR_GET -- Get the key/value of this cursor.
**
** Parameters:
** cursor -- The cursor.
@@ -250,22 +238,23 @@ typedef int (*db_cursor_del_func) __P((SMDB_CURSOR *cursor, u_int flags));
** database is hit.
**
*/
+
typedef int (*db_cursor_get_func) __P((SMDB_CURSOR *cursor,
SMDB_DBENT *key,
SMDB_DBENT *data,
- u_int flags));
+ unsigned int flags));
/*
-** Flags for DB_CURSOR_GET
+** Flags for DB_CURSOR_GET
*/
+
#define SMDB_CURSOR_GET_FIRST 0
#define SMDB_CURSOR_GET_LAST 1
#define SMDB_CURSOR_GET_NEXT 2
#define SMDB_CURSOR_GET_RANGE 3
-
/*
-** DB_CURSOR_PUT -- Put the key/value at this cursor.
+** DB_CURSOR_PUT -- Put the key/value at this cursor.
**
** Parameters:
** cursor -- The cursor.
@@ -277,10 +266,11 @@ typedef int (*db_cursor_get_func) __P((SMDB_CURSOR *cursor,
** 0 - Success, otherwise errno.
**
*/
+
typedef int (*db_cursor_put_func) __P((SMDB_CURSOR *cursor,
SMDB_DBENT *key,
SMDB_DBENT *data,
- u_int flags));
+ unsigned int flags));
@@ -296,9 +286,9 @@ struct cursor_struct
struct database_params_struct
{
- u_int smdbp_num_elements;
- u_int smdbp_cache_size;
- bool smdbp_allow_dup;
+ unsigned int smdbp_num_elements;
+ unsigned int smdbp_cache_size;
+ bool smdbp_allow_dup;
};
typedef struct database_params_struct SMDB_DBPARAMS;
@@ -319,10 +309,10 @@ struct entry_struct
};
typedef char *SMDB_DBTYPE;
-typedef u_int SMDB_FLAG;
+typedef unsigned int SMDB_FLAG;
/*
-** These are types of databases.
+** These are types of databases.
*/
# define SMDB_TYPE_DEFAULT NULL
@@ -335,8 +325,9 @@ typedef u_int SMDB_FLAG;
# define SMDB_TYPE_NDBM_LEN 4
/*
-** These are flags
+** These are flags
*/
+
/* Flags for put */
# define SMDBF_NO_OVERWRITE 0x00000001
# define SMDBF_ALLOW_DUP 0x00000002
diff --git a/contrib/sendmail/include/sendmail/mailstats.h b/contrib/sendmail/include/sendmail/mailstats.h
index 830061d..9a8a635 100644
--- a/contrib/sendmail/include/sendmail/mailstats.h
+++ b/contrib/sendmail/include/sendmail/mailstats.h
@@ -10,10 +10,14 @@
* the sendmail distribution.
*
*
- * $Id: mailstats.h,v 8.13 1999/05/22 02:29:10 ca Exp $
+ * $Id: mailstats.h,v 8.18 2001/11/21 13:39:10 gshapiro Exp $
*/
-#define STAT_VERSION 3
+#if _FFR_QUARANTINE
+# define STAT_VERSION 4
+#else /* _FFR_QUARANTINE */
+# define STAT_VERSION 3
+#endif /* _FFR_QUARANTINE */
#define STAT_MAGIC 0x1B1DE
/*
@@ -35,4 +39,7 @@ struct statistics
long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
long stat_nr[MAXMAILERS]; /* # rejects by each mailer */
long stat_nd[MAXMAILERS]; /* # discards by each mailer */
+#if _FFR_QUARANTINE
+ long stat_nq[MAXMAILERS]; /* # quarantines by each mailer */
+#endif /* _FFR_QUARANTINE */
};
diff --git a/contrib/sendmail/include/sendmail/pathnames.h b/contrib/sendmail/include/sendmail/pathnames.h
index 9f99f6c..54efd32 100644
--- a/contrib/sendmail/include/sendmail/pathnames.h
+++ b/contrib/sendmail/include/sendmail/pathnames.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -9,28 +9,54 @@
* the sendmail distribution.
*
*
- * $Id: pathnames.h,v 8.16.8.8 2000/09/28 21:26:39 gshapiro Exp $
+ * $Id: pathnames.h,v 8.35 2001/03/23 22:09:44 ca Exp $
*/
+#ifndef SM_PATHNAMES_H
+# define SM_PATHNAMES_H
-# ifndef _PATH_SENDMAILCF
-# if defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF)
-# define _PATH_SENDMAILCF _PATH_VENDOR_CF
-# else /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */
-# define _PATH_SENDMAILCF "/etc/mail/sendmail.cf"
-# endif /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */
-# endif /* ! _PATH_SENDMAILCF */
-# ifndef _PATH_SENDMAILPID
-# ifdef BSD4_4
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# else /* BSD4_4 */
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif /* BSD4_4 */
-# endif /* ! _PATH_SENDMAILPID */
+# ifndef _PATH_SENDMAILCF
+# if defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF)
+# define _PATH_SENDMAILCF _PATH_VENDOR_CF
+# else /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */
+# define _PATH_SENDMAILCF "/etc/mail/sendmail.cf"
+# endif /* defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF) */
+# endif /* ! _PATH_SENDMAILCF */
-# ifndef _PATH_HOSTS
-# define _PATH_HOSTS "/etc/hosts"
-# endif /* ! _PATH_HOSTS */
+# ifndef _PATH_SENDMAILPID
+# ifdef BSD4_4
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# else /* BSD4_4 */
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif /* BSD4_4 */
+# endif /* ! _PATH_SENDMAILPID */
+# ifndef _PATH_SENDMAIL
+# define _PATH_SENDMAIL "/usr/lib/sendmail"
+# endif /* ! _PATH_SENDMAIL */
+# ifndef _PATH_MAILDIR
+# define _PATH_MAILDIR "/var/spool/mail"
+# endif /* ! _PATH_MAILDIR */
+
+# ifndef _PATH_LOCTMP
+# define _PATH_LOCTMP "/tmp/local.XXXXXX"
+# endif /* ! _PATH_LOCTMP */
+
+# ifndef _PATH_HOSTS
+# define _PATH_HOSTS "/etc/hosts"
+# endif /* ! _PATH_HOSTS */
+
+
+
+# ifndef _DIR_SENDMAILCF
+# define _DIR_SENDMAILCF "/etc/mail/"
+# endif /* ! _DIR_SENDMAILCF */
+
+# define SM_GET_RIGHT_CF 0 /* get "right" .cf */
+# define SM_GET_SENDMAIL_CF 1 /* always use sendmail.cf */
+# define SM_GET_SUBMIT_CF 2 /* always use submit.cf */
+
+extern char *getcfname __P((int, int, int, char *));
+#endif /* ! SM_PATHNAMES_H */
diff --git a/contrib/sendmail/include/sendmail/sendmail.h b/contrib/sendmail/include/sendmail/sendmail.h
index 395b895..bbd3177 100644
--- a/contrib/sendmail/include/sendmail/sendmail.h
+++ b/contrib/sendmail/include/sendmail/sendmail.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -10,23 +10,18 @@
* the sendmail distribution.
*
*
- * $Id: sendmail.h,v 8.34.4.8 2001/06/01 05:06:51 gshapiro Exp $
+ * $Id: sendmail.h,v 8.67 2001/09/08 01:20:57 gshapiro Exp $
*/
/*
** SENDMAIL.H -- Global definitions for sendmail.
*/
-#if SFIO
-# include <sfio/stdio.h>
-#else /* SFIO */
-# include <stdio.h>
-#endif /* SFIO */
-#include <string.h>
+#include <stdio.h>
+#include <sm/bitops.h>
+#include <sm/io.h>
+#include <sm/string.h>
#include "conf.h"
-#include "sendmail/errstring.h"
-#include "sendmail/useful.h"
-
/**********************************************************************
** Table sizes, etc....
@@ -37,45 +32,6 @@
#endif /* ! MAXMAILERS */
/*
-** Data structure for bit maps.
-**
-** Each bit in this map can be referenced by an ascii character.
-** This is 256 possible bits, or 32 8-bit bytes.
-*/
-
-#define BITMAPBITS 256 /* number of bits in a bit map */
-#define BYTEBITS 8 /* number of bits in a byte */
-#define BITMAPBYTES (BITMAPBITS / BYTEBITS) /* number of bytes in bit map */
-
-/* internal macros */
-#define _BITWORD(bit) ((bit) / (BYTEBITS * sizeof (int)))
-#define _BITBIT(bit) ((unsigned int)1 << ((bit) % (BYTEBITS * sizeof (int))))
-
-typedef unsigned int BITMAP256[BITMAPBYTES / sizeof (int)];
-
-/* properly case and truncate bit */
-#define bitidx(bit) ((unsigned int) (bit) & 0xff)
-
-/* test bit number N */
-#define bitnset(bit, map) ((map)[_BITWORD(bit)] & _BITBIT(bit))
-
-/* set bit number N */
-#define setbitn(bit, map) (map)[_BITWORD(bit)] |= _BITBIT(bit)
-
-/* clear bit number N */
-#define clrbitn(bit, map) (map)[_BITWORD(bit)] &= ~_BITBIT(bit)
-
-/* clear an entire bit map */
-#define clrbitmap(map) memset((char *) map, '\0', BITMAPBYTES)
-
-
-/*
-** Utility macros
-*/
-
-/* return number of bytes left in a buffer */
-#define SPACELEFT(buf, ptr) (sizeof buf - ((ptr) - buf))
-/*
** Flags passed to safefile/safedirpath.
*/
@@ -85,7 +41,7 @@ typedef unsigned int BITMAP256[BITMAPBYTES / sizeof (int)];
#define SFF_ROOTOK 0x00000004L /* ok for root to own this file */
#define SFF_RUNASREALUID 0x00000008L /* if no ctladdr, run as real uid */
#define SFF_NOPATHCHECK 0x00000010L /* don't bother checking dir path */
-#define SFF_SETUIDOK 0x00000020L /* setuid files are ok */
+#define SFF_SETUIDOK 0x00000020L /* set-user-ID files are ok */
#define SFF_CREAT 0x00000040L /* ok to create file if necessary */
#define SFF_REGONLY 0x00000080L /* regular files only */
#define SFF_SAFEDIRPATH 0x00000100L /* no writable directories allowed */
@@ -108,6 +64,7 @@ typedef unsigned int BITMAP256[BITMAPBYTES / sizeof (int)];
extern int safefile __P((char *, UID_T, GID_T, char *, long, int, struct stat *));
extern int safedirpath __P((char *, UID_T, GID_T, char *, long, int, int));
extern int safeopen __P((char *, int, int, long));
+extern SM_FILE_T*safefopen __P((char *, int, int, long));
extern int dfopen __P((char *, int, int, long));
extern bool filechanged __P((char *, int, struct stat *));
@@ -116,6 +73,7 @@ extern bool filechanged __P((char *, int, struct stat *));
**
** Hopefully nobody uses these.
*/
+
#define DBS_SAFE 0
#define DBS_ASSUMESAFECHOWN 1
#define DBS_GROUPWRITABLEDIRPATHSAFE 2
@@ -144,42 +102,33 @@ extern bool filechanged __P((char *, int, struct stat *));
#define DBS_HELPFILEINUNSAFEDIRPATH 25
#define DBS_FORWARDFILEINUNSAFEDIRPATHSAFE 26
#define DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE 27
-#define DBS_RUNPROGRAMINUNSAFEDIRPATH 28 /* Not used yet */
+#define DBS_RUNPROGRAMINUNSAFEDIRPATH 28
#define DBS_RUNWRITABLEPROGRAM 29
#define DBS_INCLUDEFILEINUNSAFEDIRPATH 30
#define DBS_NONROOTSAFEADDR 31
#define DBS_TRUSTSTICKYBIT 32
#define DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH 33
#define DBS_INSUFFICIENTENTROPY 34
-#if _FFR_UNSAFE_SASL
-# define DBS_GROUPREADABLESASLFILE 35
-#endif /* _FFR_UNSAFE_SASL */
-#if _FFR_UNSAFE_WRITABLE_INCLUDE
-# define DBS_GROUPWRITABLEFORWARDFILE 36
-# define DBS_GROUPWRITABLEINCLUDEFILE 37
-# define DBS_WORLDWRITABLEFORWARDFILE 38
-# define DBS_WORLDWRITABLEINCLUDEFILE 39
-#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */
+#define DBS_GROUPREADABLESASLDBFILE 35
+#define DBS_GROUPWRITABLESASLDBFILE 36
+#define DBS_GROUPWRITABLEFORWARDFILE 37
+#define DBS_GROUPWRITABLEINCLUDEFILE 38
+#define DBS_WORLDWRITABLEFORWARDFILE 39
+#define DBS_WORLDWRITABLEINCLUDEFILE 40
+#define DBS_GROUPREADABLEKEYFILE 41
+#if _FFR_GROUPREADABLEAUTHINFOFILE
+# define DBS_GROUPREADABLEAUTHINFOFILE 42
+#endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
/* struct defining such things */
struct dbsval
{
- char *dbs_name; /* name of DontBlameSendmail flag */
- u_char dbs_flag; /* numeric level */
+ char *dbs_name; /* name of DontBlameSendmail flag */
+ unsigned char dbs_flag; /* numeric level */
};
-#if _FFR_DPRINTF
-extern void dprintf __P((const char *, ...));
-extern int dflush __P((void));
-#else /* _FFR_DPRINTF */
-#define dprintf printf
-#define dflush() fflush(stdout)
-#endif /* _FFR_DPRINTF */
-
-extern int sm_snprintf __P((char *, size_t, const char *, ...));
-extern int sm_vsnprintf __P((char *, size_t, const char *, va_list));
-extern char *quad_to_string __P((QUAD_T));
-
-extern size_t strlcpy __P((char *, const char *, size_t));
-extern size_t strlcat __P((char *, const char *, size_t));
+/* Flags for submitmode */
+#define SUBMIT_UNKNOWN 0x0000 /* unknown agent type */
+#define SUBMIT_MTA 0x0001 /* act like a message transfer agent */
+#define SUBMIT_MSA 0x0002 /* act like a message submission agent */
diff --git a/contrib/sendmail/include/sm/assert.h b/contrib/sendmail/include/sm/assert.h
new file mode 100644
index 0000000..6b86536
--- /dev/null
+++ b/contrib/sendmail/include/sm/assert.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: assert.h,v 1.10 2001/06/07 20:04:53 ca Exp $
+ */
+
+/*
+** libsm abnormal program termination and assertion checking
+** See libsm/assert.html for documentation.
+*/
+
+#ifndef SM_ASSERT_H
+# define SM_ASSERT_H
+
+# include <sm/gen.h>
+# include <sm/debug.h>
+
+/*
+** abnormal program termination
+*/
+
+typedef void (*SM_ABORT_HANDLER_T) __P((const char *, int, const char *));
+
+extern SM_DEAD(void
+sm_abort_at __P((
+ const char *,
+ int,
+ const char *)));
+
+extern void
+sm_abort_sethandler __P((
+ SM_ABORT_HANDLER_T));
+
+extern SM_DEAD(void PRINTFLIKE(1, 2)
+sm_abort __P((
+ char *,
+ ...)));
+
+/*
+** assertion checking
+*/
+
+# ifndef SM_CHECK_ALL
+# define SM_CHECK_ALL 1
+# endif /* ! SM_CHECK_ALL */
+
+# ifndef SM_CHECK_REQUIRE
+# define SM_CHECK_REQUIRE SM_CHECK_ALL
+# endif /* ! SM_CHECK_REQUIRE */
+
+# ifndef SM_CHECK_ENSURE
+# define SM_CHECK_ENSURE SM_CHECK_ALL
+# endif /* ! SM_CHECK_ENSURE */
+
+# ifndef SM_CHECK_ASSERT
+# define SM_CHECK_ASSERT SM_CHECK_ALL
+# endif /* ! SM_CHECK_ASSERT */
+
+# if SM_CHECK_REQUIRE
+# if defined(__STDC__) || defined(__cplusplus)
+# define SM_REQUIRE(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_REQUIRE(" #cond ") failed"), 0)))
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define SM_REQUIRE(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_REQUIRE(cond) failed"), 0)))
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+# else /* SM_CHECK_REQUIRE */
+# define SM_REQUIRE(cond) ((void) 0)
+# endif /* SM_CHECK_REQUIRE */
+
+# define SM_REQUIRE_ISA(obj, magic) \
+ SM_REQUIRE((obj) != NULL && (obj)->sm_magic == (magic))
+
+# if SM_CHECK_ENSURE
+# if defined(__STDC__) || defined(__cplusplus)
+# define SM_ENSURE(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_ENSURE(" #cond ") failed"), 0)))
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define SM_ENSURE(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_ENSURE(cond) failed"), 0)))
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+# else /* SM_CHECK_ENSURE */
+# define SM_ENSURE(cond) ((void) 0)
+# endif /* SM_CHECK_ENSURE */
+
+# if SM_CHECK_ASSERT
+# if defined(__STDC__) || defined(__cplusplus)
+# define SM_ASSERT(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_ASSERT(" #cond ") failed"), 0)))
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define SM_ASSERT(cond) \
+ ((void) ((cond) || (sm_abort_at(__FILE__, __LINE__, \
+ "SM_ASSERT(cond) failed"), 0)))
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+# else /* SM_CHECK_ASSERT */
+# define SM_ASSERT(cond) ((void) 0)
+# endif /* SM_CHECK_ASSERT */
+
+extern SM_DEBUG_T SmExpensiveRequire;
+extern SM_DEBUG_T SmExpensiveEnsure;
+extern SM_DEBUG_T SmExpensiveAssert;
+
+#endif /* ! SM_ASSERT_H */
diff --git a/contrib/sendmail/include/sm/bitops.h b/contrib/sendmail/include/sm/bitops.h
new file mode 100644
index 0000000..44778ba
--- /dev/null
+++ b/contrib/sendmail/include/sm/bitops.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ *
+ * $Id: bitops.h,v 1.2 2001/09/22 22:05:42 ca Exp $
+ */
+
+#ifndef SM_BITOPS_H
+# define SM_BITOPS_H
+
+/*
+** Data structure for bit maps.
+**
+** Each bit in this map can be referenced by an ascii character.
+** This is 256 possible bits, or 32 8-bit bytes.
+*/
+
+# define BITMAPBITS 256 /* number of bits in a bit map */
+# define BYTEBITS 8 /* number of bits in a byte */
+# define BITMAPBYTES (BITMAPBITS / BYTEBITS) /* number of bytes in bit map */
+# define BITMAPMAX ((BITMAPBYTES / sizeof (int)) - 1)
+
+/* internal macros */
+
+/* make sure this index never leaves the allowed range: 0 to BITMAPMAX */
+# define _BITWORD(bit) (((unsigned char)(bit) / (BYTEBITS * sizeof (int))) & BITMAPMAX)
+# define _BITBIT(bit) ((unsigned int)1 << ((unsigned char)(bit) % (BYTEBITS * sizeof (int))))
+
+typedef unsigned int BITMAP256[BITMAPBYTES / sizeof (int)];
+
+/* properly case and truncate bit */
+# define bitidx(bit) ((unsigned int) (bit) & 0xff)
+
+/* test bit number N */
+# define bitnset(bit, map) ((map)[_BITWORD(bit)] & _BITBIT(bit))
+
+/* set bit number N */
+# define setbitn(bit, map) (map)[_BITWORD(bit)] |= _BITBIT(bit)
+
+/* clear bit number N */
+# define clrbitn(bit, map) (map)[_BITWORD(bit)] &= ~_BITBIT(bit)
+
+/* clear an entire bit map */
+# define clrbitmap(map) memset((char *) map, '\0', BITMAPBYTES)
+
+/* bit hacking */
+# define bitset(bit, word) (((word) & (bit)) != 0)
+
+#endif /* ! SM_BITOPS_H */
diff --git a/contrib/sendmail/include/sm/cdefs.h b/contrib/sendmail/include/sm/cdefs.h
new file mode 100644
index 0000000..b8597d9
--- /dev/null
+++ b/contrib/sendmail/include/sm/cdefs.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: cdefs.h,v 1.14 2001/06/07 20:04:53 ca Exp $
+ */
+
+/*
+** libsm C language portability macros
+** See libsm/cdefs.html for documentation.
+*/
+
+#ifndef SM_CDEFS_H
+# define SM_CDEFS_H
+
+# include <sm/config.h>
+
+/*
+** BSD and Linux have <sys/cdefs.h> which defines a set of C language
+** portability macros that are a defacto standard in the open source
+** community.
+*/
+
+# if SM_CONF_SYS_CDEFS_H
+# include <sys/cdefs.h>
+# endif /* SM_CONF_SYS_CDEFS_H */
+
+/*
+** Define the standard C language portability macros
+** for platforms that lack <sys/cdefs.h>.
+*/
+
+# if !SM_CONF_SYS_CDEFS_H
+# if defined(__cplusplus)
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS };
+# else /* defined(__cplusplus) */
+# define __BEGIN_DECLS
+# define __END_DECLS
+# endif /* defined(__cplusplus) */
+# if defined(__STDC__) || defined(__cplusplus)
+# define __P(protos) protos
+# define __CONCAT(x,y) x ## y
+# define __STRING(x) #x
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define __P(protos) ()
+# define __CONCAT(x,y) x/**/y
+# define __STRING(x) "x"
+# define const
+# define signed
+# define volatile
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+# endif /* !SM_CONF_SYS_CDEFS_H */
+
+/*
+** Define SM_DEAD, a macro used to declare functions that do not return
+** to their caller.
+*/
+
+# ifndef SM_DEAD
+# if __GNUC__ >= 2
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 5
+# define SM_DEAD(proto) volatile proto
+# else /* __GNUC__ == 2 && __GNUC_MINOR__ < 5 */
+# define SM_DEAD(proto) proto __attribute__((__noreturn__))
+# endif /* __GNUC__ == 2 && __GNUC_MINOR__ < 5 */
+# else /* __GNUC__ >= 2 */
+# define SM_DEAD(proto) proto
+# endif /* __GNUC__ >= 2 */
+# endif /* SM_DEAD */
+
+/*
+** Define SM_UNUSED, a macro used to declare variables that may be unused.
+*/
+
+# ifndef SM_UNUSED
+# if __GNUC__ >= 2
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
+# define SM_UNUSED(decl) decl
+# else /* __GNUC__ == 2 && __GNUC_MINOR__ < 7 */
+# define SM_UNUSED(decl) decl __attribute__((__unused__))
+# endif /* __GNUC__ == 2 && __GNUC_MINOR__ < 7 */
+# else /* __GNUC__ >= 2 */
+# define SM_UNUSED(decl) decl
+# endif /* __GNUC__ >= 2 */
+# endif /* SM_UNUSED */
+
+/*
+** The SM_NONVOLATILE macro is used to declare variables that are not
+** volatile, but which must be declared volatile when compiling with
+** gcc -O -Wall in order to suppress bogus warning messages.
+**
+** Variables that actually are volatile should be declared volatile
+** using the "volatile" keyword. If a variable actually is volatile,
+** then SM_NONVOLATILE should not be used.
+**
+** To compile sendmail with gcc and see all non-bogus warnings,
+** you should use
+** gcc -O -Wall -DSM_OMIT_BOGUS_WARNINGS ...
+** Do not use -DSM_OMIT_BOGUS_WARNINGS when compiling the production
+** version of sendmail, because there is a performance hit.
+*/
+
+# ifdef SM_OMIT_BOGUS_WARNINGS
+# define SM_NONVOLATILE volatile
+# else /* SM_OMIT_BOGUS_WARNINGS */
+# define SM_NONVOLATILE
+# endif /* SM_OMIT_BOGUS_WARNINGS */
+
+/*
+** Turn on format string argument checking.
+*/
+
+# ifndef SM_CONF_FORMAT_TEST
+# if __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+# define SM_CONF_FORMAT_TEST 1
+# else /* __GNUC__ == 2 && __GNUC_MINOR__ >= 7 */
+# define SM_CONF_FORMAT_TEST 0
+# endif /* __GNUC__ == 2 && __GNUC_MINOR__ >= 7 */
+# endif /* SM_CONF_FORMAT_TEST */
+
+# ifndef PRINTFLIKE
+# if SM_CONF_FORMAT_TEST
+# define PRINTFLIKE(x,y) __attribute__ ((__format__ (__printf__, x, y)))
+# else /* SM_CONF_FORMAT_TEST */
+# define PRINTFLIKE(x,y)
+# endif /* SM_CONF_FORMAT_TEST */
+# endif /* ! PRINTFLIKE */
+
+# ifndef SCANFLIKE
+# if SM_CONF_FORMAT_TEST
+# define SCANFLIKE(x,y) __attribute__ ((__format__ (__scanf__, x, y)))
+# else /* SM_CONF_FORMAT_TEST */
+# define SCANFLIKE(x,y)
+# endif /* SM_CONF_FORMAT_TEST */
+# endif /* ! SCANFLIKE */
+
+#endif /* ! SM_CDEFS_H */
diff --git a/contrib/sendmail/include/sm/cf.h b/contrib/sendmail/include/sm/cf.h
new file mode 100644
index 0000000..3869210
--- /dev/null
+++ b/contrib/sendmail/include/sm/cf.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: cf.h,v 1.2 2001/03/08 03:23:07 ca Exp $
+ */
+
+#ifndef SM_CF_H
+# define SM_CF_H
+
+#include <sm/gen.h>
+
+typedef struct
+{
+ char *opt_name;
+ char *opt_val;
+} SM_CF_OPT_T;
+
+extern int
+sm_cf_getopt __P((
+ char *path,
+ int optc,
+ SM_CF_OPT_T *optv));
+
+#endif /* ! SM_CF_H */
diff --git a/contrib/sendmail/include/sm/clock.h b/contrib/sendmail/include/sm/clock.h
new file mode 100644
index 0000000..b0dfb43
--- /dev/null
+++ b/contrib/sendmail/include/sm/clock.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: clock.h,v 1.11 2001/05/14 23:25:37 gshapiro Exp $
+ */
+
+/*
+** CLOCK.H -- for co-ordinating timed events
+*/
+
+#ifndef _SM_CLOCK_H
+# define _SM_CLOCK_H 1
+
+# include <sm/signal.h>
+# if SM_CONF_SETITIMER
+# include <sys/time.h>
+# endif /* SM_CONF_SETITIMER */
+
+/*
+** STRUCT SM_EVENT -- event queue.
+**
+** Maintained in sorted order.
+**
+** We store the pid of the process that set this event to insure
+** that when we fork we will not take events intended for the parent.
+*/
+
+struct sm_event
+{
+# if SM_CONF_SETITIMER
+ struct timeval ev_time; /* time of the call (microseconds) */
+# else /* SM_CONF_SETITIMER */
+ time_t ev_time; /* time of the call (seconds) */
+# endif /* SM_CONF_SETITIMER */
+ void (*ev_func)__P((int));
+ /* function to call */
+ int ev_arg; /* argument to ev_func */
+ pid_t ev_pid; /* pid that set this event */
+ struct sm_event *ev_link; /* link to next item */
+};
+
+typedef struct sm_event SM_EVENT;
+
+/* functions */
+extern void sm_clrevent __P((SM_EVENT *));
+extern void sm_clear_events __P((void));
+extern SM_EVENT *sm_setevent __P((time_t, void(*)(), int));
+extern SM_EVENT *sm_seteventm __P((int, void(*)(), int));
+extern SM_EVENT *sm_sigsafe_seteventm __P((int, void(*)(), int));
+extern SIGFUNC_DECL sm_tick __P((int));
+
+/*
+** SM_SETEVENT -- set an event to happen at a specific time in seconds.
+**
+** Translates the seconds into millseconds and calls sm_seteventm()
+** to get a specific event to happen in the future at a specific time.
+**
+** Parameters:
+** t -- intvl until next event occurs (seconds).
+** f -- function to call on event.
+** a -- argument to func on event.
+**
+** Returns:
+** result of sm_seteventm().
+**
+** Side Effects:
+** Any that sm_seteventm() have.
+*/
+
+#define sm_setevent(t, f, a) sm_seteventm((int)((t) * 1000), (f), (a))
+#define sm_sigsafe_setevent(t, f, a) sm_sigsafe_seteventm((int)((t) * 1000), (f), (a))
+
+#endif /* _SM_CLOCK_H */
diff --git a/contrib/sendmail/include/sm/conf.h b/contrib/sendmail/include/sm/conf.h
new file mode 100644
index 0000000..f54cd96
--- /dev/null
+++ b/contrib/sendmail/include/sm/conf.h
@@ -0,0 +1,2803 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ *
+ * $Id: conf.h,v 1.82 2001/12/20 16:14:48 ca Exp $
+ */
+
+/*
+** CONF.H -- All user-configurable parameters for sendmail
+**
+** Send updates to sendmail@Sendmail.ORG so they will be
+** included in the next release.
+*/
+
+#ifndef SM_CONF_H
+# define SM_CONF_H 1
+
+
+# include <sm/config.h>
+# include <sm/varargs.h>
+
+/*
+** General "standard C" defines.
+**
+** These may be undone later, to cope with systems that claim to
+** be Standard C but aren't. Gcc is the biggest offender -- it
+** doesn't realize that the library is part of the language.
+**
+** Life would be much easier if we could get rid of this sort
+** of bozo problems.
+*/
+
+# ifdef __STDC__
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# endif /* __STDC__ */
+
+/*
+** Assume you have standard calls; can be #undefed below if necessary.
+*/
+
+# ifndef HASLSTAT
+# define HASLSTAT 1 /* has lstat(2) call */
+# endif /* ! HASLSTAT */
+
+# ifndef HASNICE
+# define HASNICE 1 /* has nice(2) call */
+# endif /* ! HASNICE */
+
+# ifndef HASRRESVPORT
+# define HASRRESVPORT 1 /* has rrsevport(3) call */
+# endif /* ! HASRRESVPORT */
+
+/**********************************************************************
+** "Hard" compilation options.
+** #define these if they are available; comment them out otherwise.
+** These cannot be overridden from the Makefile, and should really not
+** be turned off unless absolutely necessary.
+**********************************************************************/
+
+#define LOG 1 /* enable logging -- don't turn off */
+
+/**********************************************************************
+** Operating system configuration.
+**
+** Unless you are porting to a new OS, you shouldn't have to
+** change these.
+**********************************************************************/
+
+/*
+** HP-UX -- tested for 8.07, 9.00, and 9.01.
+**
+** If V4FS is defined, compile for HP-UX 10.0.
+** 11.x support from Richard Allen <ra@hp.is>.
+*/
+
+# ifdef __hpux
+ /* common definitions for HP-UX 9.x and 10.x */
+# undef m_flags /* conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h on HP 300 */
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASSETRESGID 1 /* use setresgid(2) to set saved gid */
+# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
+# define seteuid(e) setresuid(-1, e, -1)
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# define LA_TYPE LA_HPUX
+# define SPT_TYPE SPT_PSTAT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define GIDSET_T gid_t
+# define LDA_USE_LOCKF 1
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
+# endif /* ! HASGETUSERSHELL */
+# ifdef HPUX10
+# define _PATH_SENDMAIL "/usr/sbin/sendmail"
+# define SMRSH_CMDDIR "/var/adm/sm.bin"
+# endif /* HPUX10 */
+# ifdef HPUX11
+# define HASFCHOWN 1 /* has fchown(2) */
+# ifndef BROKEN_RES_SEARCH
+# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
+# endif /* ! BROKEN_RES_SEARCH */
+# define SMRSH_CMDDIR "/var/adm/sm.bin"
+# define _PATH_SENDMAIL "/usr/sbin/sendmail"
+# else /* HPUX11 */
+# ifndef NOT_SENDMAIL
+# define syslog hard_syslog
+# endif /* ! NOT_SENDMAIL */
+# endif /* HPUX11 */
+# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
+
+# ifdef V4FS
+ /* HP-UX 10.x */
+# define _PATH_UNIX "/stand/vmunix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# ifndef IDENTPROTO
+# define IDENTPROTO 1 /* TCP/IP implementation fixed in 10.0 */
+# endif /* ! IDENTPROTO */
+# include <sys/mpctl.h> /* for mpctl() in get_num_procs_online() */
+# else /* V4FS */
+ /* HP-UX 9.x */
+# define _PATH_UNIX "/hp-ux"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# ifdef __STDC__
+extern void hard_syslog(int, char *, ...);
+# else /* __STDC__ */
+extern void hard_syslog();
+# endif /* __STDC__ */
+# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
+# endif /* V4FS */
+
+# endif /* __hpux */
+
+/*
+** IBM AIX 5.x
+*/
+
+# ifdef _AIX5
+# define _AIX4 40300
+# endif /* _AIX5 */
+
+/*
+** IBM AIX 4.x
+*/
+
+# ifdef _AIX4
+# define _AIX3 1 /* pull in AIX3 stuff */
+# define BSD4_4_SOCKADDR /* has sa_len */
+# define USESETEUID 1 /* seteuid(2) works */
+# define TZ_TYPE TZ_NAME /* use tzname[] vector */
+# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
+# if _AIX4 >= 40200
+# define HASSETREUID 1 /* setreuid(2) works as of AIX 4.2 */
+# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
+# endif /* _AIX4 >= 40200 */
+# if defined(_ILS_MACROS) /* IBM versions aren't side-effect clean */
+# undef isascii
+# define isascii(c) !(c & ~0177)
+# undef isdigit
+# define isdigit(__a) (_IS(__a,_ISDIGIT))
+# undef isspace
+# define isspace(__a) (_IS(__a,_ISSPACE))
+# endif /* defined(_ILS_MACROS) */
+# endif /* _AIX4 */
+
+
+/*
+** IBM AIX 3.x -- actually tested for 3.2.3
+*/
+
+# ifdef _AIX3
+# include <paths.h>
+# include <sys/machine.h> /* to get byte order */
+# include <sys/select.h>
+# define HASFCHOWN 1 /* has fchown(2) */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
+# define GIDSET_T gid_t
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# define LA_TYPE LA_INT
+# define FSHIFT 16
+# define LA_AVENRUN "avenrun"
+# if !defined(_AIX4) || _AIX4 < 40300
+# ifndef __BIT_TYPES_DEFINED__
+# define SM_INT32 int
+# endif /* __BIT_TYPES_DEFINED__ */
+# endif /* !defined(_AIX4) || _AIX4 < 40300 */
+# if !defined(_AIX4) || _AIX4 < 40200
+# define SM_CONF_SYSLOG 0
+# endif /* !defined(_AIX4) || _AIX4 < 40200 */
+# endif /* _AIX3 */
+
+
+/*
+** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773
+**
+** From Mark Whetzel <markw@wg.waii.com>.
+*/
+
+# ifdef AIX /* AIX/RT compiler pre-defines this */
+# include <paths.h>
+# include <sys/time.h> /* AIX/RT resource.h does NOT include this */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define HASFCHMOD 0 /* does not have fchmod(2) syscall */
+# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */
+# define HASSETVBUF 1 /* use setvbuf(2) system call */
+# define HASSETRLIMIT 0 /* does not have setrlimit call */
+# define HASFLOCK 0 /* does not have flock call - use fcntl */
+# define HASULIMIT 1 /* use ulimit instead of setrlimit call */
+# define SM_CONF_GETOPT 0 /* Do we need theirs or ours */
+# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */
+# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
+# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */
+# define GIDSET_T int
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */
+# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
+# define ARBPTR_T int *
+# define void int
+typedef int pid_t;
+/* RTisms for BSD compatibility, specified in the Makefile
+ define BSD 1
+ define BSD_INCLUDES 1
+ define BSD_REMAP_SIGNAL_TO_SIGVEC
+ RTisms needed above */
+/* make this sendmail in a completely different place */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/local/newmail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* AIX */
+
+# if defined(_AIX)
+# define LDA_USE_LOCKF 1
+# define LDA_USE_SETEUID 1
+# endif /* defined(_AIX) */
+
+/*
+** Silicon Graphics IRIX
+**
+** Compiles on 4.0.1.
+**
+** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0).
+** Use IRIX5 instead of IRIX for IRIX 5.x.
+**
+** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>.
+** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
+*/
+
+# ifdef IRIX
+# define SYSTEM5 1 /* this is a System-V derived system */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# define setpgid BSDsetpgrp
+# define GIDSET_T gid_t
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define SYSLOG_BUFSIZE 512
+# ifdef IRIX6
+# define STAT64 1
+# define QUAD_T unsigned long long
+# define LA_TYPE LA_IRIX6 /* figure out at run time */
+# define SAFENFSPATHCONF 0 /* pathconf(2) lies on NFS filesystems */
+# else /* IRIX6 */
+# define LA_TYPE LA_INT
+
+# ifdef IRIX64
+# define STAT64 1
+# define QUAD_T unsigned long long
+# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */
+# else /* IRIX64 */
+# define STAT64 0
+# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
+# endif /* IRIX64 */
+# endif /* IRIX6 */
+# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
+# include <sys/cdefs.h>
+# include <paths.h>
+# define ARGV_T char *const *
+# define HASFCHOWN 1 /* has fchown(2) */
+# define HASSETRLIMIT 1 /* has setrlimit(2) syscall */
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */
+# define HASSTRERROR 1 /* has strerror(3) */
+# else /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+# define ARGV_T const char **
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+# endif /* IRIX */
+
+
+/*
+** SunOS and Solaris
+**
+** Tested on SunOS 4.1.x (a.k.a. Solaris 1.1.x) and
+** Solaris 2.4 (a.k.a. SunOS 5.4).
+*/
+
+# if defined(sun) && !defined(BSD)
+
+# include <sys/time.h>
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
+# ifndef HASFCHOWN
+# define HASFCHOWN 1 /* fchown(2) */
+# endif /* ! HASFCHOWN */
+
+# ifdef __svr4__
+# define LDA_USE_LOCKF 1
+# define LDA_USE_SETEUID 1
+# define _PATH_MAILDIR "/var/mail"
+# endif /* __svr4__ */
+
+# ifdef SOLARIS_2_3
+# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */
+# endif /* SOLARIS_2_3 */
+
+# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4))
+# define SOLARIS 1 /* unknown Solaris version */
+# endif /* defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4)) */
+
+# ifdef SOLARIS
+ /* Solaris 2.x (a.k.a. SunOS 5.x) */
+# ifndef __svr4__
+# define __svr4__ /* use all System V Release 4 defines below */
+# endif /* ! __svr4__ */
+# define GIDSET_T gid_t
+# define USE_SA_SIGACTION 1 /* use sa_sigaction field */
+# define BROKEN_PTHREAD_SLEEP 1 /* sleep after pthread_create() fails */
+# define HASSTRERROR 1 /* has strerror(3) */
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/dev/ksyms"
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# ifndef _PATH_HOSTS
+# define _PATH_HOSTS "/etc/inet/hosts"
+# endif /* ! _PATH_HOSTS */
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
+# endif /* ! SYSLOG_BUFSIZE */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TZNAME
+# endif /* ! TZ_TYPE */
+# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
+# define USESETEUID 1 /* seteuid works as of 2.3 */
+# define LDA_CONTENTLENGTH 1 /* Needs the Content-Length header */
+# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
+# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205)
+# define HASSETREUID 1 /* setreuid works as of 2.5 */
+# define HASSETREGID 1 /* use setregid(2) to set saved gid */
+# if SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700)
+# ifndef LA_TYPE
+# define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */
+# endif /* ! LA_TYPE */
+# ifndef RANDOMSHIFT /* random() doesn't work well (sometimes) */
+# define RANDOMSHIFT 8
+# endif /* ! RANDOMSHIFT */
+# endif /* SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700) */
+# else /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
+# ifndef HASRANDOM
+# define HASRANDOM 0 /* doesn't have random(3) */
+# endif /* ! HASRANDOM */
+# endif /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
+# if (SOLARIS > 10000 && SOLARIS < 20600) || SOLARIS < 206
+# define SM_INT32 int /* 32bit integer */
+# endif /* (SOLARIS > 10000 && SOLARIS < 20600) || SOLARIS < 206 */
+# if SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207)
+# ifndef LA_TYPE
+# include <sys/loadavg.h>
+# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209)
+# include <sys/pset.h>
+# define LA_TYPE LA_PSET /* pset_getloadavg(3c) appears in 2.9 */
+# else /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */
+# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */
+# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */
+# endif /* ! LA_TYPE */
+# define HASGETUSERSHELL 1 /* getusershell(3c) bug fixed in 2.7 */
+# endif /* SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207) */
+# if SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208)
+# undef _PATH_SENDMAILPID /* tmpfs /var/run added in 2.8 */
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# define SMRSH_CMDDIR "/var/adm/sm.bin"
+# define SL_FUDGE 34 /* fudge offset for SyslogPrefixLen */
+# endif /* SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208) */
+# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209)
+# define HASURANDOMDEV 1 /* /dev/[u]random added in S9 */
+# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */
+# endif /* ! HASGETUSERSHELL */
+
+# else /* SOLARIS */
+ /* SunOS 4.0.3 or 4.1.x */
+# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
+# include <memory.h>
+# include <vfork.h>
+# ifdef __GNUC__
+# define strtoul strtol /* gcc library bogosity */
+# endif /* __GNUC__ */
+# define memmove(d, s, l) (bcopy((s), (d), (l)))
+# define atexit(f) on_exit((f), 0) /* ugly hack for SunOS */
+# define SM_INT32 int /* 32bit integer */
+# define SM_ALIGN_SIZE (sizeof(long))
+# define GIDSET_T int
+# define SM_CONF_SYSLOG 0
+
+# ifdef SUNOS403
+ /* special tweaking for SunOS 4.0.3 */
+# include <malloc.h>
+# define BSD4_3 1 /* 4.3 BSD-based */
+# define NEEDSTRSTR 1 /* need emulation of strstr(3) routine */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# undef WIFEXITED
+# undef WEXITSTATUS
+# undef HASUNAME
+# define setpgid setpgrp
+# define MODE_T int
+typedef int pid_t;
+extern char *getenv();
+
+# else /* SUNOS403 */
+ /* 4.1.x specifics */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+
+# endif /* SUNOS403 */
+# endif /* SOLARIS */
+
+# ifndef LA_TYPE
+# define LA_TYPE LA_INT
+# endif /* ! LA_TYPE */
+
+# endif /* defined(sun) && !defined(BSD) */
+
+/*
+** DG/UX
+**
+** Tested on 5.4.2 and 5.4.3. Use DGUX_5_4_2 to get the
+** older support.
+** 5.4.3 changes from Mark T. Robinson <mtr@ornl.gov>.
+*/
+
+# ifdef DGUX_5_4_2
+# define DGUX 1
+# endif /* DGUX_5_4_2 */
+
+# ifdef DGUX
+# define SYSTEM5 1
+# define LA_TYPE LA_DGUX
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# define SPT_TYPE SPT_NONE /* don't use setproctitle */
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define LDA_USE_LOCKF 1
+
+/* these include files must be included early on DG/UX */
+# include <netinet/in.h>
+# include <arpa/inet.h>
+
+/* compiler doesn't understand const? */
+# define const
+
+# ifdef DGUX_5_4_2
+# define inet_addr dgux_inet_addr
+extern long dgux_inet_addr();
+# endif /* DGUX_5_4_2 */
+# endif /* DGUX */
+
+
+/*
+** Digital Ultrix 4.2 - 4.5
+**
+** Apparently, fcntl locking is broken on 4.2A, in that locks are
+** not dropped when the process exits. This causes major problems,
+** so flock is the only alternative.
+*/
+
+# ifdef ultrix
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASFCHOWN 1 /* has fchown(2) syscall */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# ifndef BROKEN_RES_SEARCH
+# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
+# endif /* ! BROKEN_RES_SEARCH */
+# if !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621
+# define NEEDLOCAL_HOSTNAME_LENGTH 1 /* see sendmail/README */
+# endif /* !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621 */
+# ifdef vax
+# define LA_TYPE LA_FLOAT
+# else /* vax */
+# define LA_TYPE LA_INT
+# define LA_AVENRUN "avenrun"
+# endif /* vax */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* pre-4.4 TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# define SYSLOG_BUFSIZE 256
+# define SM_CONF_SYSLOG 0
+# endif /* ultrix */
+
+
+/*
+** OSF/1 for KSR.
+**
+** Contributed by Todd C. Miller <Todd.Miller@cs.colorado.edu>
+*/
+
+# ifdef __ksr__
+# define __osf__ 1 /* get OSF/1 defines below */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
+# endif /* ! TZ_TYPE */
+# endif /* __ksr__ */
+
+
+/*
+** OSF/1 for Intel Paragon.
+**
+** Contributed by Jeff A. Earickson <jeff@ssd.intel.com>
+** of Intel Scalable Systems Divison.
+*/
+
+# ifdef __PARAGON__
+# define __osf__ 1 /* get OSF/1 defines below */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
+# endif /* ! TZ_TYPE */
+# define GIDSET_T gid_t
+# define MAXNAMLEN NAME_MAX
+# endif /* __PARAGON__ */
+
+
+/*
+** Tru64 UNIX, formerly known as Digital UNIX, formerly known as DEC OSF/1
+**
+** Tested for 3.2 and 4.0.
+*/
+
+# ifdef __osf__
+# define HASUNAME 1 /* has uname(2) call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASFCHOWN 1 /* has fchown(2) syscall */
+# define HASSETLOGIN 1 /* has setlogin(2) */
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# define GIDSET_T gid_t
+# define SM_INT32 int /* 32bit integer */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define LA_TYPE LA_ALPHAOSF
+# define SFS_TYPE SFS_STATVFS /* use <sys/statvfs.h> statfs() impl */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* __osf__ */
+
+
+/*
+** NeXTstep
+*/
+
+# ifdef NeXT
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define NEEDPUTENV 2 /* need putenv(3) call; no setenv(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define UID_T int /* compiler gripes on uid_t */
+# define GID_T int /* ditto for gid_t */
+# define MODE_T int /* and mode_t */
+# define setpgid setpgrp
+# ifndef NOT_SENDMAIL
+# define sleep sleepX
+# endif /* ! NOT_SENDMAIL */
+# ifndef LA_TYPE
+# define LA_TYPE LA_MACH
+# endif /* ! LA_TYPE */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifdef _POSIX_SOURCE
+extern struct passwd *getpwent();
+# else /* _POSIX_SOURCE */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+typedef int pid_t;
+# undef WEXITSTATUS
+# undef WIFEXITED
+# undef WIFSTOPPED
+# undef WTERMSIG
+# endif /* _POSIX_SOURCE */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/sendmail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# define SM_INT32 int /* 32bit integer */
+
+# ifdef TCPWRAPPERS
+# ifndef HASUNSETENV
+# define HASUNSETENV 1
+# endif /* ! HASUNSETENV */
+# undef NEEDPUTENV
+# endif /* TCPWRAPPERS */
+# ifndef __APPLE__
+# include <libc.h>
+# ifndef S_IRUSR
+# define S_IRUSR S_IREAD
+# endif /* ! S_IRUSR */
+# ifndef S_IWUSR
+# define S_IWUSR S_IWRITE
+# endif /* ! S_IWUSR */
+# define _PATH_MAILDIR "/usr/spool/mail"
+# endif /* ! __APPLE__ */
+# ifndef isascii
+# define isascii(c) ((unsigned)(c) <= 0177)
+# endif /* ! isascii */
+# endif /* NeXT */
+
+/*
+** Apple Rhapsody
+** Contributed by Wilfredo Sanchez <wsanchez@apple.com>
+**
+** Also used for Apple Darwin support.
+*/
+
+# if defined(DARWIN)
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASFLOCK 1 /* has flock(2) syscall */
+# define HASUNAME 1 /* has uname(2) syscall */
+# define HASUNSETENV 1
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+# define HASINITGROUPS 1
+# define HASSETVBUF 1
+# define HASSETREUID 0
+# define HASSETEUID 1
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASLSTAT 1
+# define HASSETRLIMIT 1
+# define HASWAITPID 1
+# define HASSTRERROR 1 /* has strerror(3) */
+# define HASGETDTABLESIZE 1
+# define HASGETUSERSHELL 1
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define BSD4_4_SOCKADDR /* has sa_len */
+# define NETLINK 1 /* supports AF_LINK */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# define GIDSET_T gid_t
+# define LA_TYPE LA_SUBR /* use getloadavg(3) */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# define SPT_TYPE SPT_PSSTRINGS
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# endif /* defined(DARWIN) */
+
+
+/*
+** 4.4 BSD
+**
+** See also BSD defines.
+*/
+
+# if defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__)
+# include <paths.h>
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASFCHOWN 1 /* has fchown(2) syscall */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define BSD4_4_SOCKADDR /* has sa_len */
+# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
+# define NETLINK 1 /* supports AF_LINK */
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif /* ! LA_TYPE */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# define SPT_TYPE SPT_PSSTRINGS /* use PS_STRINGS pointer */
+# endif /* defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__) */
+
+
+/*
+** BSD/OS (was BSD/386) (all versions)
+** From Tony Sanders, BSDI
+*/
+
+# ifdef __bsdi__
+# include <paths.h>
+# define HASUNSETENV 1 /* has the unsetenv(3) call */
+# define HASSETREUID 0 /* BSD-OS has broken setreuid(2) emulation */
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASSETLOGIN 1 /* has setlogin(2) */
+# define HASUNAME 1 /* has uname(2) syscall */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define BSD4_4_SOCKADDR /* has sa_len */
+# define NETLINK 1 /* supports AF_LINK */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif /* ! LA_TYPE */
+# define GIDSET_T gid_t
+# define QUAD_T quad_t
+# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312
+ /* version 1.1 or later */
+# undef SPT_TYPE
+# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
+# else /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
+ /* version 1.0 or earlier */
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
+# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 /* on 3.x */
+# define HASSETUSERCONTEXT 1 /* has setusercontext */
+# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 */
+# if defined(_BSDI_VERSION) && _BSDI_VERSION <= 199701 /* 3.1 and earlier */
+# define MODE_T int /* va_arg() can't handle less than int */
+# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION <= 199701 */
+# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199910 /* on 4.x */
+# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
+# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199910 */
+# endif /* __bsdi__ */
+
+
+/*
+** QNX 4.2x
+** Contributed by Glen McCready <glen@qnx.com>.
+**
+** Should work with all versions of QNX.
+*/
+
+# if defined(__QNX__)
+# include <unix.h>
+# include <sys/select.h>
+# undef NGROUPS_MAX
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define HASFLOCK 0
+# undef HASINITGROUPS /* has initgroups(3) call */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# define TZ_TYPE TZ_TMNAME /* use tmname variable */
+# define GIDSET_T gid_t
+# define LA_TYPE LA_ZERO
+# define SFS_TYPE SFS_NONE
+# define SPT_TYPE SPT_REUSEARGV
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# define HASGETUSERSHELL 0
+# define E_PSEUDOBASE 512
+# define _FILE_H_INCLUDED
+# endif /* defined(__QNX__) */
+
+
+/*
+** FreeBSD / NetBSD / OpenBSD (all architectures, all versions)
+**
+** 4.3BSD clone, closer to 4.4BSD for FreeBSD 1.x and NetBSD 0.9x
+** 4.4BSD-Lite based for FreeBSD 2.x and NetBSD 1.x
+**
+** See also BSD defines.
+*/
+
+# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+# include <paths.h>
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASFCHOWN 1 /* fchown(2) */
+# define HASUNAME 1 /* has uname(2) syscall */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
+# include <sys/cdefs.h>
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define BSD4_4_SOCKADDR /* has sa_len */
+# define NETLINK 1 /* supports AF_LINK */
+# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
+# define GIDSET_T gid_t
+# define QUAD_T unsigned long long
+# ifndef LA_TYPE
+# define LA_TYPE LA_SUBR
+# endif /* ! LA_TYPE */
+# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
+# if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1)
+# undef SPT_TYPE
+# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
+# endif /* defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) */
+# if defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3))
+# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
+# endif /* defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3)) */
+# if defined(__FreeBSD__)
+# define HASSETLOGIN 1 /* has setlogin(2) */
+# if __FreeBSD_version >= 227001
+# define HASSRANDOMDEV 1 /* has srandomdev(3) */
+# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
+# endif /* __FreeBSD_version >= 227001 */
+# undef SPT_TYPE
+# if __FreeBSD__ >= 2
+# include <osreldate.h>
+# if __FreeBSD_version >= 199512 /* 2.2-current when it appeared */
+# include <libutil.h>
+# define SPT_TYPE SPT_BUILTIN
+# endif /* __FreeBSD_version >= 199512 */
+# if __FreeBSD_version >= 222000 /* 2.2.2-release and later */
+# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
+# endif /* __FreeBSD_version >= 222000 */
+# if __FreeBSD_version >= 330000 /* 3.3.0-release and later */
+# define SMRSH_CMDDIR "/usr/libexec/sm.bin"
+# define SMRSH_PATH "/bin:/usr/bin"
+# endif /* __FreeBSD_version >= 330000 */
+# define USESYSCTL 1 /* use sysctl(3) for getting ncpus */
+# include <sys/sysctl.h>
+# endif /* __FreeBSD__ >= 2 */
+# ifndef SPT_TYPE
+# define SPT_TYPE SPT_REUSEARGV
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# endif /* ! SPT_TYPE */
+# endif /* defined(__FreeBSD__) */
+# if defined(__OpenBSD__)
+# undef SPT_TYPE
+# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
+# define HASSETLOGIN 1 /* has setlogin(2) */
+# define HASSETREUID 0 /* OpenBSD has broken setreuid(2) emulation */
+# define HASSETEGID 1 /* use setegid(2) to set saved gid */
+# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
+# if OpenBSD >= 200006
+# define HASSRANDOMDEV 1 /* has srandomdev(3) */
+# endif /* OpenBSD >= 200006 */
+# if OpenBSD >= 200012
+# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
+# endif /* OpenBSD >= 200012 */
+# endif /* defined(__OpenBSD__) */
+# endif /* defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) */
+
+
+/*
+** Mach386
+**
+** For mt Xinu's Mach386 system.
+*/
+
+# if defined(MACH) && defined(i386) && !defined(__GNU__)
+# define MACH386 1
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define NEEDSTRTOL 1 /* need the strtol() function */
+# define setpgid setpgrp
+# ifndef LA_TYPE
+# define LA_TYPE LA_FLOAT
+# endif /* ! LA_TYPE */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# undef HASSETVBUF /* don't actually have setvbuf(3) */
+# undef WEXITSTATUS
+# undef WIFEXITED
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* defined(MACH) && defined(i386) && !defined(__GNU__) */
+
+
+
+/*
+** GNU OS (hurd)
+** Largely BSD & posix compatible.
+** Port contributed by Miles Bader <miles@gnu.ai.mit.edu>.
+** Updated by Mark Kettenis <kettenis@wins.uva.nl>.
+*/
+
+# if defined(__GNU__) && !defined(NeXT)
+# include <paths.h>
+# define HASFCHMOD 1 /* has fchmod(2) call */
+# define HASFCHOWN 1 /* has fchown(2) call */
+# define HASUNAME 1 /* has uname(2) call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define GIDSET_T gid_t
+# define SOCKADDR_LEN_T socklen_t
+# define SOCKOPT_LEN_T socklen_t
+# if (__GLIBC__ == 2 && __GLIBC_MINOR__ > 1) || __GLIBC__ > 2
+# define LA_TYPE LA_SUBR
+# else /* (__GLIBC__ == 2 && __GLIBC_MINOR__ > 1) || __GLIBC__ > 2 */
+# define LA_TYPE LA_MACH
+ /* GNU uses mach[34], which renames some rpcs from mach2.x. */
+# define host_self mach_host_self
+# endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ > 1) || __GLIBC__ > 2 */
+# define SFS_TYPE SFS_STATFS
+# define SPT_TYPE SPT_CHANGEARGV
+# define ERRLIST_PREDEFINED 1 /* don't declare sys_errlist */
+# define BSD4_4_SOCKADDR 1 /* has sa_len */
+# define SIOCGIFCONF_IS_BROKEN 1 /* SIOCGFCONF doesn't work */
+# define HAS_IN_H 1 /* GNU has netinet/in.h. */
+/* GNU has no MAXPATHLEN; ideally the code should be changed to not use it. */
+# define MAXPATHLEN 2048
+# endif /* defined(__GNU__) && !defined(NeXT) */
+
+/*
+** 4.3 BSD -- this is for very old systems
+**
+** Should work for mt Xinu MORE/BSD and Mips UMIPS-BSD 2.1.
+**
+** You'll also have to install a new resolver library.
+** I don't guarantee that support for this environment is complete.
+*/
+
+# if defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd)
+# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define ARBPTR_T char *
+# define setpgid setpgrp
+# ifndef LA_TYPE
+# define LA_TYPE LA_FLOAT
+# endif /* ! LA_TYPE */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# undef WEXITSTATUS
+# undef WIFEXITED
+typedef short pid_t;
+# endif /* defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) */
+
+
+/*
+** SCO Unix
+**
+** This includes three parts:
+**
+** The first is for SCO OpenServer 5.
+** (Contributed by Keith Reynolds <keithr@sco.COM>).
+**
+** SCO OpenServer 5 has a compiler version number macro,
+** which we can use to figure out what version we're on.
+** This may have to change in future releases.
+**
+** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0.
+** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>).
+**
+** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier.
+*/
+
+/* SCO OpenServer 5 */
+# if _SCO_DS >= 1
+# include <paths.h>
+# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM returns bogus value */
+# define HASFCHMOD 1 /* has fchmod(2) call */
+# define HASFCHOWN 1 /* has fchown(2) call */
+# define HASSETRLIMIT 1 /* has setrlimit(2) call */
+# define USESETEUID 1 /* has seteuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
+# define RLIMIT_NEEDS_SYS_TIME_H 1
+# define LDA_USE_LOCKF 1
+# ifndef LA_TYPE
+# define LA_TYPE LA_DEVSHORT
+# endif /* ! LA_TYPE */
+# define _PATH_AVENRUN "/dev/table/avenrun"
+# ifndef _SCO_unix_4_2
+# define _SCO_unix_4_2
+# else /* ! _SCO_unix_4_2 */
+# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
+# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
+# endif /* ! _SCO_unix_4_2 */
+# endif /* _SCO_DS >= 1 */
+
+/* SCO UNIX 3.2v4.2/Open Desktop 3.0 */
+# ifdef _SCO_unix_4_2
+# define _SCO_unix_
+# define HASSETREUID 1 /* has setreuid(2) call */
+# endif /* _SCO_unix_4_2 */
+
+/* SCO UNIX 3.2v4.0 Open Desktop 2.0 and earlier */
+# ifdef _SCO_unix_
+# include <sys/stream.h> /* needed for IP_SRCROUTE */
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define NOFTRUNCATE 0 /* has (simulated) ftruncate call */
+# ifndef USE_SIGLONGJMP
+# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
+# endif /* ! USE_SIGLONGJMP */
+# define MAXPATHLEN PATHSIZE
+# define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define SPT_TYPE SPT_SCO /* write kernel u. area */
+# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */
+# define UID_T uid_t
+# define GID_T gid_t
+# define GIDSET_T gid_t
+# define _PATH_UNIX "/unix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+
+/* stuff fixed in later releases */
+# ifndef _SCO_unix_4_2
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# endif /* ! _SCO_unix_4_2 */
+
+# ifndef _SCO_DS
+# define ftruncate chsize /* use chsize(2) to emulate ftruncate */
+# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
+# define NETUNIX 0 /* no unix domain socket support */
+# define LA_TYPE LA_SHORT
+# endif /* ! _SCO_DS */
+
+# endif /* _SCO_unix_ */
+
+/*
+** ISC (SunSoft) Unix.
+**
+** Contributed by J.J. Bailey <jjb@jagware.bcc.com>
+*/
+
+# ifdef ISC_UNIX
+# include <net/errno.h>
+# include <sys/stream.h> /* needed for IP_SRCROUTE */
+# include <sys/bsdtypes.h>
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
+# define NETUNIX 0 /* no unix domain socket support */
+# define MAXPATHLEN 1024
+# define LA_TYPE LA_SHORT
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define _PATH_UNIX "/unix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* ISC_UNIX */
+
+
+/*
+** Altos System V (5.3.1)
+** Contributed by Tim Rice <tim@trr.metro.net>.
+*/
+
+# ifdef ALTOS_SYSTEM_V
+# include <sys/stream.h>
+# include <limits.h>
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define NEEDFSYNC 1 /* no fsync(2) in system library */
+# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
+# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
+# define MAXPATHLEN PATH_MAX
+# define LA_TYPE LA_SHORT
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
+# define NETUNIX 0 /* no unix domain socket support */
+# undef WIFEXITED
+# undef WEXITSTATUS
+# define strtoul strtol /* gcc library bogosity */
+
+typedef unsigned short uid_t;
+typedef unsigned short gid_t;
+typedef short pid_t;
+typedef unsigned long mode_t;
+
+/* some stuff that should have been in the include files */
+extern char *malloc();
+extern struct passwd *getpwent();
+extern struct passwd *getpwnam();
+extern struct passwd *getpwuid();
+extern char *getenv();
+extern struct group *getgrgid();
+extern struct group *getgrnam();
+
+# endif /* ALTOS_SYSTEM_V */
+
+
+/*
+** ConvexOS 11.0 and later
+**
+** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this
+** works on 9.1 as well.
+**
+** ConvexOS 11.5 and later, should work on 11.0 as defined.
+** For pre-ConvexOOS 11.0, define SM_CONF_GETOPT=0, undef IDENTPROTO
+**
+** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp.
+** (now the CONVEX Technologies Center of Hewlett Packard)
+*/
+
+# ifdef _CONVEX_SOURCE
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */
+# define HASINITGROUPS 1 /* has initgroups(3) */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETSID 1 /* has POSIX setsid(2) call */
+# define HASUNSETENV 1 /* has unsetenv(3) */
+# define HASFLOCK 1 /* has flock(2) */
+# define HASSETRLIMIT 1 /* has setrlimit(2) */
+# define HASSETREUID 1 /* has setreuid(2) */
+# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */
+# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */
+# define SM_CONF_GETOPT 1 /* need a replacement for getopt(3) */
+# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
+# define LA_TYPE LA_FLOAT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef S_IREAD
+# define S_IREAD _S_IREAD
+# define S_IWRITE _S_IWRITE
+# define S_IEXEC _S_IEXEC
+# define S_IFMT _S_IFMT
+# define S_IFCHR _S_IFCHR
+# define S_IFBLK _S_IFBLK
+# endif /* ! S_IREAD */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TIMEZONE
+# endif /* ! TZ_TYPE */
+# ifndef IDENTPROTO
+# define IDENTPROTO 1
+# endif /* ! IDENTPROTO */
+# ifndef SHARE_V1
+# define SHARE_V1 1 /* version 1 of the fair share scheduler */
+# endif /* ! SHARE_V1 */
+# if !defined(__GNUC__ )
+# define UID_T int /* GNUC gets it right, ConvexC botches */
+# define GID_T int /* GNUC gets it right, ConvexC botches */
+# endif /* !defined(__GNUC__ ) */
+# if SECUREWARE
+# define FORK fork /* SecureWare wants the real fork! */
+# else /* SECUREWARE */
+# define FORK vfork /* the rest of the OS versions don't care */
+# endif /* SECUREWARE */
+# endif /* _CONVEX_SOURCE */
+
+
+/*
+** RISC/os 4.52
+**
+** Gives a ton of warning messages, but otherwise compiles.
+*/
+
+# ifdef RISCOS
+
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define NEEDPUTENV 1 /* need putenv(3) call */
+# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define LA_TYPE LA_INT
+# define LA_AVENRUN "avenrun"
+# define _PATH_UNIX "/unix"
+# undef WIFEXITED
+
+# define setpgid setpgrp
+
+typedef int pid_t;
+# define SIGFUNC_DEFINED
+# define SIGFUNC_RETURN (0)
+# define SIGFUNC_DECL int
+typedef int (*sigfunc_t)();
+extern char *getenv();
+extern void *malloc();
+
+/* added for RISC/os 4.01...which is dumber than 4.50 */
+# ifdef RISCOS_4_0
+# ifndef ARBPTR_T
+# define ARBPTR_T char *
+# endif /* ! ARBPTR_T */
+# undef HASFLOCK
+# define HASFLOCK 0
+# endif /* RISCOS_4_0 */
+
+# include <sys/time.h>
+
+# endif /* RISCOS */
+
+
+/*
+** Linux 0.99pl10 and above...
+**
+** Thanks to, in reverse order of contact:
+**
+** John Kennedy <warlock@csuchico.edu>
+** Andrew Pam <avatar@aus.xanadu.com>
+** Florian La Roche <rzsfl@rz.uni-sb.de>
+** Karl London <karl@borg.demon.co.uk>
+**
+** Last compiled against: [07/21/98 @ 11:47:34 AM (Tuesday)]
+** sendmail 8.9.1 bind-8.1.2 db-2.4.14
+** gcc-2.8.1 glibc-2.0.94 linux-2.1.109
+**
+** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style
+** file locking is no longer allowed. In particular, make sure
+** your DBM library and sendmail are both using either flock(2)
+** *or* fcntl(2) file locking, but not both.
+*/
+
+# ifdef __linux__
+# include <linux/version.h>
+# if !defined(KERNEL_VERSION) /* not defined in 2.0.x kernel series */
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+# endif /* !defined(KERNEL_VERSION) */
+# define BSD 1 /* include BSD defines */
+# define HASSETREGID 1 /* use setregid(2) to set saved gid */
+# ifndef REQUIRES_DIR_FSYNC
+# define REQUIRES_DIR_FSYNC 1 /* requires fsync() on directory */
+# endif /* REQUIRES_DIR_FSYNC */
+# ifndef USESETEUID
+# define USESETEUID 0 /* has it due to POSIX, but doesn't work */
+# endif /* USESETEUID */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASUNSETENV 1 /* has unsetenv(3) call */
+# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
+# define GIDSET_T gid_t /* from <linux/types.h> */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */
+# endif /* HASGETUSERSHELL */
+# ifndef IP_SRCROUTE
+# define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */
+# endif /* ! IP_SRCROUTE */
+# ifndef HAS_IN_H
+# define HAS_IN_H 1 /* use netinet/in.h */
+# endif /* ! HAS_IN_H */
+# ifndef USE_SIGLONGJMP
+# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
+# endif /* ! USE_SIGLONGJMP */
+# ifndef HASFLOCK
+# if LINUX_VERSION_CODE < 66399
+# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */
+# else /* LINUX_VERSION_CODE < 66399 */
+# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */
+# endif /* LINUX_VERSION_CODE < 66399 */
+# endif /* ! HASFLOCK */
+# ifndef LA_TYPE
+# define LA_TYPE LA_PROCSTR
+# endif /* ! LA_TYPE */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,0))
+# ifndef HASURANDOMDEV
+# define HASURANDOMDEV 1 /* 2.0 (at least) has linux/drivers/char/random.c */
+# endif /* ! HASURANDOMDEV */
+# endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,0)) */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_NONE /* no standard for Linux */
+# endif /* ! TZ_TYPE */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# include <sys/sysmacros.h>
+# undef atol /* wounded in <stdlib.h> */
+# if NETINET6
+ /*
+ ** Linux doesn't have a good way to tell userland what interfaces are
+ ** IPv6-capable. Therefore, the BIND resolver can not determine if there
+ ** are IPv6 interfaces to honor AI_ADDRCONFIG. Unfortunately, it assumes
+ ** that none are present. (Excuse the macro name ADDRCONFIG_IS_BROKEN.)
+ */
+# define ADDRCONFIG_IS_BROKEN 1
+
+ /*
+ ** Indirectly included from glibc's <feature.h>. IPv6 support is native
+ ** in 2.1 and later, but the APIs appear before the functions.
+ */
+# if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+# define HASSTRERROR 1 /* has strerror(3) */
+# define GLIBC_VERSION ((__GLIBC__ << 8) + __GLIBC_MINOR__)
+# if (GLIBC_VERSION >= 0x201)
+# undef IPPROTO_ICMPV6 /* linux #defines, glibc enums */
+# else /* (GLIBC_VERSION >= 0x201) */
+# include <linux/in6.h> /* IPv6 support */
+# endif /* (GLIBC_VERSION >= 0x201) */
+# if (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE))
+ /* Have APIs in <netdb.h>, but no support in glibc */
+# define NEEDSGETIPNODE 1
+# endif /* (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE)) */
+# undef GLIBC_VERSION
+# endif /* defined(__GLIBC__) && defined(__GLIBC_MINOR__) */
+# endif /* NETINET6 */
+# ifndef HASFCHOWN
+# define HASFCHOWN 1 /* fchown(2) */
+# endif /* ! HASFCHOWN */
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) && !defined(HASFCHMOD)
+# define HASFCHMOD 1 /* fchmod(2) */
+# endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) && !defined(HASFCHMOD) */
+# endif /* __linux__ */
+
+
+/*
+** DELL SVR4 Issue 2.2, and others
+** From Kimmo Suominen <kim@grendel.lut.fi>
+**
+** It's on #ifdef DELL_SVR4 because Solaris also gets __svr4__
+** defined, and the definitions conflict.
+**
+** Peter Wemm <peter@perth.DIALix.oz.au> claims that the setreuid
+** trick works on DELL 2.2 (SVR4.0/386 version 4.0) and ESIX 4.0.3A
+** (SVR4.0/386 version 3.0).
+*/
+
+# ifdef DELL_SVR4
+ /* no changes necessary */
+ /* see general __svr4__ defines below */
+# endif /* DELL_SVR4 */
+
+
+/*
+** Apple A/UX 3.0
+*/
+
+# ifdef _AUX_SOURCE
+# include <sys/sysmacros.h>
+# define BSD /* has BSD routines */
+# define HASSETRLIMIT 0 /* ... but not setrlimit(2) */
+# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
+# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASSETVBUF 1 /* has setvbuf(3) in libc */
+# define HASSTRERROR 1 /* has strerror(3) */
+# define SIGFUNC_DEFINED /* sigfunc_t already defined */
+# define SIGFUNC_RETURN /* POSIX-mode */
+# define SIGFUNC_DECL void /* POSIX-mode */
+# define ERRLIST_PREDEFINED 1
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# ifndef LA_TYPE
+# define LA_TYPE LA_INT
+# define FSHIFT 16
+# endif /* ! LA_TYPE */
+# define LA_AVENRUN "avenrun"
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define TZ_TYPE TZ_TZNAME
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/unix" /* should be in <paths.h> */
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# undef WIFEXITED
+# undef WEXITSTATUS
+# endif /* _AUX_SOURCE */
+
+
+/*
+** Encore UMAX V
+**
+** Not extensively tested.
+*/
+
+# ifdef UMAXV
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define MAXPATHLEN PATH_MAX
+extern struct passwd *getpwent(), *getpwnam(), *getpwuid();
+extern struct group *getgrent(), *getgrnam(), *getgrgid();
+# undef WIFEXITED
+# undef WEXITSTATUS
+# endif /* UMAXV */
+
+
+/*
+** Stardent Titan 3000 running TitanOS 4.2.
+**
+** Must be compiled in "cc -43" mode.
+**
+** From Kate Hedstrom <kate@ahab.rutgers.edu>.
+**
+** Note the tweaking below after the BSD defines are set.
+*/
+
+# ifdef titan
+# define setpgid setpgrp
+typedef int pid_t;
+# undef WIFEXITED
+# undef WEXITSTATUS
+# endif /* titan */
+
+
+/*
+** Sequent DYNIX 3.2.0
+**
+** From Jim Davis <jdavis@cs.arizona.edu>.
+*/
+
+# ifdef sequent
+
+# define BSD 1
+# define HASUNSETENV 1
+# define BSD4_3 1 /* to get signal() in conf.c */
+# define WAITUNION 1
+# define LA_TYPE LA_FLOAT
+# ifdef _POSIX_VERSION
+# undef _POSIX_VERSION /* set in <unistd.h> */
+# endif /* _POSIX_VERSION */
+# undef HASSETVBUF /* don't actually have setvbuf(3) */
+# define setpgid setpgrp
+
+/* Have to redefine WIFEXITED to take an int, to work with waitfor() */
+# undef WIFEXITED
+# define WIFEXITED(s) (((union wait*)&(s))->w_stopval != WSTOPPED && \
+ ((union wait*)&(s))->w_termsig == 0)
+# define WEXITSTATUS(s) (((union wait*)&(s))->w_retcode)
+typedef int pid_t;
+# define isgraph(c) (isprint(c) && (c != ' '))
+
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/dynix"
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# endif /* sequent */
+
+
+/*
+** Sequent DYNIX/ptx v2.0 (and higher)
+**
+** For DYNIX/ptx v1.x, undefine HASSETREUID.
+**
+** From Tim Wright <timw@sequent.com>.
+** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995,
+** for DYNIX/ptx 4.0.2.
+*/
+
+# ifdef _SEQUENT_
+# include <sys/stream.h>
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASSETSID 1 /* has POSIX setsid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define GIDSET_T gid_t
+# define LA_TYPE LA_INT
+# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
+# define SPT_TYPE SPT_NONE /* don't use setproctitle */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* _SEQUENT_ */
+
+
+/*
+** Cray Unicos
+**
+** Ported by David L. Kensiski, Sterling Sofware <kensiski@nas.nasa.gov>
+*/
+
+# ifdef UNICOS
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define MAXPATHLEN PATHSIZE
+# define LA_TYPE LA_ZERO
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# endif /* UNICOS */
+
+
+/*
+** Apollo DomainOS
+**
+** From Todd Martin <tmartint@tus.ssi1.com> & Don Lewis <gdonl@gv.ssi1.com>
+**
+** 15 Jan 1994; updated 2 Aug 1995
+**
+*/
+
+# ifdef apollo
+# define HASSETREUID 1 /* has setreuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(2) call */
+# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
+# define SPT_TYPE SPT_NONE /* don't use setproctitle */
+# define LA_TYPE LA_SUBR /* use getloadavg.c */
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define TZ_TYPE TZ_TZNAME
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# undef S_IFSOCK /* S_IFSOCK and S_IFIFO are the same */
+# undef S_IFIFO
+# define S_IFIFO 0010000
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# define RLIMIT_NEEDS_SYS_TIME_H 1
+# if defined(NGROUPS_MAX) && !NGROUPS_MAX
+# undef NGROUPS_MAX
+# endif /* defined(NGROUPS_MAX) && !NGROUPS_MAX */
+# endif /* apollo */
+
+/*
+** MPE-iX
+**
+** Requires MPE 6.0 or greater. See sendmail/README for more info.
+**
+** From Mark Bixby <mark_bixby@hp.com> or <mark@bixby.org>.
+*/
+
+# ifdef MPE
+
+# include <sys/sysmacros.h>
+# include <fcntl.h>
+
+/* Sendmail stuff */
+# define HASFCHOWN 0 /* lacks fchown() */
+# define HASGETUSERSHELL 0 /* lacks getusershell() */
+# ifdef HASNICE
+# undef HASNICE
+# endif /* HASNICE */
+# define HASNICE 0 /* lacks nice() */
+# define HASRANDOM 0 /* lacks random() */
+# ifdef HASRRESVPORT
+# undef HASRRESVPORT
+# endif /* HASRRESVPORT */
+# define HASRRESVPORT 0 /* lacks rresvport() */
+# define IP_SRCROUTE 0 /* lacks IP source routing fields */
+# ifdef MATCHGECOS
+# undef MATCHGECOS
+# endif /* MATCHGECOS */
+# define MATCHGECOS 0 /* lacks an initialized GECOS field */
+# define NEEDFSYNC 1 /* use sendmail's fsync() */
+# define NEEDLINK 1 /* use sendmail's link() */
+# define NOFTRUNCATE 1 /* lacks ftruncate() */
+# define SFS_TYPE SFS_NONE /* can't determine disk space */
+# define SM_CONF_SYSLOG 0 /* use sendmail decl of syslog() */
+# define USE_DOUBLE_FORK 0 /* don't fork an intermediate zombie */
+# define USE_ENVIRON 1 /* use environ instead of envp */
+
+/* Missing header stuff */
+# define AF_UNSPEC 0
+# define AF_MAX AF_INET
+# define IFF_LOOPBACK 0x8
+# define IN_LOOPBACKNET 127
+# define MAXNAMLEN NAME_MAX
+# define S_IEXEC S_IXUSR
+# define S_IREAD S_IRUSR
+# define S_IWRITE S_IWUSR
+
+/* Present header stuff that needs to be missing */
+# undef NGROUPS_MAX
+
+/* Shadow functions */
+# define bind sendmail_mpe_bind
+# define _exit sendmail_mpe__exit
+# define exit sendmail_mpe_exit
+# define fcntl sendmail_mpe_fcntl
+# define getegid sendmail_mpe_getegid
+# define geteuid sendmail_mpe_geteuid
+# define getpwnam sendmail_mpe_getpwnam
+# define getpwuid sendmail_mpe_getpwuid
+# define setgid sendmail_mpe_setgid
+# define setuid sendmail_mpe_setuid
+extern int sendmail_mpe_fcntl __P((int, int, ...));
+extern struct passwd * sendmail_mpe_getpwnam __P((const char *));
+extern struct passwd * sendmail_mpe_getpwuid __P((uid_t));
+# endif /* MPE */
+
+/*
+** System V Rel 5.x (a.k.a Unixware7 w/o BSD-Compatibility Libs ie. native)
+**
+** Contributed by Paul Gampe <paulg@apnic.net>
+*/
+
+# ifdef __svr5__
+# include <sys/mkdev.h>
+# define __svr4__
+# define SYS5SIGNALS 1
+# define HASFCHOWN 1 /* has fchown(2) call */
+# define HASSETSID 1
+# define HASSETREUID 1
+# define HASWAITPID 1
+# define HASGETDTABLESIZE 1
+# define GIDSET_T gid_t
+# define SOCKADDR_LEN_T size_t
+# define SOCKOPT_LEN_T size_t
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/stand/unix"
+# endif /* ! _PATH_UNIX */
+# define SPT_PADCHAR '\0' /* pad process title with nulls */
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024 /* unsure */
+# endif /* ! SYSLOG_BUFSIZE */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
+#if !defined(SM_SET_H_ERRNO) && defined(_REENTRANT)
+# define SM_SET_H_ERRNO(err) set_h_errno((err))
+#endif /* ! SM_SET_H_ERRNO && _REENTRANT */
+# endif /* __svr5__ */
+
+/* ###################################################################### */
+
+/*
+** UnixWare 2.x
+*/
+
+# ifdef UNIXWARE2
+# define UNIXWARE 1
+# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
+# endif /* UNIXWARE2 */
+
+
+/*
+** UnixWare 1.1.2.
+**
+** Updated by Petr Lampa <lampa@fee.vutbr.cz>.
+** From Evan Champion <evanc@spatial.synapse.org>.
+*/
+
+# ifdef UNIXWARE
+# include <sys/mkdev.h>
+# define SYSTEM5 1
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# define HASSETREUID 1
+# define HASSETSID 1
+# define HASINITGROUPS 1
+# define GIDSET_T gid_t
+# define SLEEP_T unsigned
+# define SFS_TYPE SFS_STATVFS
+# define LA_TYPE LA_ZERO
+# undef WIFEXITED
+# undef WEXITSTATUS
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/unix"
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# define SYSLOG_BUFSIZE 128
+# endif /* UNIXWARE */
+
+
+/*
+** Intergraph CLIX 3.1
+**
+** From Paul Southworth <pauls@locust.cic.net>
+*/
+
+# ifdef CLIX
+# define SYSTEM5 1 /* looks like System V */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# endif /* ! HASGETUSERSHELL */
+# define DEV_BSIZE 512 /* device block size not defined */
+# define GIDSET_T gid_t
+# undef LOG /* syslog not available */
+# define NEEDFSYNC 1 /* no fsync in system library */
+# define GETSHORT _getshort
+# endif /* CLIX */
+
+
+/*
+** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP
+**
+** From Kevin Darcy <kevin@tech.mis.cfc.com>.
+*/
+
+# ifdef NCR_MP_RAS2
+# include <sys/sockio.h>
+# define __svr4__
+# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
+# define SYSLOG_BUFSIZE 1024
+# define SPT_TYPE SPT_NONE
+# endif /* NCR_MP_RAS2 */
+
+
+/*
+** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP
+**
+** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
+*/
+
+# ifdef NCR_MP_RAS3
+# define __svr4__
+# define HASFCHOWN 1 /* has fchown(2) call */
+# define LDA_USE_LOCKF 1
+# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM has non-std interface */
+# define SO_REUSEADDR_IS_BROKEN 1 /* doesn't work if accept() fails */
+# define SYSLOG_BUFSIZE 1024
+# define SPT_TYPE SPT_NONE
+# define _PATH_MAILDIR "/var/mail"
+# ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE
+# define _XOPEN_SOURCE_EXTENDED 1
+# include <sys/resource.h>
+# undef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE_EXTENDED
+# endif /* ! _XOPEN_SOURCE */
+# endif /* NCR_MP_RAS3 */
+
+
+/*
+** Tandem NonStop-UX SVR4
+**
+** From Rick McCarty <mccarty@mpd.tandem.com>.
+*/
+
+# ifdef NonStop_UX_BXX
+# define __svr4__
+# endif /* NonStop_UX_BXX */
+
+
+/*
+** Hitachi 3050R/3050RX and 3500 Workstations running HI-UX/WE2.
+**
+** Tested for 1.04, 1.03
+** From Akihiro Hashimoto ("Hash") <hash@dominic.ipc.chiba-u.ac.jp>.
+**
+** Tested for 4.02, 6.10 and 7.10
+** From Motonori NAKAMURA <motonori@media.kyoto-u.ac.jp>.
+*/
+
+# if !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE))
+# define SYSTEM5 1 /* include all the System V defines */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define HASFCHMOD 1 /* has fchmod(2) syscall */
+# define setreuid(r, e) setresuid(r, e, -1)
+# define LA_TYPE LA_FLOAT
+# define SPT_TYPE SPT_PSTAT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifndef HASSETVBUF
+# define HASSETVBUF /* HI-UX has no setlinebuf */
+# endif /* ! HASSETVBUF */
+# ifndef GIDSET_T
+# define GIDSET_T gid_t
+# endif /* ! GIDSET_T */
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/HI-UX"
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
+# endif /* ! HASGETUSERSHELL */
+# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
+
+/*
+** avoid m_flags conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h
+** on HIUX 3050
+*/
+# undef m_flags
+
+# define SM_CONF_SYSLOG 0
+
+# endif /* !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE)) */
+
+
+/*
+** Amdahl UTS System V 2.1.5 (SVr3-based)
+**
+** From: Janet Jackson <janet@dialix.oz.au>.
+*/
+
+# ifdef _UTS
+# include <sys/sysmacros.h>
+# undef HASLSTAT /* has symlinks, but they cause problems */
+# define NEEDFSYNC 1 /* system fsync(2) fails on non-EFS filesys */
+# define SYS5SIGNALS 1 /* System V signal semantics */
+# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define HASINITGROUPS 1 /* has initgroups(3) function */
+# define HASSETVBUF 1 /* has setvbuf(3) function */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) function */
+# endif /* ! HASGETUSERSHELL */
+# define GIDSET_T gid_t /* type of 2nd arg to getgroups(2) isn't int */
+# define LA_TYPE LA_ZERO /* doesn't have load average */
+# define SFS_TYPE SFS_4ARGS /* use 4-arg statfs() */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define _PATH_UNIX "/unix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# endif /* _UTS */
+
+/*
+** Cray Computer Corporation's CSOS
+**
+** From Scott Bolte <scott@craycos.com>.
+*/
+
+# ifdef _CRAYCOM
+# define SYSTEM5 1 /* include all the System V defines */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define NEEDFSYNC 1 /* no fsync in system library */
+# define MAXPATHLEN PATHSIZE
+# define LA_TYPE LA_ZERO
+# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
+# define SFS_BAVAIL f_bfree /* alternate field name */
+# define _POSIX_CHOWN_RESTRICTED -1
+extern struct group *getgrent(), *getgrnam(), *getgrgid();
+# endif /* _CRAYCOM */
+
+
+/*
+** Sony NEWS-OS 4.2.1R and 6.0.3
+**
+** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
+*/
+
+# ifdef sony_news
+# ifndef __svr4
+ /* NEWS-OS 4.2.1R */
+# ifndef BSD
+# define BSD /* has BSD routines */
+# endif /* ! BSD */
+# define HASUNSETENV 1 /* has unsetenv(2) call */
+# undef HASSETVBUF /* don't actually have setvbuf(3) */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# define LA_TYPE LA_INT
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# define setpgid setpgrp
+# undef WIFEXITED
+# undef WEXITSTATUS
+# define MODE_T int /* system include files have no mode_t */
+typedef int pid_t;
+typedef int (*sigfunc_t)();
+# define SIGFUNC_DEFINED
+# define SIGFUNC_RETURN (0)
+# define SIGFUNC_DECL int
+
+# else /* ! __svr4 */
+ /* NEWS-OS 6.0.3 with /bin/cc */
+# ifndef __svr4__
+# define __svr4__ /* use all System V Release 4 defines below */
+# endif /* ! __svr4__ */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
+# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
+# ifndef SPT_TYPE
+# define SPT_TYPE SPT_SYSMIPS /* use sysmips() (OS 6.0.2 or later) */
+# endif /* ! SPT_TYPE */
+# define GIDSET_T gid_t
+# undef WIFEXITED
+# undef WEXITSTATUS
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 256
+# endif /* ! SYSLOG_BUFSIZE */
+# define _PATH_UNIX "/stand/unix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+
+# endif /* ! __svr4 */
+# endif /* sony_news */
+
+
+/*
+** Omron LUNA/UNIOS-B 3.0, LUNA2/Mach and LUNA88K Mach
+**
+** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
+*/
+
+# ifdef luna
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# define HASUNSETENV 1 /* has unsetenv(2) call */
+# define NEEDPUTENV 1 /* need putenv(3) call */
+# define SM_CONF_GETOPT 0 /* need a replacement for getopt(3) */
+# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
+# define WAITUNION 1 /* use "union wait" as wait argument type */
+# ifdef uniosb
+# include <sys/time.h>
+# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
+# define LA_TYPE LA_INT
+# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
+# endif /* uniosb */
+# ifdef luna2
+# define LA_TYPE LA_SUBR
+# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
+# endif /* luna2 */
+# ifdef luna88k
+# define LA_TYPE LA_INT
+# endif /* luna88k */
+# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
+# define setpgid setpgrp
+# undef WIFEXITED
+# undef WEXITSTATUS
+typedef int pid_t;
+typedef int (*sigfunc_t)();
+# define SIGFUNC_DEFINED
+# define SIGFUNC_RETURN (0)
+# define SIGFUNC_DECL int
+extern char *getenv();
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# endif /* luna */
+
+
+/*
+** NEC EWS-UX/V 4.2 (with /usr/ucb/cc)
+**
+** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
+*/
+
+# if defined(nec_ews_svr4) || defined(_nec_ews_svr4)
+# ifndef __svr4__
+# define __svr4__ /* use all System V Release 4 defines below */
+# endif /* ! __svr4__ */
+# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define LA_TYPE LA_READKSYM /* use MIOC_READSYM ioctl */
+# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
+# define GIDSET_T gid_t
+# undef WIFEXITED
+# undef WEXITSTATUS
+# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
+# endif /* ! SYSLOG_BUFSIZE */
+# endif /* defined(nec_ews_svr4) || defined(_nec_ews_svr4) */
+
+
+/*
+** Fujitsu/ICL UXP/DS (For the DS/90 Series)
+**
+** From Diego R. Lopez <drlopez@cica.es>.
+** Additional changes from Fumio Moriya and Toshiaki Nomura of the
+** Fujitsu Fresoftware group <dsfrsoft@oai6.yk.fujitsu.co.jp>.
+*/
+
+# ifdef __uxp__
+# include <arpa/nameser.h>
+# include <sys/sysmacros.h>
+# include <sys/mkdev.h>
+# define __svr4__
+# define HASGETUSERSHELL 0
+# define HASFLOCK 0
+# define _PATH_UNIX "/stand/unix"
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# endif /* __uxp__ */
+
+/*
+** Pyramid DC/OSx
+**
+** From Earle Ake <akee@wpdiss1.wpafb.af.mil>.
+*/
+
+# ifdef DCOSx
+# define GIDSET_T gid_t
+# ifndef IDENTPROTO
+# define IDENTPROTO 0 /* TCP/IP implementation is broken */
+# endif /* ! IDENTPROTO */
+# endif /* DCOSx */
+
+/*
+** Concurrent Computer Corporation Maxion
+**
+** From Donald R. Laster Jr. <laster@access.digex.net>.
+*/
+
+# ifdef __MAXION__
+
+# include <sys/stream.h>
+# define __svr4__ 1 /* SVR4.2MP */
+# define HASSETREUID 1 /* have setreuid(2) */
+# define HASLSTAT 1 /* have lstat(2) */
+# define HASSETRLIMIT 1 /* have setrlimit(2) */
+# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */
+# define HASGETUSERSHELL 1 /* have getusershell(3) */
+# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
+# define SLEEP_T unsigned
+# define SFS_TYPE SFS_STATVFS
+# define SFS_BAVAIL f_bavail
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */
+# endif /* ! SYSLOG_BUFSIZE */
+
+# undef WUNTRACED
+# undef WIFEXITED
+# undef WIFSIGNALED
+# undef WIFSTOPPED
+# undef WEXITSTATUS
+# undef WTERMSIG
+# undef WSTOPSIG
+
+# endif /* __MAXION__ */
+
+/*
+** Harris Nighthawk PowerUX (nh6000 box)
+**
+** Contributed by Bob Miorelli, Pratt & Whitney <miorelli@pweh.com>
+*/
+
+# ifdef _PowerUX
+# ifndef __svr4__
+# define __svr4__
+# endif /* ! __svr4__ */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# define SYSLOG_BUFSIZE 1024
+# define LA_TYPE LA_ZERO
+typedef struct msgb mblk_t;
+# undef offsetof /* avoid stddefs.h and sys/sysmacros.h conflict */
+# endif /* _PowerUX */
+
+/*
+** Siemens Nixdorf Informationssysteme AG SINIX
+**
+** Contributed by Gerald Rinske of Siemens Business Services VAS.
+*/
+# ifdef sinix
+# define HASRANDOM 0 /* has random(3) */
+# define SYSLOG_BUFSIZE 1024
+# define SM_INT32 int /* 32bit integer */
+# endif /* sinix */
+
+/*
+** CRAY T3E
+**
+** Contributed by Manu Mahonen <mailadm@csc.fi>
+** of Center for Scientific Computing.
+*/
+# ifdef _CRAY
+# define GET_IPOPT_DST(dst) *(struct in_addr *)&(dst)
+# define _PATH_MAILDIR "/usr/spool/mail"
+# if !defined(MAXPATHLEN)
+# define MAXPATHLEN PATHSIZE
+# endif /* !defined(MAXPATHLEN) */
+# endif /* _CRAY */
+
+/*
+** Motorola 922, MC88110, UNIX SYSTEM V/88 Release 4.0 Version 4.3
+**
+** Contributed by Sergey Rusanov <rsm@utfoms.udmnet.ru>
+*/
+
+# ifdef MOTO
+# define HASFCHMOD 1
+# define HASSETRLIMIT 0
+# define HASSETSID 1
+# define HASSETREUID 1
+# define HASULIMIT 1
+# define HASWAITPID 1
+# define HASGETDTABLESIZE 1
+# define HASGETUSERSHELL 1
+# define IP_SRCROUTE 0
+# define IDENTPROTO 0
+# define RES_DNSRCH_VARIABLE _res_dnsrch
+# define _PATH_UNIX "/unix"
+# define _PATH_VENDOR_CF "/etc/sendmail.cf"
+# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
+# endif /* MOTO */
+
+
+/**********************************************************************
+** End of Per-Operating System defines
+**********************************************************************/
+/**********************************************************************
+** More general defines
+**********************************************************************/
+
+/* general BSD defines */
+# ifdef BSD
+# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
+# ifndef HASSETREUID
+# define HASSETREUID 1 /* has setreuid(2) call */
+# endif /* ! HASSETREUID */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# ifndef IP_SRCROUTE
+# define IP_SRCROUTE 1 /* can check IP source routing */
+# endif /* ! IP_SRCROUTE */
+# ifndef HASSETRLIMIT
+# define HASSETRLIMIT 1 /* has setrlimit(2) call */
+# endif /* ! HASSETRLIMIT */
+# ifndef HASFLOCK
+# define HASFLOCK 1 /* has flock(2) call */
+# endif /* ! HASFLOCK */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone variable */
+# endif /* ! TZ_TYPE */
+# endif /* BSD */
+
+/* general System V Release 4 defines */
+# ifdef __svr4__
+# define SYSTEM5 1
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# define HASINITGROUPS 1 /* has initgroups(3) call */
+# define BSD_COMP 1 /* get BSD ioctl calls */
+# ifndef HASSETRLIMIT
+# define HASSETRLIMIT 1 /* has setrlimit(2) call */
+# endif /* ! HASSETRLIMIT */
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
+# endif /* ! HASGETUSERSHELL */
+# ifndef HASFCHMOD
+# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */
+# endif /* ! HASFCHMOD */
+
+# ifndef _PATH_UNIX
+# define _PATH_UNIX "/unix"
+# endif /* ! _PATH_UNIX */
+# ifndef _PATH_VENDOR_CF
+# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
+# endif /* ! _PATH_VENDOR_CF */
+# ifndef _PATH_SENDMAILPID
+# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
+# endif /* ! _PATH_SENDMAILPID */
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 128
+# endif /* ! SYSLOG_BUFSIZE */
+# ifndef SFS_TYPE
+# define SFS_TYPE SFS_STATVFS
+# endif /* ! SFS_TYPE */
+
+# ifndef USE_SIGLONGJMP
+# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
+# endif /* ! USE_SIGLONGJMP */
+# endif /* __svr4__ */
+
+# ifdef __SVR4
+# define LDA_USE_LOCKF 1
+# define LDA_USE_SETEUID 1
+# define _PATH_MAILDIR "/var/mail"
+# endif /* __SVR4 */
+
+/* general System V defines */
+# ifdef SYSTEM5
+# include <sys/sysmacros.h>
+# define HASUNAME 1 /* use System V uname(2) system call */
+# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
+# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
+# ifndef HASULIMIT
+# define HASULIMIT 1 /* has the ulimit(2) syscall */
+# endif /* ! HASULIMIT */
+# ifndef LA_TYPE
+# ifdef MIOC_READKSYM
+# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
+# else /* MIOC_READKSYM */
+# define LA_TYPE LA_INT /* assume integer load average */
+# endif /* MIOC_READKSYM */
+# endif /* ! LA_TYPE */
+# ifndef SFS_TYPE
+# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
+# endif /* ! SFS_TYPE */
+# ifndef TZ_TYPE
+# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
+# endif /* ! TZ_TYPE */
+# endif /* SYSTEM5 */
+
+/* general POSIX defines */
+# ifdef _POSIX_VERSION
+# define HASSETSID 1 /* has Posix setsid(2) call */
+# define HASWAITPID 1 /* has Posix waitpid(2) call */
+# if _POSIX_VERSION >= 199500 && !defined(USESETEUID)
+# define USESETEUID 1 /* has usable seteuid(2) call */
+# endif /* _POSIX_VERSION >= 199500 && !defined(USESETEUID) */
+# endif /* _POSIX_VERSION */
+/*
+** Tweaking for systems that (for example) claim to be BSD or POSIX
+** but don't have all the standard BSD or POSIX routines (boo hiss).
+*/
+
+# ifdef titan
+# undef HASINITGROUPS /* doesn't have initgroups(3) call */
+# endif /* titan */
+
+# ifdef _CRAYCOM
+# undef HASSETSID /* despite POSIX claim, doesn't have setsid */
+# endif /* _CRAYCOM */
+
+# ifdef MOTO
+# undef USESETEUID
+# endif /* MOTO */
+
+/*
+** Due to a "feature" in some operating systems such as Ultrix 4.3 and
+** HPUX 8.0, if you receive a "No route to host" message (ICMP message
+** ICMP_UNREACH_HOST) on _any_ connection, all connections to that host
+** are closed. Some firewalls return this error if you try to connect
+** to the IDENT port (113), so you can't receive email from these hosts
+** on these systems. The firewall really should use a more specific
+** message such as ICMP_UNREACH_PROTOCOL or _PORT or _FILTER_PROHIB. If
+** not explicitly set to zero above, default it on.
+*/
+
+# ifndef IDENTPROTO
+# define IDENTPROTO 1 /* use IDENT proto (RFC 1413) */
+# endif /* ! IDENTPROTO */
+
+# ifndef IP_SRCROUTE
+# define IP_SRCROUTE 1 /* Detect IP source routing */
+# endif /* ! IP_SRCROUTE */
+
+# ifndef HASGETUSERSHELL
+# define HASGETUSERSHELL 1 /* libc has getusershell(3) call */
+# endif /* ! HASGETUSERSHELL */
+
+# ifndef NETUNIX
+# define NETUNIX 1 /* include unix domain support */
+# endif /* ! NETUNIX */
+
+# ifndef HASRANDOM
+# define HASRANDOM 1 /* has random(3) support */
+# endif /* ! HASRANDOM */
+
+# ifndef HASFLOCK
+# define HASFLOCK 0 /* assume no flock(2) support */
+# endif /* ! HASFLOCK */
+
+# ifndef HASSETREUID
+# define HASSETREUID 0 /* assume no setreuid(2) call */
+# endif /* ! HASSETREUID */
+
+# ifndef HASFCHMOD
+# define HASFCHMOD 0 /* assume no fchmod(2) syscall */
+# endif /* ! HASFCHMOD */
+
+# ifndef USESETEUID
+# define USESETEUID 0 /* assume no seteuid(2) call or no saved ids */
+# endif /* ! USESETEUID */
+
+# ifndef HASSETRLIMIT
+# define HASSETRLIMIT 0 /* assume no setrlimit(2) support */
+# endif /* ! HASSETRLIMIT */
+
+# ifndef HASULIMIT
+# define HASULIMIT 0 /* assume no ulimit(2) support */
+# endif /* ! HASULIMIT */
+
+# ifndef SECUREWARE
+# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */
+# endif /* ! SECUREWARE */
+
+# ifndef USE_DOUBLE_FORK
+# define USE_DOUBLE_FORK 1 /* avoid intermediate zombies */
+# endif /* ! USE_DOUBLE_FORK */
+
+# ifndef USE_ENVIRON
+# define USE_ENVIRON 0 /* use main() envp instead of extern environ */
+# endif /* ! USE_ENVIRON */
+
+# ifndef USE_SIGLONGJMP
+# define USE_SIGLONGJMP 0 /* assume setjmp handles signals properly */
+# endif /* ! USE_SIGLONGJMP */
+
+# ifndef FDSET_CAST
+# define FDSET_CAST /* (empty) cast for fd_set arg to select */
+# endif /* ! FDSET_CAST */
+
+/*
+** Pick a mailer setuid method for changing the current uid
+*/
+
+# define USE_SETEUID 0
+# define USE_SETREUID 1
+# define USE_SETUID 2
+
+# if USESETEUID
+# define MAILER_SETUID_METHOD USE_SETEUID
+# else /* USESETEUID */
+# if HASSETREUID
+# define MAILER_SETUID_METHOD USE_SETREUID
+# else /* HASSETREUID */
+# define MAILER_SETUID_METHOD USE_SETUID
+# endif /* HASSETREUID */
+# endif /* USESETEUID */
+
+/*
+** If no type for argument two of getgroups call is defined, assume
+** it's an integer -- unfortunately, there seem to be several choices
+** here.
+*/
+
+# ifndef GIDSET_T
+# define GIDSET_T int
+# endif /* ! GIDSET_T */
+
+# ifndef UID_T
+# define UID_T uid_t
+# endif /* ! UID_T */
+
+# ifndef GID_T
+# define GID_T gid_t
+# endif /* ! GID_T */
+
+# ifndef MODE_T
+# define MODE_T mode_t
+# endif /* ! MODE_T */
+
+# ifndef ARGV_T
+# define ARGV_T char **
+# endif /* ! ARGV_T */
+
+# ifndef SOCKADDR_LEN_T
+# define SOCKADDR_LEN_T int
+# endif /* ! SOCKADDR_LEN_T */
+
+# ifndef SOCKOPT_LEN_T
+# define SOCKOPT_LEN_T int
+# endif /* ! SOCKOPT_LEN_T */
+
+# ifndef QUAD_T
+# define QUAD_T unsigned long
+# endif /* ! QUAD_T */
+/**********************************************************************
+** Remaining definitions should never have to be changed. They are
+** primarily to provide back compatibility for older systems -- for
+** example, it includes some POSIX compatibility definitions
+**********************************************************************/
+
+/* System 5 compatibility */
+# ifndef S_ISREG
+# define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG)
+# endif /* ! S_ISREG */
+# ifndef S_ISDIR
+# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR)
+# endif /* ! S_ISDIR */
+# if !defined(S_ISLNK) && defined(S_IFLNK)
+# define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK)
+# endif /* !defined(S_ISLNK) && defined(S_IFLNK) */
+# if !defined(S_ISFIFO)
+# if defined(S_IFIFO)
+# define S_ISFIFO(foo) ((foo & S_IFMT) == S_IFIFO)
+# else /* defined(S_IFIFO) */
+# define S_ISFIFO(foo) false
+# endif /* defined(S_IFIFO) */
+# endif /* !defined(S_ISFIFO) */
+# ifndef S_IRUSR
+# define S_IRUSR 0400
+# endif /* ! S_IRUSR */
+# ifndef S_IWUSR
+# define S_IWUSR 0200
+# endif /* ! S_IWUSR */
+# ifndef S_IRGRP
+# define S_IRGRP 0040
+# endif /* ! S_IRGRP */
+# ifndef S_IWGRP
+# define S_IWGRP 0020
+# endif /* ! S_IWGRP */
+# ifndef S_IROTH
+# define S_IROTH 0004
+# endif /* ! S_IROTH */
+# ifndef S_IWOTH
+# define S_IWOTH 0002
+# endif /* ! S_IWOTH */
+
+/* close-on-exec flag */
+# ifndef FD_CLOEXEC
+# define FD_CLOEXEC 1
+# endif /* ! FD_CLOEXEC */
+
+/*
+** Older systems don't have this error code -- it should be in
+** /usr/include/sysexits.h.
+*/
+
+# ifndef EX_CONFIG
+# define EX_CONFIG 78 /* configuration error */
+# endif /* ! EX_CONFIG */
+
+/* pseudo-codes */
+# define EX_QUIT 22 /* drop out of server immediately */
+# define EX_RESTART 23 /* restart sendmail daemon */
+# define EX_SHUTDOWN 24 /* shutdown sendmail daemon */
+
+#ifndef EX_NOTFOUND
+# define EX_NOTFOUND EX_NOHOST
+#endif /* ! EX_NOTFOUND */
+
+/* pseudo-code used for mci_setstat */
+# define EX_NOTSTICKY -5 /* don't save persistent status */
+
+
+/*
+** An "impossible" file mode to indicate that the file does not exist.
+*/
+
+# define ST_MODE_NOFILE 0171147 /* unlikely to occur */
+
+
+/* type of arbitrary pointer */
+# ifndef ARBPTR_T
+# define ARBPTR_T void *
+# endif /* ! ARBPTR_T */
+
+# ifndef __P
+# include "sm/cdefs.h"
+# endif /* ! __P */
+
+# if HESIOD && !defined(NAMED_BIND)
+# define NAMED_BIND 1 /* not one without the other */
+# endif /* HESIOD && !defined(NAMED_BIND) */
+
+# if NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno )
+extern int h_errno;
+# endif /* NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno ) */
+
+# if NEEDPUTENV
+extern int putenv __P((char *));
+# endif /* NEEDPUTENV */
+
+#if !HASUNSETENV
+extern void unsetenv __P((char *));
+#endif /* !HASUNSETENV */
+
+# ifdef LDAPMAP
+# include <sys/time.h>
+# include <lber.h>
+# include <ldap.h>
+
+/* Some LDAP constants */
+# define LDAPMAP_FALSE 0
+# define LDAPMAP_TRUE 1
+
+/*
+** ldap_init(3) is broken in Umich 3.x and OpenLDAP 1.0/1.1.
+** Use the lack of LDAP_OPT_SIZELIMIT to detect old API implementations
+** and assume (falsely) that all old API implementations are broken.
+** (OpenLDAP 1.2 and later have a working ldap_init(), add -DUSE_LDAP_INIT)
+*/
+
+# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT)
+# define USE_LDAP_INIT 1
+# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT) */
+
+/*
+** LDAP_OPT_SIZELIMIT is not defined under Umich 3.x nor OpenLDAP 1.x,
+** hence ldap_set_option() must not exist.
+*/
+
+# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION)
+# define USE_LDAP_SET_OPTION 1
+# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION) */
+
+# endif /* LDAPMAP */
+
+# if HASUNAME
+# include <sys/utsname.h>
+# ifdef newstr
+# undef newstr
+# endif /* newstr */
+# else /* HASUNAME */
+# define NODE_LENGTH 32
+struct utsname
+{
+ char nodename[NODE_LENGTH + 1];
+};
+# endif /* HASUNAME */
+
+# if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V)
+# define MAXHOSTNAMELEN 256
+# endif /* !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V) */
+
+# if !defined(SIGCHLD) && defined(SIGCLD)
+# define SIGCHLD SIGCLD
+# endif /* !defined(SIGCHLD) && defined(SIGCLD) */
+
+# ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+# endif /* ! STDIN_FILENO */
+
+# ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+# endif /* ! STDOUT_FILENO */
+
+# ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+# endif /* ! STDERR_FILENO */
+
+# ifndef LOCK_SH
+# define LOCK_SH 0x01 /* shared lock */
+# define LOCK_EX 0x02 /* exclusive lock */
+# define LOCK_NB 0x04 /* non-blocking lock */
+# define LOCK_UN 0x08 /* unlock */
+# endif /* ! LOCK_SH */
+
+# ifndef S_IXOTH
+# define S_IXOTH (S_IEXEC >> 6)
+# endif /* ! S_IXOTH */
+
+# ifndef S_IXGRP
+# define S_IXGRP (S_IEXEC >> 3)
+# endif /* ! S_IXGRP */
+
+# ifndef S_IXUSR
+# define S_IXUSR (S_IEXEC)
+# endif /* ! S_IXUSR */
+
+#ifndef O_ACCMODE
+# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
+#endif /* ! O_ACCMODE */
+
+# ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+# endif /* ! SEEK_SET */
+
+# ifndef SIG_ERR
+# define SIG_ERR ((void (*)()) -1)
+# endif /* ! SIG_ERR */
+
+# ifndef WEXITSTATUS
+# define WEXITSTATUS(st) (((st) >> 8) & 0377)
+# endif /* ! WEXITSTATUS */
+# ifndef WIFEXITED
+# define WIFEXITED(st) (((st) & 0377) == 0)
+# endif /* ! WIFEXITED */
+# ifndef WIFSTOPPED
+# define WIFSTOPPED(st) (((st) & 0100) == 0)
+# endif /* ! WIFSTOPPED */
+# ifndef WCOREDUMP
+# define WCOREDUMP(st) (((st) & 0200) != 0)
+# endif /* ! WCOREDUMP */
+# ifndef WTERMSIG
+# define WTERMSIG(st) (((st) & 0177))
+# endif /* ! WTERMSIG */
+
+# ifndef SIGFUNC_DEFINED
+typedef void (*sigfunc_t) __P((int));
+# endif /* ! SIGFUNC_DEFINED */
+# ifndef SIGFUNC_RETURN
+# define SIGFUNC_RETURN
+# endif /* ! SIGFUNC_RETURN */
+# ifndef SIGFUNC_DECL
+# define SIGFUNC_DECL void
+# endif /* ! SIGFUNC_DECL */
+
+/* size of syslog buffer */
+# ifndef SYSLOG_BUFSIZE
+# define SYSLOG_BUFSIZE 1024
+# endif /* ! SYSLOG_BUFSIZE */
+
+/*
+** Size of prescan buffer.
+** Despite comments in the _sendmail_ book, this probably should
+** not be changed; there are some hard-to-define dependencies.
+*/
+
+# define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */
+
+/* fork routine -- set above using #ifdef _osname_ or in Makefile */
+# ifndef FORK
+# define FORK fork /* function to call to fork mailer */
+# endif /* ! FORK */
+
+/* setting h_errno */
+# ifndef SM_SET_H_ERRNO
+# define SM_SET_H_ERRNO(err) h_errno = (err)
+# endif /* SM_SET_H_ERRNO */
+
+# ifndef SM_CONF_GETOPT
+# define SM_CONF_GETOPT 1
+# endif /* ! SM_CONF_GETOPT */
+
+/* random routine -- set above using #ifdef _osname_ or in Makefile */
+# if HASRANDOM
+# define get_random() random()
+# else /* HASRANDOM */
+# define get_random() ((long) rand())
+# ifndef RANDOMSHIFT
+# define RANDOMSHIFT 8
+# endif /* ! RANDOMSHIFT */
+# endif /* HASRANDOM */
+
+/*
+** Default to using scanf in readcf.
+*/
+
+# ifndef SCANF
+# define SCANF 1
+# endif /* ! SCANF */
+
+/* XXX 32 bit type */
+# ifndef SM_INT32
+# define SM_INT32 int32_t
+# endif /* ! SM_INT32 */
+
+/*
+** SVr4 and similar systems use different routines for setjmp/longjmp
+** with signal support
+*/
+
+# if USE_SIGLONGJMP
+# ifdef jmp_buf
+# undef jmp_buf
+# endif /* jmp_buf */
+# define jmp_buf sigjmp_buf
+# ifdef setjmp
+# undef setjmp
+# endif /* setjmp */
+# define setjmp(env) sigsetjmp(env, 1)
+# ifdef longjmp
+# undef longjmp
+# endif /* longjmp */
+# define longjmp(env, val) siglongjmp(env, val)
+# endif /* USE_SIGLONGJMP */
+
+# if !defined(NGROUPS_MAX) && defined(NGROUPS)
+# define NGROUPS_MAX NGROUPS /* POSIX naming convention */
+# endif /* !defined(NGROUPS_MAX) && defined(NGROUPS) */
+
+/*
+** Some snprintf() implementations are rumored not to NUL terminate.
+*/
+# if SNPRINTF_IS_BROKEN
+# ifdef snprintf
+# undef snprintf
+# endif /* snprintf */
+# define snprintf sm_snprintf
+# ifdef vsnprintf
+# undef vsnprintf
+# endif /* vsnprintf */
+# define vsnprintf sm_vsnprintf
+# endif /* SNPRINTF_IS_BROKEN */
+
+/*
+** If we don't have a system syslog, simulate it.
+*/
+
+# if !LOG
+# define LOG_EMERG 0 /* system is unusable */
+# define LOG_ALERT 1 /* action must be taken immediately */
+# define LOG_CRIT 2 /* critical conditions */
+# define LOG_ERR 3 /* error conditions */
+# define LOG_WARNING 4 /* warning conditions */
+# define LOG_NOTICE 5 /* normal but significant condition */
+# define LOG_INFO 6 /* informational */
+# define LOG_DEBUG 7 /* debug-level messages */
+# endif /* !LOG */
+
+# ifndef SM_CONF_SYSLOG
+# define SM_CONF_SYSLOG 1 /* syslog.h has prototype for syslog() */
+# endif /* SM_CONF_SYSLOG */
+
+# if !SM_CONF_SYSLOG
+# ifdef __STDC__
+extern void syslog(int, const char *, ...);
+# else /* __STDC__ */
+extern void syslog();
+# endif /* __STDC__ */
+# endif /* !SM_CONF_SYSLOG */
+
+/* portable(?) definition for alignment */
+# ifndef SM_ALIGN_SIZE
+struct sm_align
+{
+ char al_c;
+ union
+ {
+ long al_l;
+ void *al_p;
+ double al_d;
+ void (*al_f)();
+ } al_u;
+};
+# define SM_ALIGN_SIZE offsetof(struct sm_align, al_u)
+# endif /* ! SM_ALIGN_SIZE */
+# define SM_ALIGN_BITS (SM_ALIGN_SIZE - 1)
+
+#endif /* ! SM_CONF_H */
diff --git a/contrib/sendmail/include/sm/config.h b/contrib/sendmail/include/sm/config.h
new file mode 100644
index 0000000..de34a76
--- /dev/null
+++ b/contrib/sendmail/include/sm/config.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: config.h,v 1.42 2001/06/17 21:31:11 ca Exp $
+ */
+
+/*
+** libsm configuration macros.
+** The values of these macros are platform dependent.
+** The default values are given here.
+** If the default is incorrect, then the correct value can be specified
+** in the m4 configuration file in devtools/OS.
+*/
+
+#ifndef SM_CONFIG_H
+# define SM_CONFIG_H
+
+# include "sm_os.h"
+
+/*
+** SM_CONF_STDBOOL_H is 1 if <stdbool.h> exists
+*/
+
+# ifndef SM_CONF_STDBOOL_H
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define SM_CONF_STDBOOL_H 1
+# else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L */
+# define SM_CONF_STDBOOL_H 0
+# endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L */
+# endif /* ! SM_CONF_STDBOOL_H */
+
+/*
+** Configuration macros that specify how __P is defined.
+*/
+
+# ifndef SM_CONF_SYS_CDEFS_H
+# define SM_CONF_SYS_CDEFS_H 0
+# endif /* ! SM_CONF_SYS_CDEFS_H */
+
+/*
+** SM_CONF_STDDEF_H is 1 if <stddef.h> exists
+*/
+
+# ifndef SM_CONF_STDDEF_H
+# define SM_CONF_STDDEF_H 1
+# endif /* ! SM_CONF_STDDEF_H */
+
+/*
+** Configuration macro that specifies whether strlcpy/strlcat are available.
+** Note: this is the default so that the libsm version (optimized) will
+** be used by default (sm_strlcpy/sm_strlcat).
+*/
+
+# ifndef SM_CONF_STRL
+# define SM_CONF_STRL 0
+# endif /* ! SM_CONF_STRL */
+
+/*
+** Configuration macro indicating that setitimer is available
+*/
+
+# ifndef SM_CONF_SETITIMER
+# define SM_CONF_SETITIMER 1
+# endif /* ! SM_CONF_SETITIMER */
+
+/*
+** Does <sys/types.h> define uid_t and gid_t?
+*/
+
+# ifndef SM_CONF_UID_GID
+# define SM_CONF_UID_GID 1
+# endif /* ! SM_CONF_UID_GID */
+
+/*
+** Does <sys/types.h> define ssize_t?
+*/
+# ifndef SM_CONF_SSIZE_T
+# define SM_CONF_SSIZE_T 1
+# endif /* ! SM_CONF_SSIZE_T */
+
+/*
+** Does the C compiler support long long?
+*/
+
+# ifndef SM_CONF_LONGLONG
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define SM_CONF_LONGLONG 1
+# else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L */
+# if defined(__GNUC__)
+# define SM_CONF_LONGLONG 1
+# else /* defined(__GNUC__) */
+# define SM_CONF_LONGLONG 0
+# endif /* defined(__GNUC__) */
+# endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L */
+# endif /* ! SM_CONF_LONGLONG */
+
+/*
+** Does <sys/types.h> define quad_t and u_quad_t?
+** We only care if long long is not available.
+*/
+
+# ifndef SM_CONF_QUAD_T
+# define SM_CONF_QUAD_T 0
+# endif /* ! SM_CONF_QUAD_T */
+
+/*
+** Configuration macro indicating that shared memory is available
+*/
+
+# ifndef SM_CONF_SHM
+# define SM_CONF_SHM 0
+# endif /* ! SM_CONF_SHM */
+
+/*
+** Does <setjmp.h> define sigsetjmp?
+*/
+
+# ifndef SM_CONF_SIGSETJMP
+# define SM_CONF_SIGSETJMP 1
+# endif /* ! SM_CONF_SIGSETJMP */
+
+/*
+** Does <sysexits.h> exist, and define the EX_* macros with values
+** that differ from the default BSD values in <sm/sysexits.h>?
+*/
+
+# ifndef SM_CONF_SYSEXITS_H
+# define SM_CONF_SYSEXITS_H 0
+# endif /* ! SM_CONF_SYSEXITS_H */
+
+/* has memchr() prototype? (if not: needs memory.h) */
+# ifndef SM_CONF_MEMCHR
+# define SM_CONF_MEMCHR 1
+# endif /* ! SM_CONF_MEMCHR */
+
+/* try LLONG tests in libsm/t-types.c? */
+# ifndef SM_CONF_TEST_LLONG
+# define SM_CONF_TEST_LLONG 1
+# endif /* !SM_CONF_TEST_LLONG */
+
+#endif /* ! SM_CONFIG_H */
diff --git a/contrib/sendmail/include/sm/debug.h b/contrib/sendmail/include/sm/debug.h
new file mode 100644
index 0000000..eba29ad
--- /dev/null
+++ b/contrib/sendmail/include/sm/debug.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: debug.h,v 1.15 2001/03/08 03:23:07 ca Exp $
+ */
+
+/*
+** libsm debugging and tracing
+** See libsm/debug.html for documentation.
+*/
+
+#ifndef SM_DEBUG_H
+# define SM_DEBUG_H
+
+# include <sm/gen.h>
+# include <sm/io.h>
+
+/*
+** abstractions for printing trace messages
+*/
+
+extern SM_FILE_T *
+sm_debug_file __P((void));
+
+extern void
+sm_debug_setfile __P((
+ SM_FILE_T *));
+
+extern void PRINTFLIKE(1, 2)
+sm_dprintf __P((
+ char *_fmt,
+ ...));
+
+extern void
+sm_dflush __P((void));
+
+/*
+** abstractions for setting and testing debug activation levels
+*/
+
+extern void
+sm_debug_addsettings_x __P((
+ const char *));
+
+extern void
+sm_debug_addsetting_x __P((
+ const char *,
+ int));
+
+# define SM_DEBUG_UNKNOWN ((SM_ATOMIC_UINT_T)(-1))
+
+extern const char SmDebugMagic[];
+
+typedef struct sm_debug SM_DEBUG_T;
+struct sm_debug
+{
+ const char *sm_magic; /* points to SmDebugMagic */
+
+ /*
+ ** debug_level is the activation level of this debug
+ ** object. Level 0 means no debug activity.
+ ** It is initialized to SM_DEBUG_UNKNOWN, which indicates
+ ** that the true value is unknown. If debug_level ==
+ ** SM_DEBUG_UNKNOWN, then the access functions will look up
+ ** its true value in the internal table of debug settings.
+ */
+
+ SM_ATOMIC_UINT_T debug_level;
+
+ /*
+ ** debug_name is the name used to reference this SM_DEBUG
+ ** structure via the sendmail -d option.
+ */
+
+ char *debug_name;
+
+ /*
+ ** debug_desc is a literal character string of the form
+ ** "@(#)$Debug: <name> - <short description> $"
+ */
+
+ char *debug_desc;
+
+ /*
+ ** We keep a linked list of initialized SM_DEBUG structures
+ ** so that when sm_debug_addsetting is called, we can reset
+ ** them all back to the uninitialized state.
+ */
+
+ SM_DEBUG_T *debug_next;
+};
+
+# ifndef SM_DEBUG_CHECK
+# define SM_DEBUG_CHECK 1
+# endif /* ! SM_DEBUG_CHECK */
+
+# if SM_DEBUG_CHECK
+/*
+** This macro is cleverly designed so that if the debug object is below
+** the specified level, then the only overhead is a single comparison
+** (except for the first time this macro is invoked).
+*/
+
+# define sm_debug_active(debug, level) \
+ ((debug)->debug_level >= (level) && \
+ ((debug)->debug_level != SM_DEBUG_UNKNOWN || \
+ sm_debug_loadactive(debug, level)))
+
+# define sm_debug_level(debug) \
+ ((debug)->debug_level == SM_DEBUG_UNKNOWN \
+ ? sm_debug_loadlevel(debug) : (debug)->debug_level)
+
+# define sm_debug_unknown(debug) ((debug)->debug_level == SM_DEBUG_UNKNOWN)
+# else /* SM_DEBUG_CHECK */
+# define sm_debug_active(debug, level) 0
+# define sm_debug_level(debug) 0
+# define sm_debug_unknown(debug) 0
+# endif /* SM_DEBUG_CHECK */
+
+extern bool
+sm_debug_loadactive __P((
+ SM_DEBUG_T *,
+ int));
+
+extern int
+sm_debug_loadlevel __P((
+ SM_DEBUG_T *));
+
+# define SM_DEBUG_INITIALIZER(name, desc) { \
+ SmDebugMagic, \
+ SM_DEBUG_UNKNOWN, \
+ name, \
+ desc, \
+ NULL}
+
+#endif /* ! SM_DEBUG_H */
diff --git a/contrib/sendmail/include/sm/errstring.h b/contrib/sendmail/include/sm/errstring.h
new file mode 100644
index 0000000..c5447d1
--- /dev/null
+++ b/contrib/sendmail/include/sm/errstring.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ *
+ * $Id: errstring.h,v 1.4 2001/06/07 20:04:53 ca Exp $
+ */
+
+/*
+** Error codes.
+*/
+
+#ifndef SM_ERRSTRING_H
+# define SM_ERRSTRING_H
+
+#include <errno.h>
+extern int errno;
+
+/*
+** These are used in a few cases where we need some special
+** error codes, but where the system doesn't provide something
+** reasonable. They are printed in sm_errstring.
+*/
+
+#ifndef E_PSEUDOBASE
+# define E_PSEUDOBASE 256
+#endif /* ! E_PSEUDOBASE */
+
+#define E_SM_OPENTIMEOUT (E_PSEUDOBASE + 0) /* Timeout on file open */
+#define E_SM_NOSLINK (E_PSEUDOBASE + 1) /* Symbolic links not allowed */
+#define E_SM_NOHLINK (E_PSEUDOBASE + 2) /* Hard links not allowed */
+#define E_SM_REGONLY (E_PSEUDOBASE + 3) /* Regular files only */
+#define E_SM_ISEXEC (E_PSEUDOBASE + 4) /* Executable files not allowed */
+#define E_SM_WWDIR (E_PSEUDOBASE + 5) /* World writable directory */
+#define E_SM_GWDIR (E_PSEUDOBASE + 6) /* Group writable directory */
+#define E_SM_FILECHANGE (E_PSEUDOBASE + 7) /* File changed after open */
+#define E_SM_WWFILE (E_PSEUDOBASE + 8) /* World writable file */
+#define E_SM_GWFILE (E_PSEUDOBASE + 9) /* Group writable file */
+#define E_SM_GRFILE (E_PSEUDOBASE + 10) /* g readable file */
+#define E_SM_WRFILE (E_PSEUDOBASE + 11) /* o readable file */
+#define E_DNSBASE (E_PSEUDOBASE + 20) /* base for DNS h_errno */
+#define E_SMDBBASE (E_PSEUDOBASE + 40) /* base for libsmdb errors */
+#define E_LDAPBASE (E_PSEUDOBASE + 70) /* base for LDAP errors */
+
+/* libsmdb */
+#define SMDBE_OK 0
+#define SMDBE_MALLOC (E_SMDBBASE + 1)
+#define SMDBE_GDBM_IS_BAD (E_SMDBBASE + 2)
+#define SMDBE_UNSUPPORTED (E_SMDBBASE + 3)
+#define SMDBE_DUPLICATE (E_SMDBBASE + 4)
+#define SMDBE_BAD_OPEN (E_SMDBBASE + 5)
+#define SMDBE_NOT_FOUND (E_SMDBBASE + 6)
+#define SMDBE_UNKNOWN_DB_TYPE (E_SMDBBASE + 7)
+#define SMDBE_UNSUPPORTED_DB_TYPE (E_SMDBBASE + 8)
+#define SMDBE_INCOMPLETE (E_SMDBBASE + 9)
+#define SMDBE_KEY_EMPTY (E_SMDBBASE + 10)
+#define SMDBE_KEY_EXIST (E_SMDBBASE + 11)
+#define SMDBE_LOCK_DEADLOCK (E_SMDBBASE + 12)
+#define SMDBE_LOCK_NOT_GRANTED (E_SMDBBASE + 13)
+#define SMDBE_LOCK_NOT_HELD (E_SMDBBASE + 14)
+#define SMDBE_RUN_RECOVERY (E_SMDBBASE + 15)
+#define SMDBE_IO_ERROR (E_SMDBBASE + 16)
+#define SMDBE_READ_ONLY (E_SMDBBASE + 17)
+#define SMDBE_DB_NAME_TOO_LONG (E_SMDBBASE + 18)
+#define SMDBE_INVALID_PARAMETER (E_SMDBBASE + 19)
+#define SMDBE_ONLY_SUPPORTS_ONE_CURSOR (E_SMDBBASE + 20)
+#define SMDBE_NOT_A_VALID_CURSOR (E_SMDBBASE + 21)
+#define SMDBE_LAST_ENTRY (E_SMDBBASE + 22)
+#define SMDBE_OLD_VERSION (E_SMDBBASE + 23)
+
+extern const char *
+sm_errstring __P((
+ int _errno));
+
+#endif /* SM_ERRSTRING_H */
diff --git a/contrib/sendmail/include/sm/exc.h b/contrib/sendmail/include/sm/exc.h
new file mode 100644
index 0000000..afcb125
--- /dev/null
+++ b/contrib/sendmail/include/sm/exc.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: exc.h,v 1.23 2001/06/07 20:04:53 ca Exp $
+ */
+
+/*
+** libsm exception handling
+** See libsm/exc.html for documentation.
+*/
+
+#ifndef SM_EXC_H
+# define SM_EXC_H
+
+#include <sm/setjmp.h>
+#include <sm/io.h>
+#include <sm/gen.h>
+#include <sm/assert.h>
+
+typedef struct sm_exc SM_EXC_T;
+typedef struct sm_exc_type SM_EXC_TYPE_T;
+typedef union sm_val SM_VAL_T;
+
+/*
+** Exception types
+*/
+
+extern const char SmExcTypeMagic[];
+
+struct sm_exc_type
+{
+ const char *sm_magic;
+ const char *etype_category;
+ const char *etype_argformat;
+ void (*etype_print) __P((SM_EXC_T *, SM_FILE_T *));
+ const char *etype_printcontext;
+};
+
+extern const SM_EXC_TYPE_T SmEtypeOs;
+extern const SM_EXC_TYPE_T SmEtypeErr;
+
+extern void
+sm_etype_printf __P((
+ SM_EXC_T *_exc,
+ SM_FILE_T *_stream));
+
+/*
+** Exception objects
+*/
+
+extern const char SmExcMagic[];
+
+union sm_val
+{
+ int v_int;
+ long v_long;
+ char *v_str;
+ SM_EXC_T *v_exc;
+};
+
+struct sm_exc
+{
+ const char *sm_magic;
+ size_t exc_refcount;
+ const SM_EXC_TYPE_T *exc_type;
+ SM_VAL_T *exc_argv;
+};
+
+# define SM_EXC_INITIALIZER(type, argv) \
+ { \
+ SmExcMagic, \
+ 0, \
+ type, \
+ argv, \
+ }
+
+extern SM_EXC_T *
+sm_exc_new_x __P((
+ const SM_EXC_TYPE_T *_type,
+ ...));
+
+extern SM_EXC_T *
+sm_exc_addref __P((
+ SM_EXC_T *_exc));
+
+extern void
+sm_exc_free __P((
+ SM_EXC_T *_exc));
+
+extern bool
+sm_exc_match __P((
+ SM_EXC_T *_exc,
+ const char *_pattern));
+
+extern void
+sm_exc_write __P((
+ SM_EXC_T *_exc,
+ SM_FILE_T *_stream));
+
+extern void
+sm_exc_print __P((
+ SM_EXC_T *_exc,
+ SM_FILE_T *_stream));
+
+extern SM_DEAD(void
+sm_exc_raise_x __P((
+ SM_EXC_T *_exc)));
+
+extern SM_DEAD(void
+sm_exc_raisenew_x __P((
+ const SM_EXC_TYPE_T *_type,
+ ...)));
+
+/*
+** Exception handling
+*/
+
+typedef void (*SM_EXC_DEFAULT_HANDLER_T) __P((SM_EXC_T *));
+
+extern void
+sm_exc_newthread __P((
+ SM_EXC_DEFAULT_HANDLER_T _handle));
+
+typedef struct sm_exc_handler SM_EXC_HANDLER_T;
+struct sm_exc_handler
+{
+ SM_EXC_T *eh_value;
+ SM_JMPBUF_T eh_context;
+ SM_EXC_HANDLER_T *eh_parent;
+ int eh_state;
+};
+
+/* values for eh_state */
+enum
+{
+ SM_EH_PUSHED = 2,
+ SM_EH_POPPED = 0,
+ SM_EH_HANDLED = 1
+};
+
+extern SM_EXC_HANDLER_T *SmExcHandler;
+
+# define SM_TRY { SM_EXC_HANDLER_T _h; \
+ do { \
+ _h.eh_value = NULL; \
+ _h.eh_parent = SmExcHandler; \
+ _h.eh_state = SM_EH_PUSHED; \
+ SmExcHandler = &_h; \
+ if (sm_setjmp_nosig(_h.eh_context) == 0) {
+
+# define SM_FINALLY SM_ASSERT(SmExcHandler == &_h); \
+ } \
+ if (sm_setjmp_nosig(_h.eh_context) == 0) {
+
+# define SM_EXCEPT(e,pat) } \
+ if (_h.eh_state == SM_EH_HANDLED) \
+ break; \
+ if (_h.eh_state == SM_EH_PUSHED) { \
+ SM_ASSERT(SmExcHandler == &_h); \
+ SmExcHandler = _h.eh_parent; \
+ } \
+ _h.eh_state = sm_exc_match(_h.eh_value,pat) \
+ ? SM_EH_HANDLED : SM_EH_POPPED; \
+ if (_h.eh_state == SM_EH_HANDLED) { \
+ SM_UNUSED(SM_EXC_T *e) = _h.eh_value;
+
+# define SM_END_TRY } \
+ } while (0); \
+ if (_h.eh_state == SM_EH_PUSHED) { \
+ SM_ASSERT(SmExcHandler == &_h); \
+ SmExcHandler = _h.eh_parent; \
+ if (_h.eh_value != NULL) \
+ sm_exc_raise_x(_h.eh_value); \
+ } else if (_h.eh_state == SM_EH_POPPED) { \
+ if (_h.eh_value != NULL) \
+ sm_exc_raise_x(_h.eh_value); \
+ } else \
+ sm_exc_free(_h.eh_value); \
+ }
+
+#endif /* SM_EXC_H */
diff --git a/contrib/sendmail/include/sm/fdset.h b/contrib/sendmail/include/sm/fdset.h
new file mode 100644
index 0000000..6f13411
--- /dev/null
+++ b/contrib/sendmail/include/sm/fdset.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: fdset.h,v 1.3 2001/03/30 23:45:31 geir Exp $
+ */
+
+#ifndef SM_FDSET_H
+# define SM_FDSET_H
+
+# define SM_FD_SET(fd, pfdset) FD_SET(fd, pfdset)
+# define SM_FD_ISSET(fd, pfdset) FD_ISSET(fd, pfdset)
+# define SM_FD_SETSIZE FD_SETSIZE
+
+#endif /* SM_FDSET_H */
diff --git a/contrib/sendmail/include/sm/gen.h b/contrib/sendmail/include/sm/gen.h
new file mode 100644
index 0000000..b250705
--- /dev/null
+++ b/contrib/sendmail/include/sm/gen.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: gen.h,v 1.19 2001/09/11 04:04:43 gshapiro Exp $
+ */
+
+/*
+** libsm general definitions
+** See libsm/gen.html for documentation.
+*/
+
+#ifndef SM_GEN_H
+# define SM_GEN_H
+
+# include <sm/config.h>
+# include <sm/cdefs.h>
+# include <sm/types.h>
+
+/*
+** Define SM_RCSID and SM_IDSTR,
+** macros used to embed RCS and SCCS identification strings in object files.
+*/
+
+# ifdef lint
+# define SM_RCSID(str)
+# define SM_IDSTR(id,str)
+# else /* lint */
+# define SM_RCSID(str) SM_UNUSED(static const char RcsId[]) = str;
+# define SM_IDSTR(id,str) SM_UNUSED(static const char id[]) = str;
+# endif /* lint */
+
+/*
+** Define NULL and offsetof (from the C89 standard)
+*/
+
+# if SM_CONF_STDDEF_H
+# include <stddef.h>
+# else /* SM_CONF_STDDEF_H */
+# ifndef NULL
+# define NULL 0
+# endif
+# define offsetof(type, member) ((size_t)(&((type *)0)->member))
+# endif /* SM_CONF_STDDEF_H */
+
+/*
+** Define bool, true, false (from the C99 standard)
+*/
+
+# if SM_CONF_STDBOOL_H
+# include <stdbool.h>
+# else /* SM_CONF_STDBOOL_H */
+# ifndef __cplusplus
+ typedef int bool;
+# define false 0
+# define true 1
+# endif
+# endif /* SM_CONF_STDBOOL_H */
+
+/*
+** Define SM_MAX and SM_MIN
+*/
+
+# define SM_MAX(a, b) ((a) > (b) ? (a) : (b))
+# define SM_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/* Define SM_SUCCESS and SM_FAILURE */
+# define SM_SUCCESS 0
+# define SM_FAILURE (-1)
+
+/* XXX This needs to be fixed when we start to use threads: */
+typedef int SM_ATOMIC_INT_T;
+typedef unsigned int SM_ATOMIC_UINT_T;
+
+#endif /* SM_GEN_H */
diff --git a/contrib/sendmail/include/sm/heap.h b/contrib/sendmail/include/sm/heap.h
new file mode 100644
index 0000000..8b56370
--- /dev/null
+++ b/contrib/sendmail/include/sm/heap.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: heap.h,v 1.22 2001/09/04 22:41:55 ca Exp $
+ */
+
+/*
+** Sendmail debugging memory allocation package.
+** See libsm/heap.html for documentation.
+*/
+
+#ifndef SM_HEAP_H
+# define SM_HEAP_H
+
+# include <sm/io.h>
+# include <stdlib.h>
+# include <sm/debug.h>
+# include <sm/exc.h>
+
+/* change default to 0 for production? */
+# ifndef SM_HEAP_CHECK
+# define SM_HEAP_CHECK 1
+# endif /* ! SM_HEAP_CHECK */
+
+# if SM_HEAP_CHECK
+# define sm_malloc_x(sz) sm_malloc_tagged_x(sz, __FILE__, __LINE__, SmHeapGroup)
+# define sm_malloc(size) sm_malloc_tagged(size, __FILE__, __LINE__, SmHeapGroup)
+# define sm_free(ptr) sm_free_tagged(ptr, __FILE__, __LINE__)
+
+extern void *sm_malloc_tagged __P((size_t, char *, int, int));
+extern void *sm_malloc_tagged_x __P((size_t, char *, int, int));
+extern void sm_free_tagged __P((void *, char *, int));
+extern void *sm_realloc_x __P((void *, size_t));
+extern bool sm_heap_register __P((void *, size_t, char *, int, int));
+extern void sm_heap_checkptr_tagged __P((void *, char *, int));
+extern void sm_heap_report __P((SM_FILE_T *, int));
+
+# else /* SM_HEAP_CHECK */
+# define sm_malloc_tagged(size, file, line, grp) sm_malloc(size)
+# define sm_malloc_tagged_x(size, file, line, grp) sm_malloc_x(size)
+# define sm_free_tagged(ptr, file, line) sm_free(ptr)
+# define sm_heap_register(ptr, size, file, line, grp) (true)
+# define sm_heap_checkptr_tagged(ptr, tag, num) ((void)0)
+# define sm_heap_report(file, verbose) ((void)0)
+
+extern void *sm_malloc __P((size_t));
+extern void *sm_malloc_x __P((size_t));
+extern void *sm_realloc_x __P((void *, size_t));
+extern void sm_free __P((void *));
+# endif /* SM_HEAP_CHECK */
+
+extern void *sm_realloc __P((void *, size_t));
+
+# define sm_heap_checkptr(ptr) sm_heap_checkptr_tagged(ptr, __FILE__, __LINE__)
+
+#if 0
+/*
+** sm_f[mc]alloc are plug in replacements for malloc and calloc
+** which can be used in a context requiring a function pointer,
+** and which are compatible with sm_free. Warning: sm_heap_report
+** cannot report where storage leaked by sm_f[mc]alloc was allocated.
+*/
+
+/* XXX unused right now */
+
+extern void *
+sm_fmalloc __P((
+ size_t));
+
+extern void *
+sm_fcalloc __P((
+ size_t,
+ size_t));
+#endif /* 0 */
+
+/*
+** Allocate 'permanent' storage that can be freed but may still be
+** allocated when the process exits. sm_heap_report will not complain
+** about a storage leak originating from a call to sm_pmalloc.
+*/
+
+# define sm_pmalloc(size) sm_malloc_tagged(size, __FILE__, __LINE__, 0)
+# define sm_pmalloc_x(size) sm_malloc_tagged_x(size, __FILE__, __LINE__, 0)
+
+# define sm_heap_group() SmHeapGroup
+# define sm_heap_setgroup(g) (SmHeapGroup = (g))
+# define sm_heap_newgroup() (SmHeapGroup = ++SmHeapMaxGroup)
+
+extern int SmHeapGroup;
+extern int SmHeapMaxGroup;
+
+extern SM_DEBUG_T SmHeapTrace;
+extern SM_DEBUG_T SmHeapCheck;
+extern SM_EXC_T SmHeapOutOfMemory;
+
+#endif /* ! SM_HEAP_H */
diff --git a/contrib/sendmail/include/sm/io.h b/contrib/sendmail/include/sm/io.h
new file mode 100644
index 0000000..b95ede5
--- /dev/null
+++ b/contrib/sendmail/include/sm/io.h
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: io.h,v 1.19 2001/07/10 21:56:46 gshapiro Exp $
+ */
+
+/*-
+ * @(#)stdio.h 5.17 (Berkeley) 6/3/91
+ */
+
+#ifndef SM_IO_H
+#define SM_IO_H
+
+#include <stdio.h>
+#include <sm/gen.h>
+#include <sm/varargs.h>
+
+/* mode for sm io (exposed) */
+#define SM_IO_RDWR 1 /* read-write */
+#define SM_IO_RDONLY 2 /* read-only */
+#define SM_IO_WRONLY 3 /* write-only */
+#define SM_IO_APPEND 4 /* write-only from eof */
+#define SM_IO_APPENDRW 5 /* read-write from eof */
+#define SM_IO_RDWRTR 6 /* read-write with truncation indicated */
+
+/* for sm_io_fseek, et al api's (exposed) */
+#define SM_IO_SEEK_SET 0
+#define SM_IO_SEEK_CUR 1
+#define SM_IO_SEEK_END 2
+
+/* flags for info what's with different types (exposed) */
+#define SM_IO_WHAT_MODE 1
+#define SM_IO_WHAT_VECTORS 2
+#define SM_IO_WHAT_FD 3
+#define SM_IO_WHAT_TYPE 4
+#define SM_IO_WHAT_ISTYPE 5
+#define SM_IO_IS_READABLE 6
+#define SM_IO_WHAT_TIMEOUT 7
+
+/* info flags (exposed) */
+#define SM_IO_FTYPE_CREATE 1
+#define SM_IO_FTYPE_MODIFY 2
+#define SM_IO_FTYPE_DELETE 3
+
+#define SM_IO_SL_PRIO 1
+
+#define SM_IO_OPEN_MAX 20
+
+/* for internal buffers */
+struct smbuf
+{
+ unsigned char *smb_base;
+ int smb_size;
+};
+
+/*
+** sm I/O state variables (internal only).
+**
+** The following always hold:
+**
+** if (flags&(SMLBF|SMWR)) == (SMLBF|SMWR),
+** lbfsize is -bf.size, else lbfsize is 0
+** if flags&SMRD, w is 0
+** if flags&SMWR, r is 0
+**
+** This ensures that the getc and putc macros (or inline functions) never
+** try to write or read from a file that is in `read' or `write' mode.
+** (Moreover, they can, and do, automatically switch from read mode to
+** write mode, and back, on "r+" and "w+" files.)
+**
+** lbfsize is used only to make the inline line-buffered output stream
+** code as compact as possible.
+**
+** ub, up, and ur are used when ungetc() pushes back more characters
+** than fit in the current bf, or when ungetc() pushes back a character
+** that does not match the previous one in bf. When this happens,
+** ub.base becomes non-nil (i.e., a stream has ungetc() data iff
+** ub.base!=NULL) and up and ur save the current values of p and r.
+*/
+
+typedef struct sm_file SM_FILE_T;
+
+struct sm_file
+{
+ const char *sm_magic; /* This SM_FILE_T is free when NULL */
+ unsigned char *f_p; /* current position in (some) buffer */
+ int f_r; /* read space left for getc() */
+ int f_w; /* write space left for putc() */
+ long f_flags; /* flags, below */
+ short f_file; /* fileno, if Unix fd, else -1 */
+ struct smbuf f_bf; /* the buffer (>= 1 byte, if !NULL) */
+ int f_lbfsize; /* 0 or -bf.size, for inline putc */
+
+ /* These can be used for any purpose by a file type implementation: */
+ void *f_cookie;
+ int f_ival;
+
+ /* operations */
+ int (*f_close) __P((SM_FILE_T *));
+ ssize_t (*f_read) __P((SM_FILE_T *, char *, size_t));
+ off_t (*f_seek) __P((SM_FILE_T *, off_t, int));
+ ssize_t (*f_write) __P((SM_FILE_T *, const char *, size_t));
+ int (*f_open) __P((SM_FILE_T *, const void *, int,
+ const void *));
+ int (*f_setinfo) __P((SM_FILE_T *, int , void *));
+ int (*f_getinfo) __P((SM_FILE_T *, int , void *));
+ int f_timeout;
+ int f_timeoutstate; /* either blocking or non-blocking */
+ char *f_type; /* for by-type lookups */
+ void *f_self; /* self for reference */
+ struct sm_file *f_flushfp; /* flush this before reading parent */
+ struct sm_file *f_modefp; /* sync mode with this fp */
+
+ /* separate buffer for long sequences of ungetc() */
+ struct smbuf f_ub; /* ungetc buffer */
+ unsigned char *f_up; /* saved f_p when f_p is doing ungetc */
+ int f_ur; /* saved f_r when f_r is counting ungetc */
+
+ /* tricks to meet minimum requirements even when malloc() fails */
+ unsigned char f_ubuf[3]; /* guarantee an ungetc() buffer */
+ unsigned char f_nbuf[1]; /* guarantee a getc() buffer */
+
+ /* separate buffer for fgetln() when line crosses buffer boundary */
+ struct smbuf f_lb; /* buffer for fgetln() */
+
+ /* Unix stdio files get aligned to block boundaries on fseek() */
+ int f_blksize; /* stat.st_blksize (may be != bf.size) */
+ off_t f_lseekoff; /* current lseek offset */
+ int f_dup_cnt; /* count file dup'd */
+};
+
+__BEGIN_DECLS
+extern SM_FILE_T SmIoF[];
+extern const char SmFileMagic[];
+extern SM_FILE_T SmFtStdio_def;
+extern SM_FILE_T SmFtStdiofd_def;
+extern SM_FILE_T SmFtString_def;
+extern SM_FILE_T SmFtSyslog_def;
+extern SM_FILE_T SmFtRealStdio_def;
+
+#define SMIOIN_FILENO 0
+#define SMIOOUT_FILENO 1
+#define SMIOERR_FILENO 2
+#define SMIOSTDIN_FILENO 3
+#define SMIOSTDOUT_FILENO 4
+#define SMIOSTDERR_FILENO 5
+
+/* Common predefined and already (usually) open files (exposed) */
+#define smioin (&SmIoF[SMIOIN_FILENO])
+#define smioout (&SmIoF[SMIOOUT_FILENO])
+#define smioerr (&SmIoF[SMIOERR_FILENO])
+#define smiostdin (&SmIoF[SMIOSTDIN_FILENO])
+#define smiostdout (&SmIoF[SMIOSTDOUT_FILENO])
+#define smiostderr (&SmIoF[SMIOSTDERR_FILENO])
+
+#define SmFtStdio (&SmFtStdio_def)
+#define SmFtStdiofd (&SmFtStdiofd_def)
+#define SmFtString (&SmFtString_def)
+#define SmFtSyslog (&SmFtSyslog_def)
+#define SmFtRealStdio (&SmFtRealStdio_def)
+
+#ifdef __STDC__
+# define SM_IO_SET_TYPE(f, name, open, close, read, write, seek, get, set, timeout) \
+ (f) = {SmFileMagic, (unsigned char *) 0, 0, 0, 0L, -1, {0}, 0, (void *) 0,\
+ 0, (close), (read), (seek), (write), (open), (set), (get), (timeout),\
+ 0, (name)}
+# define SM_IO_INIT_TYPE(f, name, open, close, read, write, seek, get, set, timeout)
+
+#else /* __STDC__ */
+# define SM_IO_SET_TYPE(f, name, open, close, read, write, seek, get, set, timeout) (f)
+# define SM_IO_INIT_TYPE(f, name, open, close, read, write, seek, get, set, timeout) \
+ (f).sm_magic = SmFileMagic; \
+ (f).f_p = (unsigned char *) 0; \
+ (f).f_r = 0; \
+ (f).f_w = 0; \
+ (f).f_flags = 0L; \
+ (f).f_file = 0; \
+ (f).f_bf.smb_base = (unsigned char *) 0; \
+ (f).f_bf.smb_size = 0; \
+ (f).f_lbfsize = 0; \
+ (f).f_cookie = (void *) 0; \
+ (f).f_ival = 0; \
+ (f).f_close = (close); \
+ (f).f_read = (read); \
+ (f).f_seek = (seek); \
+ (f).f_write = (write); \
+ (f).f_open = (open); \
+ (f).f_setinfo = (set); \
+ (f).f_getinfo = (get); \
+ (f).f_timeout = (timeout); \
+ (f).f_timeoutstate = 0; \
+ (f).f_type = (name);
+
+#endif /* __STDC__ */
+
+__END_DECLS
+
+/* Internal flags */
+#define SMFBF 0x000001 /* XXXX fully buffered */
+#define SMLBF 0x000002 /* line buffered */
+#define SMNBF 0x000004 /* unbuffered */
+#define SMNOW 0x000008 /* Flush each write; take read now */
+#define SMRD 0x000010 /* OK to read */
+#define SMWR 0x000020 /* OK to write */
+ /* RD and WR are never simultaneously asserted */
+#define SMRW 0x000040 /* open for reading & writing */
+#define SMFEOF 0x000080 /* found EOF */
+#define SMERR 0x000100 /* found error */
+#define SMMBF 0x000200 /* buf is from malloc */
+#define SMAPP 0x000400 /* fdopen()ed in append mode */
+#define SMSTR 0x000800 /* this is an snprintf string */
+#define SMOPT 0x001000 /* do fseek() optimisation */
+#define SMNPT 0x002000 /* do not do fseek() optimisation */
+#define SMOFF 0x004000 /* set iff offset is in fact correct */
+#define SMALC 0x010000 /* allocate string space dynamically */
+
+#define SMACCESSMASK 0x0070
+#define SMMODEMASK 0x011C
+
+/* defines for timeout constants */
+#define SM_TIME_IMMEDIATE (0)
+#define SM_TIME_FOREVER (-1)
+#define SM_TIME_DEFAULT (-2)
+
+/* timeout state for blocking */
+#define SM_TIME_BLOCK (0) /* XXX just bool? */
+#define SM_TIME_NONBLOCK (1)
+
+/* Exposed buffering type flags */
+#define SM_IO_FBF 0 /* setvbuf should set fully buffered */
+#define SM_IO_LBF 1 /* setvbuf should set line buffered */
+#define SM_IO_NBF 2 /* setvbuf should set unbuffered */
+
+/* setvbuf buffered, but through at lower file type layers */
+#define SM_IO_NOW 3
+
+/*
+** size of buffer used by setbuf.
+** If underlying filesystem blocksize is discoverable that is used instead
+*/
+
+#define SM_IO_BUFSIZ 4096
+
+#define SM_IO_EOF (-1)
+
+/* Functions defined in ANSI C standard. */
+__BEGIN_DECLS
+SM_FILE_T *sm_io_autoflush __P((SM_FILE_T *, SM_FILE_T *));
+void sm_io_automode __P((SM_FILE_T *, SM_FILE_T *));
+void sm_io_clearerr __P((SM_FILE_T *));
+int sm_io_close __P((SM_FILE_T *, int SM_NONVOLATILE));
+SM_FILE_T *sm_io_dup __P((SM_FILE_T *));
+int sm_io_eof __P((SM_FILE_T *));
+int sm_io_error __P((SM_FILE_T *));
+char *sm_io_fgets __P((SM_FILE_T *, int, char *, int));
+int sm_io_flush __P((SM_FILE_T *, int SM_NONVOLATILE));
+
+int PRINTFLIKE(3, 4)
+sm_io_fprintf __P((SM_FILE_T *, int, const char *, ...));
+
+int sm_io_fputs __P((SM_FILE_T *, int, const char *));
+
+int SCANFLIKE(3, 4)
+sm_io_fscanf __P((SM_FILE_T *, int, const char *, ...));
+
+int sm_io_getc __P((SM_FILE_T *, int));
+int sm_io_getinfo __P((SM_FILE_T *, int, void *));
+SM_FILE_T *sm_io_open __P((const SM_FILE_T *, int SM_NONVOLATILE, const void *,
+ int, const void *));
+int sm_io_purge __P((SM_FILE_T *));
+int sm_io_putc __P((SM_FILE_T *, int, int));
+size_t sm_io_read __P((SM_FILE_T *, int, void *, size_t));
+SM_FILE_T *sm_io_reopen __P((const SM_FILE_T *, int SM_NONVOLATILE,
+ const void *, int, const void *, SM_FILE_T *));
+void sm_io_rewind __P((SM_FILE_T *, int));
+int sm_io_seek __P((SM_FILE_T *, int SM_NONVOLATILE, long SM_NONVOLATILE,
+ int SM_NONVOLATILE));
+int sm_io_setinfo __P((SM_FILE_T *, int, void *));
+int sm_io_setvbuf __P((SM_FILE_T *, int, char *, int, size_t));
+
+int SCANFLIKE(2, 3)
+sm_io_sscanf __P((const char *, char const *, ...));
+
+long sm_io_tell __P((SM_FILE_T *, int SM_NONVOLATILE));
+int sm_io_ungetc __P((SM_FILE_T *, int, int));
+int sm_io_vfprintf __P((SM_FILE_T *, int, const char *, va_list));
+size_t sm_io_write __P((SM_FILE_T *, int, const void *, size_t));
+
+void sm_strio_init __P((SM_FILE_T *, char *, size_t));
+
+extern SM_FILE_T *
+sm_io_fopen __P((
+ char *_pathname,
+ int _flags,
+ ...));
+
+extern SM_FILE_T *
+sm_io_stdioopen __P((
+ FILE *_stream,
+ char *_mode));
+
+extern int
+sm_vasprintf __P((
+ char **_str,
+ const char *_fmt,
+ va_list _ap));
+
+extern int
+sm_vsnprintf __P((
+ char *,
+ size_t,
+ const char *,
+ va_list));
+
+extern void
+sm_perror __P((
+ const char *));
+
+__END_DECLS
+
+/*
+** Functions internal to the implementation.
+*/
+
+__BEGIN_DECLS
+int sm_rget __P((SM_FILE_T *, int));
+int sm_vfscanf __P((SM_FILE_T *, int SM_NONVOLATILE, const char *,
+ va_list SM_NONVOLATILE));
+int sm_wbuf __P((SM_FILE_T *, int, int));
+__END_DECLS
+
+/*
+** The macros are here so that we can
+** define function versions in the library.
+*/
+
+#define sm_getc(f, t) \
+ (--(f)->f_r < 0 ? \
+ sm_rget(f, t) : \
+ (int)(*(f)->f_p++))
+
+/*
+** This has been tuned to generate reasonable code on the vax using pcc.
+** (It also generates reasonable x86 code using gcc.)
+*/
+
+#define sm_putc(f, t, c) \
+ (--(f)->f_w < 0 ? \
+ (f)->f_w >= (f)->f_lbfsize ? \
+ (*(f)->f_p = (c)), *(f)->f_p != '\n' ? \
+ (int)*(f)->f_p++ : \
+ sm_wbuf(f, t, '\n') : \
+ sm_wbuf(f, t, (int)(c)) : \
+ (*(f)->f_p = (c), (int)*(f)->f_p++))
+
+#define sm_eof(p) (((p)->f_flags & SMFEOF) != 0)
+#define sm_error(p) (((p)->f_flags & SMERR) != 0)
+#define sm_clearerr(p) ((void)((p)->f_flags &= ~(SMERR|SMFEOF)))
+
+#define sm_io_eof(p) sm_eof(p)
+#define sm_io_error(p) sm_error(p)
+
+#define sm_io_clearerr(p) sm_clearerr(p)
+
+#ifndef lint
+# ifndef _POSIX_SOURCE
+# define sm_io_getc(fp, t) sm_getc(fp, t)
+# define sm_io_putc(fp, t, x) sm_putc(fp, t, x)
+# endif /* _POSIX_SOURCE */
+#endif /* lint */
+
+#endif /* SM_IO_H */
diff --git a/contrib/sendmail/include/sm/ldap.h b/contrib/sendmail/include/sm/ldap.h
new file mode 100644
index 0000000..7deec8b
--- /dev/null
+++ b/contrib/sendmail/include/sm/ldap.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: ldap.h,v 1.9 2002/01/11 22:06:50 gshapiro Exp $
+ */
+
+#ifndef SM_LDAP_H
+# define SM_LDAP_H
+
+# include <sm/conf.h>
+# include <sm/rpool.h>
+
+# ifndef LDAPMAP_MAX_ATTR
+# define LDAPMAP_MAX_ATTR 64
+# endif /* ! LDAPMAP_MAX_ATTR */
+# ifndef LDAPMAP_MAX_FILTER
+# define LDAPMAP_MAX_FILTER 1024
+# endif /* ! LDAPMAP_MAX_FILTER */
+# ifndef LDAPMAP_MAX_PASSWD
+# define LDAPMAP_MAX_PASSWD 256
+# endif /* ! LDAPMAP_MAX_PASSWD */
+
+# if LDAPMAP
+
+# if _FFR_LDAP_RECURSION
+
+/* Attribute types */
+# define LDAPMAP_ATTR_NORMAL 0
+# define LDAPMAP_ATTR_DN 1
+# define LDAPMAP_ATTR_FILTER 2
+# define LDAPMAP_ATTR_URL 3
+# define LDAPMAP_ATTR_FINAL 4
+
+/* sm_ldap_results() flags */
+# define SM_LDAP_SINGLEMATCH 0x0001
+# define SM_LDAP_MATCHONLY 0x0002
+# endif /* _FFR_LDAP_RECURSION */
+
+struct sm_ldap_struct
+{
+ /* needed for ldap_open or ldap_init */
+ char *ldap_host;
+ int ldap_port;
+ pid_t ldap_pid;
+
+ /* options set in ld struct before ldap_bind_s */
+ int ldap_deref;
+ time_t ldap_timelimit;
+ int ldap_sizelimit;
+ int ldap_options;
+
+ /* args for ldap_bind_s */
+ LDAP *ldap_ld;
+ char *ldap_binddn;
+ char *ldap_secret;
+ int ldap_method;
+
+ /* args for ldap_search */
+ char *ldap_base;
+ int ldap_scope;
+ char *ldap_filter;
+ char *ldap_attr[LDAPMAP_MAX_ATTR + 1];
+# if _FFR_LDAP_RECURSION
+ int ldap_attr_type[LDAPMAP_MAX_ATTR + 1];
+ char *ldap_attr_final[LDAPMAP_MAX_ATTR + 1];
+# endif /* _FFR_LDAP_RECURSION */
+ bool ldap_attrsonly;
+
+ /* args for ldap_result */
+ struct timeval ldap_timeout;
+ LDAPMessage *ldap_res;
+
+ /* ldapmap_lookup options */
+ char ldap_attrsep;
+
+ /* Linked list of maps sharing the same LDAP binding */
+ void *ldap_next;
+};
+
+typedef struct sm_ldap_struct SM_LDAP_STRUCT;
+
+# if _FFR_LDAP_RECURSION
+struct sm_ldap_recurse_list
+{
+ char *lr_search;
+ int lr_type;
+ struct sm_ldap_recurse_list *lr_next;
+};
+
+typedef struct sm_ldap_recurse_list SM_LDAP_RECURSE_LIST;
+# endif /* _FFR_LDAP_RECURSION */
+
+/* functions */
+extern void sm_ldap_clear __P((SM_LDAP_STRUCT *));
+extern bool sm_ldap_start __P((char *, SM_LDAP_STRUCT *));
+extern int sm_ldap_search __P((SM_LDAP_STRUCT *, char *));
+# if _FFR_LDAP_RECURSION
+extern int sm_ldap_results __P((SM_LDAP_STRUCT *, int, int, char,
+ SM_RPOOL_T *, char **,
+ SM_LDAP_RECURSE_LIST *));
+# endif /* _FFR_LDAP_RECURSION */
+extern void sm_ldap_setopts __P((LDAP *, SM_LDAP_STRUCT *));
+extern int sm_ldap_geterrno __P((LDAP *));
+extern void sm_ldap_close __P((SM_LDAP_STRUCT *));
+# endif /* LDAPMAP */
+
+#endif /* ! SM_LDAP_H */
diff --git a/contrib/sendmail/include/sm/limits.h b/contrib/sendmail/include/sm/limits.h
new file mode 100644
index 0000000..5041db3
--- /dev/null
+++ b/contrib/sendmail/include/sm/limits.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: limits.h,v 1.6 2001/03/08 03:23:08 ca Exp $
+ */
+
+/*
+** <sm/limits.h>
+** This header file is a portability wrapper for <limits.h>.
+** It includes <limits.h>, then it ensures that the following macros
+** from the C 1999 standard for <limits.h> are defined:
+** LLONG_MIN, LLONG_MAX
+** ULLONG_MAX
+*/
+
+#ifndef SM_LIMITS_H
+# define SM_LIMITS_H
+
+# include <limits.h>
+# include <sm/types.h>
+# include <sys/param.h>
+
+/*
+** The following assumes two's complement binary arithmetic.
+*/
+
+# ifndef LLONG_MIN
+# define LLONG_MIN ((LONGLONG_T)(~(ULLONG_MAX >> 1)))
+# endif /* ! LLONG_MIN */
+# ifndef LLONG_MAX
+# define LLONG_MAX ((LONGLONG_T)(ULLONG_MAX >> 1))
+# endif /* ! LLONG_MAX */
+# ifndef ULLONG_MAX
+# define ULLONG_MAX ((ULONGLONG_T)(-1))
+# endif /* ! ULLONG_MAX */
+
+/*
+** PATH_MAX is defined by the POSIX standard. All modern systems
+** provide it. Older systems define MAXPATHLEN in <sys/param.h> instead.
+*/
+
+# ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else /* MAXPATHLEN */
+# define PATH_MAX 2048
+# endif /* MAXPATHLEN */
+# endif /* ! PATH_MAX */
+
+#endif /* ! SM_LIMITS_H */
diff --git a/contrib/sendmail/include/sm/mbdb.h b/contrib/sendmail/include/sm/mbdb.h
new file mode 100644
index 0000000..7ec71c5
--- /dev/null
+++ b/contrib/sendmail/include/sm/mbdb.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: mbdb.h,v 1.4 2001/03/08 03:23:08 ca Exp $
+ */
+
+#ifndef SM_MBDB_H
+# define SM_MBDB_H
+
+#include <pwd.h>
+#include <sm/types.h>
+#include <sm/limits.h>
+
+/*
+** This is an abstract interface for looking up local mail recipients.
+*/
+
+#define MBDB_MAXNAME 256
+#define SM_NO_UID ((uid_t)(-1))
+#define SM_NO_GID ((gid_t)(-1))
+
+typedef struct
+{
+ uid_t mbdb_uid;
+ gid_t mbdb_gid;
+ char mbdb_name[MBDB_MAXNAME];
+ char mbdb_fullname[MBDB_MAXNAME];
+ char mbdb_homedir[PATH_MAX + 1];
+ char mbdb_shell[PATH_MAX + 1];
+} SM_MBDB_T;
+
+extern int sm_mbdb_initialize __P((char *));
+extern void sm_mbdb_terminate __P((void));
+extern int sm_mbdb_lookup __P((char *, SM_MBDB_T *));
+extern void sm_mbdb_frompw __P((SM_MBDB_T *, struct passwd *));
+extern void sm_pwfullname __P((char *, char *, char *, size_t));
+
+#endif /* ! SM_MBDB_H */
diff --git a/contrib/sendmail/include/sm/os/sm_os_aix.h b/contrib/sendmail/include/sm/os/sm_os_aix.h
new file mode 100644
index 0000000..6dc4a54
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_aix.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_aix.h,v 1.9 2001/10/09 23:12:13 ca Exp $
+ */
+
+/*
+** sm_os_aix.h -- platform definitions for AIX
+*/
+
+#define SM_OS_NAME "aix"
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 2
+#endif /* SM_CONF_SEM */
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
+
+/* AIX 3 doesn't have a prototype for syslog()? */
+#ifdef _AIX3
+# ifndef _AIX4
+# ifndef SM_CONF_SYSLOG
+# define SM_CONF_SYSLOG 0
+# endif /* SM_CONF_SYSLOG */
+# endif /* ! _AIX4 */
+#endif /* _AIX3 */
diff --git a/contrib/sendmail/include/sm/os/sm_os_freebsd.h b/contrib/sendmail/include/sm/os/sm_os_freebsd.h
new file mode 100644
index 0000000..8edc718
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_freebsd.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_freebsd.h,v 1.9 2001/06/27 21:46:48 gshapiro Exp $
+ */
+
+/*
+** Platform definitions for FreeBSD
+*/
+
+#define SM_OS_NAME "freebsd"
+
+#define SM_CONF_SYS_CDEFS_H 1
+
+#if __FreeBSD__ >= 2
+# include <osreldate.h> /* defines __FreeBSD_version */
+# if __FreeBSD_version >= 199512 /* 2.2-current when it appeared */
+# define MI_SOMAXCONN -1 /* listen() max backlog for milter */
+# endif /* __FreeBSD_version >= 199512 */
+# if __FreeBSD_version >= 330000
+ /* 3.3.0-release and later have strlcpy()/strlcat() */
+# ifndef SM_CONF_STRL
+# define SM_CONF_STRL 1
+# endif
+# endif
+#endif
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 1
+#endif /* SM_CONF_SEM */
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
diff --git a/contrib/sendmail/include/sm/os/sm_os_hp.h b/contrib/sendmail/include/sm/os/sm_os_hp.h
new file mode 100644
index 0000000..2cbcb57
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_hp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_hp.h,v 1.8 2001/10/31 15:36:56 ca Exp $
+ */
+
+/*
+** sm_os_hp.h -- platform definitions for HP
+*/
+
+#define SM_OS_NAME "hp"
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 2
+#endif /* SM_CONF_SEM */
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
+
+/* max/min buffer size of other than regular files */
+#ifndef SM_IO_MAX_BUF
+# define SM_IO_MAX_BUF 8192
+#endif /* SM_IO_MAX_BUF */
+#ifndef SM_IO_MIN_BUF
+# define SM_IO_MIN_BUF 4096
+#endif /* SM_IO_MIN_BUF */
diff --git a/contrib/sendmail/include/sm/os/sm_os_irix.h b/contrib/sendmail/include/sm/os/sm_os_irix.h
new file mode 100644
index 0000000..185485a
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_irix.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_irix.h,v 1.7 2001/10/09 23:12:13 ca Exp $
+ */
+
+/*
+** Silicon Graphics IRIX
+**
+** Compiles on 4.0.1.
+**
+** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0).
+** Use IRIX5 instead of IRIX for IRIX 5.x.
+**
+** This version tries to be adaptive using _MIPS_SIM:
+** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2
+** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2
+** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2
+**
+** _MIPS_SIM is 1 also on IRIX 5.3
+**
+** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>.
+** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
+** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
+*/
+
+#ifndef IRIX
+# define IRIX
+#endif /* ! IRIX */
+#if _MIPS_SIM > 0 && !defined(IRIX5)
+# define IRIX5 /* IRIX5 or IRIX6 */
+#endif /* _MIPS_SIM > 0 && !defined(IRIX5) */
+#if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64)
+# define IRIX6 /* IRIX6 */
+#endif /* _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64) */
+
+#define SM_OS_NAME "irix"
+
+#if defined(IRIX6) || defined(IRIX64)
+# define SM_CONF_LONGLONG 1
+#endif /* defined(IRIX6) || defined(IRIX64) */
+
+#if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
+# define SM_CONF_SYS_CDEFS_H 1
+#endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+
+/* try LLONG tests in libsm/t-types.c? */
+#ifndef SM_CONF_TEST_LLONG
+# define SM_CONF_TEST_LLONG 0
+#endif /* !SM_CONF_TEST_LLONG */
diff --git a/contrib/sendmail/include/sm/os/sm_os_linux.h b/contrib/sendmail/include/sm/os/sm_os_linux.h
new file mode 100644
index 0000000..f232c49
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_linux.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_linux.h,v 1.12 2001/10/05 01:52:41 ca Exp $
+ */
+
+/*
+** Platform definitions for Linux
+*/
+
+#define SM_OS_NAME "linux"
+
+/* to get version number */
+#include <linux/version.h>
+
+# if !defined(KERNEL_VERSION) /* not defined in 2.0.x kernel series */
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+# endif /* ! KERNEL_VERSION */
+
+/* doesn't seem to work on Linux */
+#ifndef SM_CONF_SETITIMER
+# define SM_CONF_SETITIMER 0
+#endif /* SM_CONF_SETITIMER */
+
+#ifndef SM_CONF_SHM
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,19))
+# define SM_CONF_SHM 1
+# endif /* LINUX_VERSION_CODE */
+#endif /* SM_CONF_SHM */
+
+#define SM_CONF_SYS_CDEFS_H 1
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 2
+#endif /* SM_CONF_SEM */
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
diff --git a/contrib/sendmail/include/sm/os/sm_os_mpeix.h b/contrib/sendmail/include/sm/os/sm_os_mpeix.h
new file mode 100644
index 0000000..385f1f4
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_mpeix.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_mpeix.h,v 1.2 2001/12/14 00:23:02 ca Exp $
+ */
+
+/*
+** sm_os_mpeix.h -- platform definitions for HP MPE/iX
+*/
+
+#define SM_OS_NAME "mpeix"
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 2
+#endif /* SM_CONF_SEM */
+
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
+
+#define SM_CONF_SETITIMER 0
+
+#ifndef SM_CONF_CANT_SETRGID
+# define SM_CONF_CANT_SETRGID 1
+#endif /* SM_CONF_CANT_SETRGID */
diff --git a/contrib/sendmail/include/sm/os/sm_os_next.h b/contrib/sendmail/include/sm/os/sm_os_next.h
new file mode 100644
index 0000000..03f886e
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_next.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_next.h,v 1.7 2001/04/03 01:53:06 gshapiro Exp $
+ */
+
+/*
+** Platform definitions for NeXT
+*/
+
+#define SM_OS_NAME "next"
+
+#define SM_CONF_SIGSETJMP 0
+#define SM_CONF_SSIZE_T 0
+#define SM_CONF_FORMAT_TEST 0
+
+/* doesn't seem to work on NeXT 3.x */
+#define SM_DEAD(proto) proto
+#define SM_UNUSED(decl) decl
+
+/* try LLONG tests in libsm/t-types.c? */
+#ifndef SM_CONF_TEST_LLONG
+# define SM_CONF_TEST_LLONG 0
+#endif /* !SM_CONF_TEST_LLONG */
diff --git a/contrib/sendmail/include/sm/os/sm_os_openbsd.h b/contrib/sendmail/include/sm/os/sm_os_openbsd.h
new file mode 100644
index 0000000..1acf12d
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_openbsd.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_openbsd.h,v 1.7 2000/12/05 19:00:47 dmoen Exp $
+ */
+
+/*
+** sm_os_openbsd.h -- platform definitions for OpenBSD
+**
+** Note: this header file cannot be called OpenBSD.h
+** because <sys/param.h> defines the macro OpenBSD.
+*/
+
+#define SM_OS_NAME "openbsd"
+
+#define SM_CONF_SYS_CDEFS_H 1
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+#ifndef SM_CONF_SEM
+# define SM_CONF_SEM 1
+#endif /* SM_CONF_SEM */
+#ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+#endif /* SM_CONF_MSG */
diff --git a/contrib/sendmail/include/sm/os/sm_os_openunix.h b/contrib/sendmail/include/sm/os/sm_os_openunix.h
new file mode 100644
index 0000000..3e696ba
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_openunix.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_openunix.h,v 1.5 2001/11/11 16:32:00 ca Exp $
+ */
+
+#define SM_OS_NAME "openunix"
+
+/* needs alarm(), our sleep() otherwise hangs. */
+#define SM_CONF_SETITIMER 0
+
+/* long long seems to work */
+#define SM_CONF_LONGLONG 1
+
+/* don't use flock() in mail.local.c */
+#define LDA_USE_LOCKF 1
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
diff --git a/contrib/sendmail/include/sm/os/sm_os_osf1.h b/contrib/sendmail/include/sm/os/sm_os_osf1.h
new file mode 100644
index 0000000..eef239c
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_osf1.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_osf1.h,v 1.3 2001/10/09 23:12:13 ca Exp $
+ */
+
+/*
+** platform definitions for Digital UNIX
+*/
+
+#define SM_OS_NAME "osf1"
+
+#define SM_CONF_SETITIMER 0
diff --git a/contrib/sendmail/include/sm/os/sm_os_sunos.h b/contrib/sendmail/include/sm/os/sm_os_sunos.h
new file mode 100644
index 0000000..9d20b18
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_sunos.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_sunos.h,v 1.14 2001/08/14 18:09:42 ca Exp $
+ */
+
+/*
+** platform definitions for SunOS 4.0.3, SunOS 4.1.x and Solaris 2.x
+*/
+
+#define SM_OS_NAME "sunos"
+
+#ifdef SOLARIS
+/*
+** Solaris 2.x (aka SunOS 5.x)
+** M4 config file is devtools/OS/SunOS.5.x, which defines the SOLARIS macro.
+*/
+
+# define SM_CONF_LONGLONG 1
+# ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+# endif /* SM_CONF_SHM */
+# ifndef SM_CONF_SEM
+# define SM_CONF_SEM 2
+# endif /* SM_CONF_SEM */
+# ifndef SM_CONF_MSG
+# define SM_CONF_MSG 1
+# endif /* SM_CONF_MSG */
+
+#else /* SOLARIS */
+
+/*
+** SunOS 4.0.3 or 4.1.x
+*/
+
+# define SM_CONF_SSIZE_T 0
+# ifndef SM_CONF_BROKEN_SIZE_T
+# define SM_CONF_BROKEN_SIZE_T 1 /* size_t is signed? */
+# endif /* SM_CONF_BROKEN_SIZE_T */
+
+# ifndef SM_CONF_BROKEN_STRTOD
+# define SM_CONF_BROKEN_STRTOD 1
+# endif /* ! SM_CONF_BROKEN_STRTOD */
+
+/* has memchr() prototype? (if not: needs memory.h) */
+# ifndef SM_CONF_MEMCHR
+# define SM_CONF_MEMCHR 0
+# endif /* ! SM_CONF_MEMCHR */
+
+# ifdef SUNOS403
+
+/*
+** SunOS 4.0.3
+** M4 config file is devtools/OS/SunOS4.0, which defines the SUNOS403 macro.
+*/
+
+# else /* SUNOS403 */
+
+/*
+** SunOS 4.1.x
+** M4 config file is devtools/OS/SunOS, which defines no macros.
+*/
+
+# endif /* SUNOS403 */
+#endif /* SOLARIS */
diff --git a/contrib/sendmail/include/sm/os/sm_os_ultrix.h b/contrib/sendmail/include/sm/os/sm_os_ultrix.h
new file mode 100644
index 0000000..1ae2db1
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_ultrix.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_ultrix.h,v 1.3 2001/10/09 23:12:13 ca Exp $
+ */
+
+/*
+** platform definitions for Ultrix
+*/
+
+#define SM_OS_NAME "ultrix"
+
+#define SM_CONF_SSIZE_T 0
diff --git a/contrib/sendmail/include/sm/os/sm_os_unixware.h b/contrib/sendmail/include/sm/os/sm_os_unixware.h
new file mode 100644
index 0000000..2ff5ad0
--- /dev/null
+++ b/contrib/sendmail/include/sm/os/sm_os_unixware.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sm_os_unixware.h,v 1.7 2001/11/11 16:32:00 ca Exp $
+ */
+
+#define SM_OS_NAME "unixware"
+
+/* try LLONG tests in libsm/t-types.c? */
+#ifndef SM_CONF_TEST_LLONG
+# define SM_CONF_TEST_LLONG 0
+#endif /* !SM_CONF_TEST_LLONG */
+
+/* needs alarm(), our sleep() otherwise hangs. */
+#define SM_CONF_SETITIMER 0
+
+#ifndef SM_CONF_SHM
+# define SM_CONF_SHM 1
+#endif /* SM_CONF_SHM */
+
+/* size_t seems to be signed */
+#define SM_CONF_BROKEN_SIZE_T 1
+
+/* don't use flock() in mail.local.c */
+#ifndef LDA_USE_LOCKF
+# define LDA_USE_LOCKF 1
+#endif /* LDA_USE_LOCKF */
diff --git a/contrib/sendmail/include/sm/path.h b/contrib/sendmail/include/sm/path.h
new file mode 100644
index 0000000..29fc4ca
--- /dev/null
+++ b/contrib/sendmail/include/sm/path.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: path.h,v 1.6 2001/04/03 01:53:00 gshapiro Exp $
+ */
+
+/*
+** Portable names for standard filesystem paths
+** and macros for directories.
+*/
+
+#ifndef SM_PATH_H
+# define SM_PATH_H
+
+# include <sm/gen.h>
+
+# define SM_PATH_DEVNULL "/dev/null"
+# define SM_IS_DIR_DELIM(c) ((c) == '/')
+# define SM_FIRST_DIR_DELIM(s) strchr(s, '/')
+# define SM_LAST_DIR_DELIM(s) strrchr(s, '/')
+
+/* Warning: this must be accessible as array */
+# define SM_IS_DIR_START(s) ((s)[0] == '/')
+
+# define sm_path_isdevnull(path) (strcmp(path, "/dev/null") == 0)
+
+#endif /* ! SM_PATH_H */
diff --git a/contrib/sendmail/include/sm/rpool.h b/contrib/sendmail/include/sm/rpool.h
new file mode 100644
index 0000000..e750fcb
--- /dev/null
+++ b/contrib/sendmail/include/sm/rpool.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: rpool.h,v 1.15 2001/09/04 22:41:55 ca Exp $
+ */
+
+/*
+** libsm resource pools
+** See libsm/rpool.html for documentation.
+*/
+
+#ifndef SM_RPOOL_H
+# define SM_RPOOL_H
+
+# include <sm/gen.h>
+# include <sm/heap.h>
+# include <sm/string.h>
+
+/*
+** Each memory pool object consists of an SM_POOLLINK_T,
+** followed by a platform specific amount of padding,
+** followed by 'poolsize' bytes of pool data,
+** where 'poolsize' is the value of rpool->sm_poolsize at the time
+** the pool is allocated.
+*/
+
+typedef struct sm_poollink SM_POOLLINK_T;
+struct sm_poollink
+{
+ SM_POOLLINK_T *sm_pnext;
+};
+
+typedef void (*SM_RPOOL_RFREE_T) __P((void *_rcontext));
+
+typedef SM_RPOOL_RFREE_T *SM_RPOOL_ATTACH_T;
+
+typedef struct sm_resource SM_RESOURCE_T;
+struct sm_resource
+{
+ /*
+ ** Function for freeing this resource. It may be NULL,
+ ** meaning that this resource has already been freed.
+ */
+
+ SM_RPOOL_RFREE_T sm_rfree;
+ void *sm_rcontext; /* resource data */
+};
+
+# define SM_RLIST_MAX 511
+
+typedef struct sm_rlist SM_RLIST_T;
+struct sm_rlist
+{
+ SM_RESOURCE_T sm_rvec[SM_RLIST_MAX];
+ SM_RLIST_T *sm_rnext;
+};
+
+typedef struct
+{
+ /* Points to SmRpoolMagic, or is NULL if rpool is freed. */
+ const char *sm_magic;
+
+ /*
+ ** If this rpool object has no parent, then sm_parentlink
+ ** is NULL. Otherwise, we set *sm_parentlink = NULL
+ ** when this rpool is freed, so that it isn't freed a
+ ** second time when the parent is freed.
+ */
+
+ SM_RPOOL_RFREE_T *sm_parentlink;
+
+ /*
+ ** Memory pools
+ */
+
+ /* Size of the next pool to be allocated, not including the header. */
+ size_t sm_poolsize;
+
+ /*
+ ** If an sm_rpool_malloc_x request is too big to fit
+ ** in the current pool, and the request size > bigobjectsize,
+ ** then the object will be given its own malloc'ed block.
+ ** sm_bigobjectsize <= sm_poolsize. The maximum wasted space
+ ** at the end of a pool is maxpooledobjectsize - 1.
+ */
+
+ size_t sm_bigobjectsize;
+
+ /* Points to next free byte in the current pool. */
+ char *sm_poolptr;
+
+ /*
+ ** Number of bytes available in the current pool.
+ ** Initially 0. Set to 0 by sm_rpool_free.
+ */
+
+ size_t sm_poolavail;
+
+ /* Linked list of memory pools. Initially NULL. */
+ SM_POOLLINK_T *sm_pools;
+
+ /*
+ ** Resource lists
+ */
+
+ SM_RESOURCE_T *sm_rptr; /* Points to next free resource slot. */
+
+ /*
+ ** Number of available resource slots in current list.
+ ** Initially 0. Set to 0 by sm_rpool_free.
+ */
+
+ size_t sm_ravail;
+
+ /* Linked list of resource lists. Initially NULL. */
+ SM_RLIST_T *sm_rlists;
+
+#if _FFR_PERF_RPOOL
+ int sm_nbigblocks;
+ int sm_npools;
+#endif /* _FFR_PERF_RPOOL */
+
+} SM_RPOOL_T;
+
+extern SM_RPOOL_T *
+sm_rpool_new_x __P((
+ SM_RPOOL_T *_parent));
+
+extern void
+sm_rpool_free __P((
+ SM_RPOOL_T *_rpool));
+
+# if SM_HEAP_CHECK
+extern void *
+sm_rpool_malloc_tagged_x __P((
+ SM_RPOOL_T *_rpool,
+ size_t _size,
+ char *_file,
+ int _line,
+ int _group));
+# define sm_rpool_malloc_x(rpool, size) \
+ sm_rpool_malloc_tagged_x(rpool, size, __FILE__, __LINE__, SmHeapGroup)
+extern void *
+sm_rpool_malloc_tagged __P((
+ SM_RPOOL_T *_rpool,
+ size_t _size,
+ char *_file,
+ int _line,
+ int _group));
+# define sm_rpool_malloc(rpool, size) \
+ sm_rpool_malloc_tagged(rpool, size, __FILE__, __LINE__, SmHeapGroup)
+# else /* SM_HEAP_CHECK */
+extern void *
+sm_rpool_malloc_x __P((
+ SM_RPOOL_T *_rpool,
+ size_t _size));
+extern void *
+sm_rpool_malloc __P((
+ SM_RPOOL_T *_rpool,
+ size_t _size));
+# endif /* SM_HEAP_CHECK */
+
+# define sm_rpool_strdup_x(rpool, str) \
+ strcpy(sm_rpool_malloc_x(rpool, strlen(str) + 1), str)
+
+extern SM_RPOOL_ATTACH_T
+sm_rpool_attach_x __P((
+ SM_RPOOL_T *_rpool,
+ SM_RPOOL_RFREE_T _rfree,
+ void *_rcontext));
+
+# define sm_rpool_detach(a) ((void)(*(a) = NULL))
+
+extern void
+sm_rpool_setsizes __P((
+ SM_RPOOL_T *_rpool,
+ size_t _poolsize,
+ size_t _bigobjectsize));
+
+#endif /* ! SM_RPOOL_H */
diff --git a/contrib/sendmail/include/sm/setjmp.h b/contrib/sendmail/include/sm/setjmp.h
new file mode 100644
index 0000000..01bda02
--- /dev/null
+++ b/contrib/sendmail/include/sm/setjmp.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: setjmp.h,v 1.3 2001/03/08 03:23:08 ca Exp $
+ */
+
+#ifndef SM_SETJMP_H
+# define SM_SETJMP_H
+
+# include <sm/config.h>
+# include <setjmp.h>
+
+/*
+** sm_setjmp_sig is a setjmp that saves the signal mask.
+** sm_setjmp_nosig is a setjmp that does *not* save the signal mask.
+** SM_JMPBUF_T is used with both of the above macros.
+**
+** On most systems, these can be implemented using sigsetjmp.
+** Some old BSD systems do not have sigsetjmp, but they do have
+** setjmp and _setjmp, which are just as good.
+*/
+
+# if SM_CONF_SIGSETJMP
+
+typedef sigjmp_buf SM_JMPBUF_T;
+# define sm_setjmp_sig(buf) sigsetjmp(buf, 1)
+# define sm_setjmp_nosig(buf) sigsetjmp(buf, 0)
+# define sm_longjmp_sig(buf, val) siglongjmp(buf, val)
+# define sm_longjmp_nosig(buf, val) siglongjmp(buf, val)
+
+# else /* SM_CONF_SIGSETJMP */
+
+typedef jmp_buf SM_JMPBUF_T;
+# define sm_setjmp_sig(buf) setjmp(buf)
+# define sm_longjmp_sig(buf, val) longjmp(buf, val)
+# define sm_setjmp_nosig(buf) _setjmp(buf)
+# define sm_longjmp_nosig(buf, val) _longjmp(buf, val)
+
+# endif /* SM_CONF_SIGSETJMP */
+
+#endif /* ! SM_SETJMP_H */
diff --git a/contrib/sendmail/include/sm/shm.h b/contrib/sendmail/include/sm/shm.h
new file mode 100644
index 0000000..62ffe6e
--- /dev/null
+++ b/contrib/sendmail/include/sm/shm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: shm.h,v 1.7 2001/04/20 15:21:55 ca Exp $
+ */
+
+#ifndef SM_SHM_H
+# define SM_SHM_H
+
+# if SM_CONF_SHM
+# include <sys/types.h>
+# include <sys/ipc.h>
+# include <sys/shm.h>
+
+/* # include "def.h" */
+
+/* key for shared memory */
+# define SM_SHM_KEY ((key_t) 42)
+
+/* return value for failed shmget() */
+# define SM_SHM_NULL ((void *) -1)
+# define SM_SHM_NO_ID (-1)
+# define SM_NO_SHM(id) ((id) < 0)
+
+extern void *sm_shmstart __P((key_t, int , int , int *, bool));
+extern int sm_shmstop __P((void *, int, bool));
+
+/* for those braindead systems... (e.g., SunOS 4) */
+# ifndef SHM_R
+# define SHM_R 0400
+# endif /* SHM_R */
+# ifndef SHM_W
+# define SHM_W 0200
+# endif /* SHM_W */
+
+# endif /* SM_CONF_SHM */
+#endif /* ! SM_SHM_H */
diff --git a/contrib/sendmail/include/sm/signal.h b/contrib/sendmail/include/sm/signal.h
new file mode 100644
index 0000000..3821deb
--- /dev/null
+++ b/contrib/sendmail/include/sm/signal.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: signal.h,v 1.16 2001/07/20 19:48:21 gshapiro Exp $
+ */
+
+/*
+** SIGNAL.H -- libsm (and sendmail) signal facilities
+** Extracted from sendmail/conf.h and focusing
+** on signal configuration.
+*/
+
+#ifndef SM_SIGNAL_H
+#define SM_SIGNAL_H 1
+
+#include <sys/types.h>
+#include <limits.h>
+#include <signal.h>
+#include <sm/cdefs.h>
+#include <sm/conf.h>
+
+/*
+** Critical signal sections
+*/
+
+#define PEND_SIGHUP 0x0001
+#define PEND_SIGINT 0x0002
+#define PEND_SIGTERM 0x0004
+#define PEND_SIGUSR1 0x0008
+
+#define ENTER_CRITICAL() InCriticalSection++
+
+#define LEAVE_CRITICAL() \
+do \
+{ \
+ if (InCriticalSection > 0) \
+ InCriticalSection--; \
+} while (0)
+
+#define CHECK_CRITICAL(sig) \
+do \
+{ \
+ if (InCriticalSection > 0 && (sig) != 0) \
+ { \
+ pend_signal((sig)); \
+ return SIGFUNC_RETURN; \
+ } \
+} while (0)
+
+/* variables */
+extern unsigned int volatile InCriticalSection; /* >0 if in critical section */
+extern int volatile PendingSignal; /* pending signal to resend */
+
+/* functions */
+extern void pend_signal __P((int));
+
+/* reset signal in case System V semantics */
+#ifdef SYS5SIGNALS
+# define FIX_SYSV_SIGNAL(sig, handler) \
+{ \
+ if ((sig) != 0) \
+ (void) sm_signal((sig), (handler)); \
+}
+#else /* SYS5SIGNALS */
+# define FIX_SYSV_SIGNAL(sig, handler) { /* EMPTY */ }
+#endif /* SYS5SIGNALS */
+
+extern void sm_allsignals __P((bool));
+extern int sm_blocksignal __P((int));
+extern int sm_releasesignal __P((int));
+extern sigfunc_t sm_signal __P((int, sigfunc_t));
+extern SIGFUNC_DECL sm_signal_noop __P((int));
+#endif /* SM_SIGNAL_H */
diff --git a/contrib/sendmail/include/sm/string.h b/contrib/sendmail/include/sm/string.h
new file mode 100644
index 0000000..c8cb59f
--- /dev/null
+++ b/contrib/sendmail/include/sm/string.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: string.h,v 1.36 2001/06/17 21:31:11 ca Exp $
+ */
+
+/*
+** libsm string manipulation
+*/
+
+#ifndef SM_STRING_H
+# define SM_STRING_H
+
+# include <sm/gen.h>
+# include <sm/varargs.h>
+# include <string.h> /* strlc{py,at}, strerror */
+
+/* return number of bytes left in a buffer */
+#define SPACELEFT(buf, ptr) (sizeof buf - ((ptr) - buf))
+
+extern int PRINTFLIKE(3, 4)
+sm_snprintf __P((
+ char *,
+ size_t,
+ const char *,
+ ...));
+
+extern bool
+sm_match __P((
+ const char *_str,
+ const char *_pattern));
+
+extern char *
+sm_strdup __P((
+ char *));
+
+extern char *
+sm_strndup_x __P((
+ const char *_str,
+ size_t _len));
+
+/* for "normal" data (free'd before end of process) */
+# define sm_strdup_x(str) strcpy(sm_malloc_x(strlen(str) + 1), str)
+
+/* for data that is supposed to be persistent. */
+# define sm_pstrdup_x(str) strcpy(sm_pmalloc_x(strlen(str) + 1), str)
+
+# define sm_strdup_tagged_x(str, file, line, group) \
+ strcpy(sm_malloc_tagged_x(strlen(str) + 1, file, line, group), str)
+
+extern char *
+sm_stringf_x __P((
+ const char *_fmt,
+ ...));
+
+extern char *
+sm_vstringf_x __P((
+ const char *_fmt,
+ va_list _ap));
+
+extern size_t
+sm_strlcpy __P((
+ char *_dst,
+ const char *_src,
+ ssize_t _len));
+
+extern size_t
+sm_strlcat __P((
+ char *_dst,
+ const char *_src,
+ ssize_t _len));
+
+extern size_t
+sm_strlcat2 __P((
+ char *,
+ const char *,
+ const char *,
+ ssize_t));
+
+extern size_t
+#ifdef __STDC__
+sm_strlcpyn(char *dst, ssize_t len, int n, ...);
+#else /* __STDC__ */
+sm_strlcpyn __P((char *,
+ ssize_t,
+ int,
+ va_dcl));
+#endif /* __STDC__ */
+
+# if !HASSTRERROR
+extern char *
+strerror __P((
+ int _errno));
+# endif /* !HASSTRERROR */
+
+extern int
+sm_strrevcmp __P((
+ const char *,
+ const char *));
+
+extern int
+sm_strrevcasecmp __P((
+ const char *,
+ const char *));
+
+extern int
+sm_strcasecmp __P((
+ const char *,
+ const char *));
+
+extern int
+sm_strncasecmp __P((
+ const char *,
+ const char *,
+ size_t));
+
+extern LONGLONG_T
+sm_strtoll __P((
+ const char *,
+ char**, int));
+
+extern ULONGLONG_T
+sm_strtoull __P((
+ const char *,
+ char**, int));
+
+extern void
+stripquotes __P((char *));
+
+#endif /* SM_STRING_H */
diff --git a/contrib/sendmail/include/sm/sysexits.h b/contrib/sendmail/include/sm/sysexits.h
new file mode 100644
index 0000000..750def1
--- /dev/null
+++ b/contrib/sendmail/include/sm/sysexits.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: sysexits.h,v 1.5 2001/03/10 17:30:01 ca Exp $
+ * @(#)sysexits.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef SM_SYSEXITS_H
+# define SM_SYSEXITS_H
+
+# include <sm/gen.h>
+
+/*
+** SYSEXITS.H -- Exit status codes for system programs.
+**
+** This include file attempts to categorize possible error
+** exit statuses for system programs, notably delivermail
+** and the Berkeley network.
+**
+** Error numbers begin at EX__BASE to reduce the possibility of
+** clashing with other exit statuses that random programs may
+** already return. The meaning of the codes is approximately
+** as follows:
+**
+** EX_USAGE -- The command was used incorrectly, e.g., with
+** the wrong number of arguments, a bad flag, a bad
+** syntax in a parameter, or whatever.
+** EX_DATAERR -- The input data was incorrect in some way.
+** This should only be used for user's data & not
+** system files.
+** EX_NOINPUT -- An input file (not a system file) did not
+** exist or was not readable. This could also include
+** errors like "No message" to a mailer (if it cared
+** to catch it).
+** EX_NOUSER -- The user specified did not exist. This might
+** be used for mail addresses or remote logins.
+** EX_NOHOST -- The host specified did not exist. This is used
+** in mail addresses or network requests.
+** EX_UNAVAILABLE -- A service is unavailable. This can occur
+** if a support program or file does not exist. This
+** can also be used as a catchall message when something
+** you wanted to do doesn't work, but you don't know
+** why.
+** EX_SOFTWARE -- An internal software error has been detected.
+** This should be limited to non-operating system related
+** errors as possible.
+** EX_OSERR -- An operating system error has been detected.
+** This is intended to be used for such things as "cannot
+** fork", "cannot create pipe", or the like. It includes
+** things like getuid returning a user that does not
+** exist in the passwd file.
+** EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+** etc.) does not exist, cannot be opened, or has some
+** sort of error (e.g., syntax error).
+** EX_CANTCREAT -- A (user specified) output file cannot be
+** created.
+** EX_IOERR -- An error occurred while doing I/O on some file.
+** EX_TEMPFAIL -- temporary failure, indicating something that
+** is not really an error. In sendmail, this means
+** that a mailer (e.g.) could not create a connection,
+** and the request should be reattempted later.
+** EX_PROTOCOL -- the remote system returned something that
+** was "not possible" during a protocol exchange.
+** EX_NOPERM -- You did not have sufficient permission to
+** perform the operation. This is not intended for
+** file system problems, which should use NOINPUT or
+** CANTCREAT, but rather for higher level permissions.
+*/
+
+# if SM_CONF_SYSEXITS_H
+# include <sysexits.h>
+# else /* SM_CONF_SYSEXITS_H */
+
+# define EX_OK 0 /* successful termination */
+
+# define EX__BASE 64 /* base value for error messages */
+
+# define EX_USAGE 64 /* command line usage error */
+# define EX_DATAERR 65 /* data format error */
+# define EX_NOINPUT 66 /* cannot open input */
+# define EX_NOUSER 67 /* addressee unknown */
+# define EX_NOHOST 68 /* host name unknown */
+# define EX_UNAVAILABLE 69 /* service unavailable */
+# define EX_SOFTWARE 70 /* internal software error */
+# define EX_OSERR 71 /* system error (e.g., can't fork) */
+# define EX_OSFILE 72 /* critical OS file missing */
+# define EX_CANTCREAT 73 /* can't create (user) output file */
+# define EX_IOERR 74 /* input/output error */
+# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+# define EX_PROTOCOL 76 /* remote error in protocol */
+# define EX_NOPERM 77 /* permission denied */
+# define EX_CONFIG 78 /* configuration error */
+
+# define EX__MAX 78 /* maximum listed value */
+
+# endif /* SM_CONF_SYSEXITS_H */
+
+extern char *sm_strexit __P((int));
+extern char *sm_sysexitmsg __P((int));
+extern char *sm_sysexmsg __P((int));
+
+#endif /* ! SM_SYSEXITS_H */
diff --git a/contrib/sendmail/include/sm/test.h b/contrib/sendmail/include/sm/test.h
new file mode 100644
index 0000000..1d700d7
--- /dev/null
+++ b/contrib/sendmail/include/sm/test.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: test.h,v 1.6 2001/04/03 01:53:01 gshapiro Exp $
+ */
+
+/*
+** Abstractions for writing a libsm test program.
+*/
+
+#ifndef SM_TEST_H
+# define SM_TEST_H
+
+# include <sm/gen.h>
+
+# if defined(__STDC__) || defined(__cplusplus)
+# define SM_TEST(cond) sm_test(cond, #cond, __FILE__, __LINE__)
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define SM_TEST(cond) sm_test(cond, "cond", __FILE__, __LINE__)
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+
+extern int SmTestIndex;
+extern int SmTestNumErrors;
+
+extern void
+sm_test_begin __P((
+ int _argc,
+ char **_argv,
+ char *_testname));
+
+extern bool
+sm_test __P((
+ bool _success,
+ char *_expr,
+ char *_filename,
+ int _lineno));
+
+extern int
+sm_test_end __P((void));
+
+#endif /* ! SM_TEST_H */
diff --git a/contrib/sendmail/include/sm/types.h b/contrib/sendmail/include/sm/types.h
new file mode 100644
index 0000000..625a90e
--- /dev/null
+++ b/contrib/sendmail/include/sm/types.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: types.h,v 1.13 2001/04/03 01:53:01 gshapiro Exp $
+ */
+
+/*
+** This header file defines standard integral types.
+** - It includes <sys/types.h>, and fixes portability problems that
+** exist on older Unix platforms.
+** - It defines LONGLONG_T and ULONGLONG_T, which are portable locutions
+** for 'long long' and 'unsigned long long'.
+*/
+
+#ifndef SM_TYPES_H
+# define SM_TYPES_H
+
+# include <sm/config.h>
+
+/*
+** On BSD 4.2 systems, <sys/types.h> was not idempotent.
+** This problem is circumvented by replacing all occurrences
+** of <sys/types.h> with <sm/types.h>, which is idempotent.
+*/
+
+# include <sys/types.h>
+
+/*
+** On some old Unix platforms, some of the standard types are missing.
+** We fix that here.
+*/
+
+# if !SM_CONF_UID_GID
+# define uid_t int
+# define gid_t int
+# endif /* !SM_CONF_UID_GID */
+
+# if !SM_CONF_SSIZE_T
+# define ssize_t int
+# endif /* !SM_CONF_SSIZE_T */
+
+/*
+** Define LONGLONG_T and ULONGLONG_T, which are portable locutions
+** for 'long long' and 'unsigned long long' from the C 1999 standard.
+*/
+
+# if SM_CONF_LONGLONG
+ typedef long long LONGLONG_T;
+ typedef unsigned long long ULONGLONG_T;
+# else /* SM_CONF_LONGLONG */
+# if SM_CONF_QUAD_T
+ typedef quad_t LONGLONG_T;
+ typedef u_quad_t ULONGLONG_T;
+# else /* SM_CONF_QUAD_T */
+ typedef long LONGLONG_T;
+ typedef unsigned long ULONGLONG_T;
+# endif /* SM_CONF_QUAD_T */
+# endif /* SM_CONF_LONGLONG */
+
+#endif /* ! SM_TYPES_H */
diff --git a/contrib/sendmail/include/sm/varargs.h b/contrib/sendmail/include/sm/varargs.h
new file mode 100644
index 0000000..7d2b5ca
--- /dev/null
+++ b/contrib/sendmail/include/sm/varargs.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: varargs.h,v 1.7 2001/09/13 16:45:40 ca Exp $
+ */
+
+/*
+** libsm variable argument lists
+*/
+
+#ifndef SM_VARARGS_H
+# define SM_VARARGS_H
+
+# if defined(__STDC__) || defined(__cplusplus)
+# define SM_VA_STD 1
+# include <stdarg.h>
+# define SM_VA_START(ap, f) va_start(ap, f)
+# else /* defined(__STDC__) || defined(__cplusplus) */
+# define SM_VA_STD 0
+# include <varargs.h>
+# define SM_VA_START(ap, f) va_start(ap)
+# endif /* defined(__STDC__) || defined(__cplusplus) */
+
+# if defined(va_copy)
+# define SM_VA_COPY(dst, src) va_copy((dst), (src))
+# elif defined(__va_copy)
+# define SM_VA_COPY(dst, src) __va_copy((dst), (src))
+# else
+# define SM_VA_COPY(dst, src) (dst) = (src)
+# endif
+
+/*
+** The following macros are useless, but are provided for symmetry.
+*/
+
+# define SM_VA_LOCAL_DECL va_list ap;
+# define SM_VA_ARG(ap, type) va_arg(ap, type)
+# define SM_VA_END(ap) va_end(ap)
+
+#endif /* ! SM_VARARGS_H */
diff --git a/contrib/sendmail/include/sm/xtrap.h b/contrib/sendmail/include/sm/xtrap.h
new file mode 100644
index 0000000..2e7e717
--- /dev/null
+++ b/contrib/sendmail/include/sm/xtrap.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: xtrap.h,v 1.7 2001/04/03 01:53:01 gshapiro Exp $
+ */
+
+/*
+** scaffolding for testing exception handler code
+*/
+
+#ifndef SM_XTRAP_H
+# define SM_XTRAP_H
+
+# include <sm/debug.h>
+# include <sm/exc.h>
+
+extern SM_ATOMIC_UINT_T SmXtrapCount;
+extern SM_DEBUG_T SmXtrapDebug;
+extern SM_DEBUG_T SmXtrapReport;
+
+# if SM_DEBUG_CHECK
+# define sm_xtrap_check() (++SmXtrapCount == sm_debug_level(&SmXtrapDebug))
+# else /* SM_DEBUG_CHECK */
+# define sm_xtrap_check() (0)
+# endif /* SM_DEBUG_CHECK */
+
+# define sm_xtrap_raise_x(exc) \
+ if (sm_xtrap_check()) \
+ { \
+ sm_exc_raise_x(exc); \
+ } else
+
+#endif /* ! SM_XTRAP_H */
diff --git a/contrib/sendmail/libmilter/Makefile.m4 b/contrib/sendmail/libmilter/Makefile.m4
index 19381a4..f767441 100644
--- a/contrib/sendmail/libmilter/Makefile.m4
+++ b/contrib/sendmail/libmilter/Makefile.m4
@@ -1,5 +1,7 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+dnl only required for compilation of EXTRAS
+define(`confREQUIRE_LIBSM', `true')
define(`confMT', `true')
# sendmail dir
@@ -8,17 +10,29 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`library', `libmilter')
define(`bldINSTALLABLE', `true')
-define(`bldSOURCES', `main.c engine.c listener.c handler.c comm.c smfi.c signal.c sm_gethost.c ')
-bldPUSH_SMLIB(`smutil')
+define(`LIBMILTER_EXTRAS', `errstring.c strl.c')
+APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL -Dsm_snprintf=snprintf')
+define(`bldSOURCES', `main.c engine.c listener.c handler.c comm.c smfi.c signal.c sm_gethost.c LIBMILTER_EXTRAS ')
+define(`confBEFORE', `LIBMILTER_EXTRAS')
bldPUSH_INSTALL_TARGET(`install-mfapi')
bldPRODUCT_END
-APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
+
+PUSHDIVERT(3)
+errstring.c:
+ ${LN} ${LNOPTS} ${SRCDIR}/libsm/errstring.c .
+
+strl.c:
+ ${LN} ${LNOPTS} ${SRCDIR}/libsm/strl.c .
+POPDIVERT
+
divert(bldTARGETS_SECTION)
-# Install the API header file
+# Install the API header files
MFAPI= ${SRCDIR}/inc`'lude/libmilter/mfapi.h
+MFDEF= ${SRCDIR}/inc`'lude/libmilter/mfdef.h
install-mfapi: ${MFAPI}
${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFAPI} ${DESTDIR}${INCLUDEDIR}
+ ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFDEF} ${DESTDIR}${INCLUDEDIR}
divert(0)
bldFINISH
diff --git a/contrib/sendmail/libmilter/README b/contrib/sendmail/libmilter/README
index 3eae861..f38f68a 100644
--- a/contrib/sendmail/libmilter/README
+++ b/contrib/sendmail/libmilter/README
@@ -9,17 +9,27 @@ through reference to a sample filter which is attached at the end of this
file. It is necessary to first build libmilter.a, which can be done by
issuing the './Build' command in SRCDIR/libmilter .
-NOTE: Both libmilter and the callouts in sendmail are marked as an FFR (For
-Future Release). If you intend to use them in 8.11.X, you must compiled
-both libmilter and sendmail with -D_FFR_MILTER defined. You can do this by
-adding the following to your devtools/Site/site.config.m4 file:
+NOTE: If you intend to use filters in sendmail, you must compile sendmail
+with -DMILTER defined. You can do this by adding the following to
+your devtools/Site/site.config.m4 file:
- dnl Milter
- APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1')
- APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1')
+ APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
+
++----------------+
+| SECURITY HINTS |
++----------------+
+
+Note: we strongly recommend not to run any milter as root. Libmilter
+does not need root access to communicate with sendmail. It is a
+good security practice to run a program only with root privileges
+if really necessary. A milter should probably check first whether
+it runs as root and refuse to start in that case. There is a
+compile time option _FFR_MILTER_ROOT_UNSAFE which keeps libmilter
+from unlinking a socket when running as root. It is recommended
+to turn on this option:
+
+ APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER_ROOT_UNSAFE ')
-You will also need to define _FFR_MILTER when building your .cf file using
-m4.
+-------------------+
| BUILDING A FILTER |
@@ -29,14 +39,14 @@ The following command presumes that the sample code from the end of this
README is saved to a file named 'sample.c' and built in the local platform-
specific build subdirectory (SRCDIR/obj.*/libmilter).
- cc -I../../sendmail -I../../include -o sample sample.c libmilter.a ../libsmutil/libsmutil.a -pthread
+ cc -I../../sendmail -I../../include -o sample sample.c libmilter.a ../libsm/libsm.a -pthread
It is recommended that you build your filters in a location outside of
the sendmail source tree. Modify the compiler include references (-I)
and the library locations accordingly. Also, some operating systems may
require additional libraries. For example, SunOS 5.X requires '-lresolv
--lsocket -lnsl'. Depending on your OS you may need a library instead
-of the option -pthread, e.g., -lpthread.
+-lsocket -lnsl'. Depending on your operating system you may need a library
+instead of the option -pthread, e.g., -lpthread.
Filters must be thread-safe! Many operating systems now provide support for
POSIX threads in the standard C libraries. The compiler flag to link with
@@ -77,13 +87,13 @@ IPv4 socket on port 3333 of localhost. The current flags (F=) are:
T Temporary fail connection if filter unavailable
If neither F=R nor F=T is specified, the message is passed through sendmail
-as if the filter were not present.
+in case of filter errors as if the failing filters were not present.
Finally, you can override the default timeouts used by sendmail when
talking to the filters using the T= equate. There are four fields inside
of the T= equate:
-Letter Meaning
+Letter Meaning
C Timeout for connecting to a filter (if 0, use system timeout)
S Timeout for sending information from the MTA to a filter
R Timeout for reading reply from the filter
@@ -94,7 +104,7 @@ Note the separator between each is a ';' as a ',' already separates equates
and therefore can't separate timeouts. The default values (if not set in
the config) are:
-T=C:0m;S:10s;R:10s;E:5m
+T=C:5m;S:10s;R:10s;E:5m
where 's' is seconds and 'm' is minutes.
@@ -182,6 +192,30 @@ the logging level of sendmail can be raised with the LogLevel option.
See the sendmail(8) manual page for more information.
++--------------+
+| REQUIREMENTS |
++--------------+
+
+libmilter requires pthread support in the operating system. Moreover, it
+requires that the library functions it uses are thread safe; which is true
+for the operating systems libmilter has been developed and tested on. On
+some operating systems this requires special compile time options (e.g.,
+not just -pthread). libmilter is currently known to work on (modulo problems
+in the pthread support of some specific versions):
+
+FreeBSD 3.x, 4.x
+SunOS 5.x (x >= 5)
+AIX 4.3.x
+HP UX 11.x
+Linux (recent versions/distributions)
+
+libmilter is currently not supported on:
+
+IRIX 6.x
+Ultrix
+
+Feedback about problems (and possible fixes) is welcome.
+
+--------------------------+
| SOURCE FOR SAMPLE FILTER |
+--------------------------+
@@ -201,14 +235,11 @@ below to verify the functions are thread safe.
#include "libmilter/mfapi.h"
+#ifndef true
typedef int bool;
-
-#ifndef FALSE
-# define FALSE 0
-#endif /* ! FALSE*/
-#ifndef TRUE
-# define TRUE 1
-#endif /* ! TRUE*/
+# define false 0
+# define true 1
+#endif /* ! true */
struct mlfiPriv
{
@@ -295,7 +326,7 @@ mlfi_body(ctx, bodyp, bodylen)
if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0)
{
/* write failed */
- (void) mlfi_cleanup(ctx, FALSE);
+ (void) mlfi_cleanup(ctx, false);
return SMFIS_TEMPFAIL;
}
@@ -307,7 +338,7 @@ sfsistat
mlfi_eom(ctx)
SMFICTX *ctx;
{
- return mlfi_cleanup(ctx, TRUE);
+ return mlfi_cleanup(ctx, true);
}
sfsistat
@@ -321,7 +352,7 @@ sfsistat
mlfi_abort(ctx)
SMFICTX *ctx;
{
- return mlfi_cleanup(ctx, FALSE);
+ return mlfi_cleanup(ctx, false);
}
sfsistat
@@ -349,7 +380,7 @@ mlfi_cleanup(ctx, ok)
{
/* add a header to the message announcing our presence */
if (gethostname(host, sizeof host) < 0)
- strlcpy(host, "localhost", sizeof host);
+ snprintf(host, sizeof host, "localhost");
p = strrchr(priv->mlfi_fname, '/');
if (p == NULL)
p = priv->mlfi_fname;
@@ -426,4 +457,4 @@ main(argc, argv)
/* eof */
-$Revision: 8.9.2.1.2.19 $, Last updated $Date: 2001/06/28 22:25:14 $
+$Revision: 8.35 $, Last updated $Date: 2002/01/07 21:29:20 $
diff --git a/contrib/sendmail/libmilter/comm.c b/contrib/sendmail/libmilter/comm.c
index af1ee6d..3347808 100644
--- a/contrib/sendmail/libmilter/comm.c
+++ b/contrib/sendmail/libmilter/comm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,17 +8,16 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: comm.c,v 8.30.4.6 2000/10/05 22:44:01 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: comm.c,v 8.48 2001/11/07 17:43:04 ca Exp $")
-#if _FFR_MILTER
#include "libmilter.h"
+#include <sm/errstring.h>
-#define FD_Z FD_ZERO(&readset); \
- FD_SET((u_int) sd, &readset); \
- FD_ZERO(&excset); \
- FD_SET((u_int) sd, &excset)
+#define FD_Z FD_ZERO(&readset); \
+ FD_SET((unsigned int) sd, &readset); \
+ FD_ZERO(&excset); \
+ FD_SET((unsigned int) sd, &excset)
/*
** MI_RD_CMD -- read a command
@@ -73,11 +72,13 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
*cmd = SMFIC_SELECT;
return NULL;
}
- if ((len = MI_SOCK_READ(sd, data + i, sizeof data - i)) < 0)
+
+ len = MI_SOCK_READ(sd, data + i, sizeof data - i);
+ if (MI_SOCK_READ_FAIL(len))
{
smi_log(SMI_LOG_ERR,
"%s, mi_rd_cmd: read returned %d: %s",
- name, len, strerror(errno));
+ name, len, sm_errstring(errno));
*cmd = SMFIC_RECVERR;
return NULL;
}
@@ -100,7 +101,7 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
{
smi_log(SMI_LOG_ERR,
"%s: mi_rd_cmd: select returned %d: %s",
- name, ret, strerror(errno));
+ name, ret, sm_errstring(errno));
*cmd = SMFIC_RECVERR;
return NULL;
}
@@ -116,7 +117,11 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
*cmd = SMFIC_TOOBIG;
return NULL;
}
+#if _FFR_ADD_NULL
+ buf = malloc(expl + 1);
+#else /* _FFR_ADD_NULL */
buf = malloc(expl);
+#endif /* _FFR_ADD_NULL */
if (buf == NULL)
{
*cmd = SMFIC_MALLOC;
@@ -133,11 +138,12 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
free(buf);
return NULL;
}
- if ((len = MI_SOCK_READ(sd, buf + i, expl - i)) < 0)
+ len = MI_SOCK_READ(sd, buf + i, expl - i);
+ if (MI_SOCK_READ_FAIL(len))
{
smi_log(SMI_LOG_ERR,
"%s: mi_rd_cmd: read returned %d: %s",
- name, len, strerror(errno));
+ name, len, sm_errstring(errno));
ret = -1;
break;
}
@@ -156,6 +162,10 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
if (len >= expl - i)
{
*rlen = expl;
+#if _FFR_ADD_NULL
+ /* makes life simpler for common string routines */
+ buf[expl] = '\0';
+#endif /* _FFR_ADD_NULL */
return buf;
}
i += len;
@@ -175,14 +185,14 @@ mi_rd_cmd(sd, timeout, cmd, rlen, name)
{
smi_log(SMI_LOG_ERR,
"%s: mi_rd_cmd: select returned %d: %s",
- name, ret, strerror(save_errno));
+ name, ret, sm_errstring(save_errno));
*cmd = SMFIC_RECVERR;
return NULL;
}
*cmd = SMFIC_UNKNERR;
return NULL;
}
- /*
+/*
** MI_WR_CMD -- write a cmd to sd
**
** Parameters:
@@ -222,7 +232,7 @@ mi_wr_cmd(sd, timeout, cmd, buf, len)
do
{
FD_ZERO(&wrtset);
- FD_SET((u_int) sd, &wrtset);
+ FD_SET((unsigned int) sd, &wrtset);
if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0)
return MI_FAILURE;
} while (ret < 0 && errno == EINTR);
@@ -248,7 +258,7 @@ mi_wr_cmd(sd, timeout, cmd, buf, len)
do
{
FD_ZERO(&wrtset);
- FD_SET((u_int) sd, &wrtset);
+ FD_SET((unsigned int) sd, &wrtset);
if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0)
return MI_FAILURE;
} while (ret < 0 && errno == EINTR);
@@ -264,4 +274,3 @@ mi_wr_cmd(sd, timeout, cmd, buf, len)
}
return MI_SUCCESS;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/docs/api.html b/contrib/sendmail/libmilter/docs/api.html
new file mode 100644
index 0000000..af714ef
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/api.html
@@ -0,0 +1,194 @@
+<html>
+<head><title>Milter API</title></head>
+<body>
+<h1>Milter API</h1>
+
+<h2>Contents</h2>
+<ul>
+ <li>Library Control Functions
+ <li>Data Access Functions
+ <li>Message Modification Functions
+ <li>Callbacks
+</ul>
+
+<h2>Library Control Functions</h2>
+
+Before handing control to libmilter (by calling <a
+href="smfi_main.html">smfi_main</a>), a filter may call the following
+functions to set libmilter parameters. In particular, the filter must
+call <a href="smfi_register.html">smfi_register</a> to register its
+callbacks. Each function will return either MI_SUCCESS or MI_FAILURE to
+indicate the status of the operation.
+<p>
+None of these functions communicate with the MTA. All alter the
+library's state, some of which is communicated to the MTA inside <a
+href="smfi_main.html">smfi_main</a>.
+<p>
+<table border="1" cellspacing=0 cellpadding=2><tr bgcolor="#dddddd"><th>Function</th><th>Description</th></tr>
+
+<tr><td><a href="smfi_register.html">smfi_register</a></td><td>Register a filter.</td></tr>
+
+<tr><td><a href="smfi_setconn.html">smfi_setconn</a></td><td>Specify socket to use.</td></tr>
+
+<tr><td><a href="smfi_settimeout.html">smfi_settimeout</a></td><td>Set timeout.</td></tr>
+
+<tr><td><a href="smfi_main.html">smfi_main</a></td><td>Hand control to libmilter.</td></tr>
+
+</table>
+
+<h2>Data Access Functions</h2>
+
+The following functions may be called from within the filter-defined callbacks
+to access information about the current connection or message.
+<p>
+<table border="1" cellspacing=0 cellpadding=2><tr bgcolor="#dddddd"><th>Function</th><th>Description</th></tr>
+<tr><td><a href="smfi_getsymval.html">smfi_getsymval</a></td><td>Return the value
+of a symbol.</td></tr>
+
+<tr><td><a href="smfi_getpriv.html">smfi_getpriv</a></td><td>Get the private data
+pointer.</td></tr>
+
+<tr><td><a href="smfi_setpriv.html">smfi_setpriv</a></td><td>Set the private data
+pointer.</td></tr>
+
+<tr><td><a href="smfi_setreply.html">smfi_setreply</a></td><td>Set the specific
+reply code to be used.</td></tr>
+
+</table>
+
+<h2>Message Modification Functions</h2>
+
+The following functions change a message's contents and attributes.
+<b>They may only be called in <a href="xxfi_eom.html">xxfi_eom</a></b>.
+All of these functions may invoke additional communication with the MTA.
+They will return either MI_SUCCESS or MI_FAILURE to indicate the status of
+the operation.
+
+<p>
+A filter must have set the appropriate flag (listed below) in the
+description passed to <a href="smfi_register.html">smfi_register</a>
+to call any message modification function. Failure to do so will
+cause the MTA to treat a call to the function as a failure of the
+filter, terminating its connection.
+
+<p>
+Note that the status returned indicates only whether or not the
+filter's message was successfully sent to the MTA, not whether or not
+the MTA performed the requested operation. For example, <a
+href="smfi_addheader.html">smfi_addheader</a>, when called with an
+illegal header name, will return MI_SUCCESS even though the MTA may
+later refuse to add the illegal header.
+<p>
+<table border="1" cellspacing=0 cellpadding=2><tr bgcolor="#dddddd"><th>Function</th><th>Description</th><th>SMFIF_* flag</tr>
+<tr><td><a href="smfi_addheader.html">smfi_addheader</a></td><td>Add a header to
+the message.</td><td>SMFIF_ADDHDRS</td></tr>
+
+<tr><td><a href="smfi_chgheader.html">smfi_chgheader</a></td><td>Change or delete a header.</td><td>SMFIF_CHGHDRS</td></tr>
+
+<tr><td><a href="smfi_addrcpt.html">smfi_addrcpt</a></td><td>Add a recipient to
+the envelope.</td><td>SMFIF_ADDRCPT</td></tr>
+
+<tr><td><a href="smfi_delrcpt.html">smfi_delrcpt</a></td><td>Delete a recipient
+from the envelope.</td><td>SMFIF_DELRCPT</td></tr>
+
+<tr><td><a href="smfi_replacebody.html">smfi_replacebody</a></td><td>Replace the
+body of the message.</td><td>SMFIF_CHGBODY</td></tr>
+
+</table>
+
+<h2>Callbacks</h2>
+
+The filter should implement one or more of the following callbacks,
+which are registered via <a href="smfi_register.html">smfi_register</a>:
+<p>
+<table border="1" cellspacing=0 cellpadding=2><tr bgcolor="#dddddd"><th>Function</th><th>Description</th></tr>
+
+<tr><td><a href="xxfi_connect.html">xxfi_connect</a></td><td>connection info</td></tr>
+
+<tr><td><a href="xxfi_helo.html">xxfi_helo</a></td><td>SMTP HELO/EHLO command</td></tr>
+
+<tr><td><a href="xxfi_envfrom.html">xxfi_envfrom</a></td><td>envelope sender</td></tr>
+
+<tr><td><a href="xxfi_envrcpt.html">xxfi_envrcpt</a></td><td>envelope recipient</td></tr>
+
+<tr><td><a href="xxfi_header.html">xxfi_header</a></td><td>header</td></tr>
+
+<tr><td><a href="xxfi_eoh.html">xxfi_eoh</a></td><td>end of header</td></tr>
+
+<tr><td><a href="xxfi_body.html">xxfi_body</a></td><td>body block</td></tr>
+
+<tr><td><a href="xxfi_eom.html">xxfi_eom</a></td><td>end of message</td></tr>
+
+<tr><td><a href="xxfi_abort.html">xxfi_abort</a></td><td>message aborted</td></tr>
+
+<tr><td><a href="xxfi_close.html">xxfi_close</a></td><td>connection cleanup</td></tr>
+
+</table>
+
+<p>
+The above callbacks should all return one of the following return values,
+having the indicated meanings. Any return other than one of the below
+values constitutes an error, and will cause sendmail to terminate its
+connection to the offending filter.
+
+<p><a name="conn-spec"></a>Milter distinguishes between recipient-,
+message-, and connection-oriented routines. Recipient-oriented
+callbacks may affect the processing of a single message recipient;
+message-oriented callbacks, a single message; connection-oriented
+callbacks, an entire connection (during which multiple messages may be
+delivered to multiple sets of recipients).
+<a href="xxfi_envrcpt.html">xxfi_envrcpt</a> is recipient-oriented.
+<a href="xxfi_connect.html">xxfi_connect</a>,
+<a href="xxfi_helo.html">xxfi_helo</a> and
+<a href="xxfi_close.html">xxfi_close</a> are connection-oriented. All
+other callbacks are message-oriented.
+
+<p>
+<table border="1" cellspacing=0 cellpadding=2>
+ <tr bgcolor="#dddddd"><th>Return value</th><th>Description</th></tr>
+ <tr valign="top">
+ <td>SMFIS_CONTINUE</td>
+ <td>Continue processing the current connection, message, or recipient.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_REJECT</td>
+ <td>For a connection-oriented routine, reject this connection; call <a href="xxfi_close.html">xxfi_close</a>.<br>
+ For a message-oriented routine (except
+ <a href="xxfi_eom.html">xxfi_eom</a> or
+ <a href="xxfi_abort.html">xxfi_abort</a>), reject this message.<br>
+ For a recipient-oriented routine, reject the current recipient (but continue processing the current message).
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_DISCARD</td>
+ <td>For a message- or recipient-oriented routine, accept this message, but silently discard it.<br>
+ SMFIS_DISCARD should not be returned by a connection-oriented routine.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_ACCEPT</td>
+ <td>For a connection-oriented routine, accept this connection without further filter processing; call <a href="xxfi_close.html">xxfi_close</a>.<br>
+ For a message- or recipient-oriented routine, accept this message without further filtering.<br>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_TEMPFAIL</td>
+ <td>Return a temporary failure, i.e., the corresponding SMTP command will return an appropriate 4xx status code.
+ For a message-oriented routine (except <a href="xxfi_envfrom.html">xxfi_envfrom</a>), fail for this message. <br>
+ For a connection-oriented routine, fail for this connection; call <a href="xxfi_close.html">xxfi_close</a>. <br>
+ For a recipient-oriented routine, only fail for the current recipient; continue message processing.
+ </td>
+ </tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/design.html b/contrib/sendmail/libmilter/docs/design.html
new file mode 100644
index 0000000..fbc74e6
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/design.html
@@ -0,0 +1,144 @@
+<html>
+<head>
+<title>Architecture</title>
+</head>
+<body>
+
+<h1>Architecture</h1>
+
+<h2>Contents</h2>
+
+<ul>
+ <li>Design Goals
+ <li>Implementing Filtering Policies
+ <li>MTA - Filter Communication
+</ul>
+
+<h2>Goals</h2>
+
+The Sendmail Content Management API (Milter) provides an interface for
+third-party software to validate and modify messages as they pass
+through the mail transport system. Filters can process messages'
+connection (IP) information, envelope protocol elements, message
+headers, and/or message body contents, and modify a message's
+recipients, headers, and body. The MTA configuration file specifies
+which filters are to be applied, and in what order, allowing an
+administrator to combine multiple independently-developed filters.
+
+<p>
+We expect to see both vendor-supplied, configurable mail filtering
+applications and a multiplicity of script-like filters designed by and
+for MTA administrators. A certain degree of coding sophistication and
+domain knowledge on the part of the filter provider is assumed. This
+allows filters to exercise fine-grained control at the SMTP level.
+However, as will be seen in the example, many filtering applications
+can be written with relatively little protocol knowledge.
+
+<p>
+Given these expectations, the API is designed to achieve the following
+goals:
+
+<OL>
+ <LI>Safety/security.
+ Filter processes should not need to run as root
+ (of course, they can if required, but that is a local issue);
+ this will simplify coding
+ and limit the impact of security flaws in the filter program.
+<p>
+ <LI>Reliability.
+ Coding failures in a Milter process that cause that process
+ to hang or core-dump
+ should not stop mail delivery.
+ Faced with such a failure,
+ sendmail should use a default mechanism,
+ either behaving as if the filter were not present
+ or as if a required resource were unavailable.
+ The latter failure mode will generally have sendmail return
+ a 4xx SMTP code (although in later phases of the SMTP protocol
+ it may cause the mail to be queued for later processing).
+<p>
+ <LI>Simplicity.
+ The API should make implementation of a new filter
+ no more difficult than absolutely necessary.
+ Subgoals include:
+ <UL>
+ <LI>Encourage good thread practice
+ by defining thread-clean interfaces including local data hooks.
+ <LI>Provide all interfaces required
+ while avoiding unnecessary pedanticism.
+ </UL>
+<p>
+ <LI>Performance.
+ Simple filters should not seriously impact overall MTA performance.
+</OL>
+
+<h2>Implementing Filtering Policies</h2>
+
+Milter is designed to allow a server administrator to combine
+third-party filters to implement a desired mail filtering policy. For
+example, if a site wished to scan incoming mail for viruses on several
+platforms, eliminate unsolicited commercial email, and append a mandated
+footer to selected incoming messages, the administrator could configure
+the MTA to filter messages first through a server based anti-virus
+engine, then via a large-scale spam-catching service, and finally
+append the desired footer if the message still met requisite criteria.
+Any of these filters could be added or changed independently.
+
+<p>
+Thus the site administrator, not the filter writer, controls the
+overall mail filtering environment. In particular, he/she must decide
+which filters are run, in what order they are run, and how they
+communicate with the MTA. These parameters, as well as the
+actions to be taken if a filter becomes unavailable, are selectable
+during MTA configuration. <a href="installation.html">Further
+details</a> are available later in this document.
+
+<h2>MTA - Filter communication</h2>
+
+Filters run as separate processes, outside of the sendmail address
+space. The benefits of this are threefold:
+
+<OL>
+ <LI>The filter need not run with "root" permissions, thereby
+ avoiding a large family of potential security problems.</LI>
+
+ <LI>Failures in a particular filter will not affect the MTA or
+ other filters.</LI>
+
+ <LI>The filter can potentially have higher performance because of
+ the parallelism inherent in multiple processes.</LI>
+</OL>
+
+<p>
+Each filter may communicate with multiple MTAs at the same time over
+local or remote connections, using multiple threads of execution. <a
+href="#figure-1">Figure 1</a> illustrates a possible network of
+communication channels between a site's filters, its MTAs, and other
+MTAs on the network:
+</p>
+<div align="center">
+<a name="figure-1"><img src="figure1.jpg" ALT=""></A><br>
+<b>Figure 1: A set of MTA's interacting with a set of filters.</b>
+</div>
+<p>
+The Milter library (libmilter) implements the communication protocol.
+It accepts connections from various MTAs, passes the relevant data to
+the filter through callbacks, then makes appropriate responses based
+on return codes. A filter may also send data to the MTA as a result
+of library calls. <a href="#figure-2">Figure 2</a> shows a single
+filter process processing messages from two MTAs:
+</p>
+<div align="center">
+<img src="figure2.jpg" ALT=""><br>
+<b>Figure 2: A filter handling simultaneous requests from two MTA's.</b>
+</div>
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/figure1.fig b/contrib/sendmail/libmilter/docs/figure1.fig
new file mode 100644
index 0000000..e0cbdc8
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure1.fig
@@ -0,0 +1,56 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 975 225 5025 3375
+6 1500 1275 2700 2025
+2 2 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 5
+ 1650 1425 2550 1425 2550 1875 1650 1875 1650 1425
+4 0 1 50 0 0 20 0.0000 4 195 645 1800 1725 MTA\001
+-6
+6 1950 2625 3150 3375
+2 2 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 5
+ 2100 2775 3000 2775 3000 3225 2100 3225 2100 2775
+4 0 4 50 0 0 20 0.0000 4 195 645 2250 3075 MTA\001
+-6
+6 1050 225 2250 975
+2 2 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 5
+ 1200 375 2100 375 2100 825 1200 825 1200 375
+4 0 14 50 0 0 20 0.0000 4 195 645 1350 675 MTA\001
+-6
+2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2
+ 2550 1575 3750 2625
+2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2
+ 2550 1575 3750 1575
+2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2
+ 2550 1575 3750 825
+2 1 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 2
+ 3000 2925 3750 2625
+2 1 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 2
+ 2100 525 3750 825
+2 1 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 2
+ 2100 525 3750 2625
+2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2
+ 1050 3075 2100 3075
+2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2
+ 1050 1725 1650 1725
+2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2
+ 1050 675 1200 675
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3750 2475 4950 2475 4950 2925 3750 2925 3750 2475
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3750 1425 4950 1425 4950 1875 3750 1875 3750 1425
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3750 525 4950 525 4950 975 3750 975 3750 525
+4 0 0 50 0 1 20 0.0000 4 210 795 3900 2775 Filter 3\001
+4 0 0 50 0 1 20 0.0000 4 210 795 3900 1725 Filter 2\001
+4 0 0 50 0 1 20 0.0000 4 210 795 3900 825 Filter 1\001
+-6
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 300 525 1050 525 1050 3225 300 3225 300 525
+4 0 0 50 0 2 24 1.5708 4 255 1950 825 2850 INTERNET\001
diff --git a/contrib/sendmail/libmilter/docs/figure1.jpg b/contrib/sendmail/libmilter/docs/figure1.jpg
new file mode 100644
index 0000000..1a5f1de
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure1.jpg
Binary files differ
diff --git a/contrib/sendmail/libmilter/docs/figure1.ps b/contrib/sendmail/libmilter/docs/figure1.ps
new file mode 100644
index 0000000..ae31760
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure1.ps
@@ -0,0 +1,173 @@
+%!PS-Adobe-2.0
+%%Title: figure1.fig
+%%Creator: fig2dev Version 3.2.3 Patchlevel
+%%CreationDate: Tue Jun 6 14:00:04 2000
+%%For: sean@host232.Sendmail.COM (Sean O'rourke,5400)
+%%Orientation: Landscape
+%%Pages: 1
+%%BoundingBox: 0 0 612 792
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%Magnification: 1.0000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath
+198.0 238.0 translate
+ 90 rotate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+%%Page: 1 1
+10 setmiterlimit
+ 0.06000 0.06000 sc
+%%Page: 1 1
+/Times-Bold ff 360.00 scf sf
+825 2850 m
+gs 1 -1 sc 90.0 rot (INTERNET) col0 sh gr
+/Times-Roman ff 300.00 scf sf
+1800 1725 m
+gs 1 -1 sc (MTA) col1 sh gr
+% Polyline
+15.000 slw
+n 2100 2775 m 3000 2775 l 3000 3225 l 2100 3225 l
+ cp gs col4 s gr
+/Times-Roman ff 300.00 scf sf
+2250 3075 m
+gs 1 -1 sc (MTA) col4 sh gr
+% Polyline
+n 1200 375 m 2100 375 l 2100 825 l 1200 825 l
+ cp gs col14 s gr
+/Times-Roman ff 300.00 scf sf
+1350 675 m
+gs 1 -1 sc (MTA) col14 sh gr
+% Polyline
+n 2550 1575 m
+ 3750 2625 l gs col1 s gr
+% Polyline
+n 2550 1575 m
+ 3750 1575 l gs col1 s gr
+% Polyline
+n 2550 1575 m
+ 3750 825 l gs col1 s gr
+% Polyline
+n 3000 2925 m
+ 3750 2625 l gs col4 s gr
+% Polyline
+n 2100 525 m
+ 3750 825 l gs col14 s gr
+% Polyline
+n 2100 525 m
+ 3750 2625 l gs col14 s gr
+% Polyline
+45.000 slw
+n 1050 3075 m
+ 2100 3075 l gs col0 s gr
+% Polyline
+n 1050 1725 m
+ 1650 1725 l gs col0 s gr
+% Polyline
+n 1050 675 m
+ 1200 675 l gs col0 s gr
+% Polyline
+15.000 slw
+n 3750 2475 m 4950 2475 l 4950 2925 l 3750 2925 l
+ cp gs col0 s gr
+% Polyline
+n 3750 1425 m 4950 1425 l 4950 1875 l 3750 1875 l
+ cp gs col0 s gr
+% Polyline
+n 3750 525 m 4950 525 l 4950 975 l 3750 975 l
+ cp gs col0 s gr
+/Times-Italic ff 300.00 scf sf
+3900 2775 m
+gs 1 -1 sc (Filter 3) col0 sh gr
+/Times-Italic ff 300.00 scf sf
+3900 1725 m
+gs 1 -1 sc (Filter 2) col0 sh gr
+/Times-Italic ff 300.00 scf sf
+3900 825 m
+gs 1 -1 sc (Filter 1) col0 sh gr
+% Polyline
+7.500 slw
+n 300 525 m 1050 525 l 1050 3225 l 300 3225 l
+ cp gs col0 s gr
+% Polyline
+15.000 slw
+n 1650 1425 m 2550 1425 l 2550 1875 l 1650 1875 l
+ cp gs col1 s gr
+$F2psEnd
+rs
+showpage
diff --git a/contrib/sendmail/libmilter/docs/figure2.fig b/contrib/sendmail/libmilter/docs/figure2.fig
new file mode 100644
index 0000000..c93bfe3
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure2.fig
@@ -0,0 +1,67 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 2981.250 1200.000 2700 1050 3300 1200 2700 1350
+ 1 1 1.00 60.00 120.00
+6 4200 900 6450 1350
+2 2 0 1 1 7 50 0 -1 0.000 0 0 7 0 0 5
+ 4200 900 6450 900 6450 1350 4200 1350 4200 900
+4 0 1 50 0 0 16 0.0000 4 195 2040 4350 1200 xxfi_header callback\001
+-6
+6 4200 2250 6450 2700
+2 2 0 1 4 7 50 0 -1 0.000 0 0 7 0 0 5
+ 4200 2250 6450 2250 6450 2700 4200 2700 4200 2250
+4 0 4 50 0 0 16 0.0000 4 195 2040 4350 2550 xxfi_header callback\001
+-6
+6 600 2100 1800 2850
+2 2 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 5
+ 750 2250 1650 2250 1650 2700 750 2700 750 2250
+4 0 4 50 0 0 20 0.0000 4 195 645 900 2550 MTA\001
+-6
+6 600 750 1800 1500
+2 2 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 5
+ 750 900 1650 900 1650 1350 750 1350 750 900
+4 0 1 50 0 0 20 0.0000 4 195 645 900 1200 MTA\001
+-6
+2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 4200 1200 3600 1200
+2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 3450 900 4050 900
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 2400 300 6600 300 6600 3300 2400 3300 2400 300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 2550 750 3450 750 3450 2700 2550 2700 2550 750
+2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 3450 2700 4050 2700
+2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 4200 2400 3600 2400
+2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 1650 2700 2250 2700
+2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 2400 2400 1800 2400
+2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 1650 900 2250 900
+2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 2.00 120.00 240.00
+ 2400 1200 1800 1200
+4 0 0 50 0 0 20 0.0000 4 195 630 3900 600 Filter\001
+4 0 4 50 0 0 12 0.0000 4 180 1620 3450 3000 callback (arguments)\001
+4 0 4 50 0 0 12 0.0000 4 180 1575 3900 1950 optional library calls,\001
+4 0 4 50 0 0 12 0.0000 4 135 855 3900 2175 return code\001
+4 0 4 50 0 0 12 0.0000 4 135 780 1500 2100 responses\001
+4 0 0 50 0 0 16 0.0000 4 165 645 2700 2085 Milter\001
+4 0 0 50 0 0 16 0.0000 4 225 675 2700 2400 library\001
+4 0 4 50 0 0 12 0.0000 4 135 510 1500 3000 header\001
diff --git a/contrib/sendmail/libmilter/docs/figure2.jpg b/contrib/sendmail/libmilter/docs/figure2.jpg
new file mode 100644
index 0000000..8b11485
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure2.jpg
Binary files differ
diff --git a/contrib/sendmail/libmilter/docs/figure2.ps b/contrib/sendmail/libmilter/docs/figure2.ps
new file mode 100644
index 0000000..861a193
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/figure2.ps
@@ -0,0 +1,242 @@
+%!PS-Adobe-2.0
+%%Title: figure2.fig
+%%Creator: fig2dev Version 3.2.3 Patchlevel
+%%CreationDate: Tue Jun 6 13:57:47 2000
+%%For: sean@host232.Sendmail.COM (Sean O'rourke,5400)
+%%Orientation: Landscape
+%%Pages: 1
+%%BoundingBox: 0 0 612 792
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%Magnification: 1.5000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath
+144.0 65.5 translate
+ 90 rotate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+%%Page: 1 1
+10 setmiterlimit
+ 0.09000 0.09000 sc
+%%Page: 1 1
+/Times-Roman ff 180.00 scf sf
+1500 3000 m
+gs 1 -1 sc (header) col4 sh gr
+/Times-Roman ff 240.00 scf sf
+4350 1200 m
+gs 1 -1 sc (xxfi_header callback) col1 sh gr
+% Polyline
+7.500 slw
+n 4200 2250 m 6450 2250 l 6450 2700 l 4200 2700 l
+ cp gs col4 s gr
+/Times-Roman ff 240.00 scf sf
+4350 2550 m
+gs 1 -1 sc (xxfi_header callback) col4 sh gr
+% Polyline
+15.000 slw
+n 750 2250 m 1650 2250 l 1650 2700 l 750 2700 l
+ cp gs col4 s gr
+/Times-Roman ff 300.00 scf sf
+900 2550 m
+gs 1 -1 sc (MTA) col4 sh gr
+% Polyline
+n 750 900 m 1650 900 l 1650 1350 l 750 1350 l
+ cp gs col1 s gr
+/Times-Roman ff 300.00 scf sf
+900 1200 m
+gs 1 -1 sc (MTA) col1 sh gr
+% Arc
+7.500 slw
+gs clippath
+2713 1319 m 2667 1357 l 2761 1475 l 2710 1363 l 2808 1437 l cp
+eoclip
+n 2981.2 1200.0 318.8 -151.9 151.9 arc
+gs col0 s gr
+ gr
+
+% arrowhead
+n 2808 1437 m 2710 1363 l 2761 1475 l 2808 1437 l cp gs 0.00 setgray ef gr col0 s
+% Polyline
+15.000 slw
+gs clippath
+3585 1140 m 3585 1260 l 3872 1260 l 3632 1200 l 3872 1140 l cp
+eoclip
+n 4200 1200 m
+ 3600 1200 l gs col1 s gr gr
+
+% arrowhead
+n 3872 1140 m 3632 1200 l 3872 1260 l 3872 1140 l cp gs col1 1.00 shd ef gr col1 s
+% Polyline
+gs clippath
+4065 960 m 4065 840 l 3778 840 l 4018 900 l 3778 960 l cp
+eoclip
+n 3450 900 m
+ 4050 900 l gs col1 s gr gr
+
+% arrowhead
+n 3778 960 m 4018 900 l 3778 840 l 3778 960 l cp gs col1 1.00 shd ef gr col1 s
+% Polyline
+n 2400 300 m 6600 300 l 6600 3300 l 2400 3300 l
+ cp gs col0 s gr
+% Polyline
+7.500 slw
+n 2550 750 m 3450 750 l 3450 2700 l 2550 2700 l
+ cp gs col0 s gr
+% Polyline
+15.000 slw
+gs clippath
+4065 2760 m 4065 2640 l 3778 2640 l 4018 2700 l 3778 2760 l cp
+eoclip
+n 3450 2700 m
+ 4050 2700 l gs col4 s gr gr
+
+% arrowhead
+n 3778 2760 m 4018 2700 l 3778 2640 l 3778 2760 l cp gs col4 1.00 shd ef gr col4 s
+% Polyline
+gs clippath
+3585 2340 m 3585 2460 l 3872 2460 l 3632 2400 l 3872 2340 l cp
+eoclip
+n 4200 2400 m
+ 3600 2400 l gs col4 s gr gr
+
+% arrowhead
+n 3872 2340 m 3632 2400 l 3872 2460 l 3872 2340 l cp gs col4 1.00 shd ef gr col4 s
+% Polyline
+gs clippath
+2265 2760 m 2265 2640 l 1978 2640 l 2218 2700 l 1978 2760 l cp
+eoclip
+n 1650 2700 m
+ 2250 2700 l gs col4 s gr gr
+
+% arrowhead
+n 1978 2760 m 2218 2700 l 1978 2640 l 1978 2760 l cp gs col4 1.00 shd ef gr col4 s
+% Polyline
+gs clippath
+1785 2340 m 1785 2460 l 2072 2460 l 1832 2400 l 2072 2340 l cp
+eoclip
+n 2400 2400 m
+ 1800 2400 l gs col4 s gr gr
+
+% arrowhead
+n 2072 2340 m 1832 2400 l 2072 2460 l 2072 2340 l cp gs col4 1.00 shd ef gr col4 s
+% Polyline
+gs clippath
+2265 960 m 2265 840 l 1978 840 l 2218 900 l 1978 960 l cp
+eoclip
+n 1650 900 m
+ 2250 900 l gs col1 s gr gr
+
+% arrowhead
+n 1978 960 m 2218 900 l 1978 840 l 1978 960 l cp gs col1 1.00 shd ef gr col1 s
+% Polyline
+gs clippath
+1785 1140 m 1785 1260 l 2072 1260 l 1832 1200 l 2072 1140 l cp
+eoclip
+n 2400 1200 m
+ 1800 1200 l gs col1 s gr gr
+
+% arrowhead
+n 2072 1140 m 1832 1200 l 2072 1260 l 2072 1140 l cp gs col1 1.00 shd ef gr col1 s
+/Times-Roman ff 300.00 scf sf
+3900 600 m
+gs 1 -1 sc (Filter) col0 sh gr
+/Times-Roman ff 180.00 scf sf
+3450 3000 m
+gs 1 -1 sc (callback \(arguments\)) col4 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 1950 m
+gs 1 -1 sc (optional library calls,) col4 sh gr
+/Times-Roman ff 180.00 scf sf
+3900 2175 m
+gs 1 -1 sc (return code) col4 sh gr
+/Times-Roman ff 180.00 scf sf
+1500 2100 m
+gs 1 -1 sc (responses) col4 sh gr
+/Times-Roman ff 240.00 scf sf
+2700 2085 m
+gs 1 -1 sc (Milter) col0 sh gr
+/Times-Roman ff 240.00 scf sf
+2700 2400 m
+gs 1 -1 sc (library) col0 sh gr
+% Polyline
+7.500 slw
+n 4200 900 m 6450 900 l 6450 1350 l 4200 1350 l
+ cp gs col1 s gr
+$F2psEnd
+rs
+showpage
diff --git a/contrib/sendmail/libmilter/docs/index.html b/contrib/sendmail/libmilter/docs/index.html
new file mode 100644
index 0000000..44c5f90
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/index.html
@@ -0,0 +1,92 @@
+<html>
+<head>
+<title>Filtering Mail with Sendmail</title>
+</head>
+<body>
+<!--
+$Id: index.html,v 1.10 2001/06/01 00:05:03 ca Exp $
+-->
+
+<h1>Filtering Mail with Sendmail</h1>
+
+<!--
+<P><b>Disclaimer</b>:
+This preliminary API description is provided for review only. This
+specification may change based on feedback from reviewers, and does
+not bind Sendmail to offer this functionality in any release.
+-->
+
+<h2>Introduction</h2>
+
+<P>
+Sendmail's Content Management API (milter) provides third-party
+programs to access mail messages as they are being processed by the
+Mail Transfer Agent (MTA), allowing them to examine and modify message
+content and meta-information. Filtering policies implemented by
+Milter-conformant filters may then be centrally configured and
+composed in an end-user's MTA configuration file.
+
+<p>
+Possible uses for filters include spam rejection, virus
+filtering, and content control. In general, Milter seeks to address
+site-wide filtering concerns in a scalable way. Individual users' mail
+filtering needs (e.g. sorting messages by subject) are left to
+client-level programs such as <a href="http://www.procmail.org">Procmail</a>.
+
+<P>
+This document is a technical introduction intended for those
+interested in developing Milter filters. It includes:
+<ul>
+<li>A description of Milter's design goals.
+
+<li>An explanation of Milter application architecture, including
+interactions between the support library and user code, and between
+filters and the MTA.
+
+<li>A specification of the C application programming interface.
+<li>An example of a simple Milter filter.
+</ul>
+
+<h2>Contents</h2>
+
+<ul>
+<li><a href="design.html">Architecture</a>
+<ul>
+ <li>Design Goals
+ <li>Implementing Filtering Policies
+ <li>MTA - Filter communication
+</ul>
+<li><a href="overview.html">Technical Overview</a>
+<ul>
+ <li>Initialization
+ <li>Control flow
+ <li>Multithreading
+ <li>Resource Management
+ <li>Signal Handling
+</ul>
+<li><a href="api.html">API Documentation</a>
+<ul>
+ <li>Library Control Functions
+ <li>Data Access Functions
+ <li>Message Modification Functions
+ <li>Callbacks
+</ul>
+<li><a href="installation.html">Installation and Configuration</a>
+<ul>
+ <li>Compiling and Installing Your Filter
+ <li>Configuring Sendmail
+</ul>
+<li><a href="sample.html">A Sample Filter</a>
+<!-- <li><a href="other.html">Other Sources of Information</a> -->
+</ul>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000, 2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/installation.html b/contrib/sendmail/libmilter/docs/installation.html
new file mode 100644
index 0000000..8ebe4ee
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/installation.html
@@ -0,0 +1,169 @@
+<html>
+<head><title>Installation and Configuration</title>
+</head>
+<body>
+<h1>Installation</h1>
+<h2>Contents</h2>
+<ul>
+ <li><a href="#compile">Compiling and Installing Your Filter</a>
+ <li><a href="#config">Configuring Sendmail</a>
+</ul>
+
+<h2><a name="compile">Compiling and Installing Your Filter</A></h2>
+
+To compile a filter, modify the Makefile provided with the sample program, or:
+<ul>
+ <li>Put the include and Sendmail directories in your include path
+ (e.g. -I/path/to/include -I/path/to/sendmail).
+
+ <li>Make sure libmilter.so is in your library path, and link your
+ application with it (e.g. "-lmilter").
+
+ <li>Compile with pthreads, either by using -pthread for gcc, or
+ linking with a pthreads support library (-lpthread).
+</ul>
+Your compile command line will look like
+<pre>
+cc -I/path/to/include -I/path/to/sendmail -c myfile.c
+</pre>
+and your linking command line will look something like
+<pre>
+cc -o myfilter [object-files] -L[library-location] -lmilter -pthread
+</pre>
+
+<p>
+To run the filter, the Milter shared library must be available to the
+run-time linker.
+
+<H2><a name="config">Configuring Sendmail</A></H2>
+
+First, you must compile sendmail versions before 8.12 with _FFR_MILTER
+defined. To do this, add the following lines to your build
+configuration file (devtools/Site/config.site.m4)
+<pre>
+APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1')
+APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1')
+</pre>
+
+then type <code>./Build -c</code> in your sendmail directory.
+
+<P>
+Next, you must add the desired filters to your sendmail configuration
+(.mc) file. With versions before 8.12, the file must then be
+processed with _FFR_MILTER defined. Mail filters have three equates:
+The required <code>S=</code> equate specifies the socket where
+sendmail should look for the filter; The optional <code>F=</code> and
+<code>T=</code> equates specify flags and timeouts, respectively. All
+equates names, equate field names, and flag values are case sensitive.
+
+<P>
+The current flags (<code>F=</code>) are:
+<p>
+<table cellspacing="1" cellpadding=4 border=1>
+<tr bgcolor="#dddddd" align=left valign=top>
+<th>Flag</TH> <th align="center">Meaning</TH>
+</TR>
+<tr align="left" valign=top>
+<TD>R</TD> <TD>Reject connection if filter unavailable</TD>
+</TR>
+<tr align="left" valign=top>
+<TD>T</TD> <TD>Temporary fail connection if filter unavailable</TD>
+</TR>
+</TABLE>
+
+If a filter is unavailable or unresponsive and no flags have been
+specified, the MTA will continue normal handling of the current
+connection. The MTA will try to contact the filter again on each new
+connection.
+
+<P>
+There are three fields inside of the <code>T=</code> equate: S, R, and
+E. Note the separator between each is a ";" (semicolon), as ","
+(comma) already separates equates. The value of each field is a
+decimal number followed by a single letter designating the units ("s"
+for seconds, "m" for minutes). The fields have the following
+meanings:
+<p>
+<TABLE cellspacing="1" cellpadding=4 border=1>
+<TR bgcolor="#dddddd" align=left valign=top>
+<TH>Flag</TH> <TH align="center">Meaning</TH>
+</TR>
+<TR align="left" valign=top>
+<TD>C</TD> <TD>Timeout for connecting to a filter. If set to 0, the
+ system's <CODE>connect()</CODE> timeout will be used.
+ Default: 5m</TD>
+</TR>
+<TR align="left" valign=top>
+<TD>S</TD> <TD>Timeout for sending information from the MTA to a
+ filter. Default: 10s</TD>
+</TR>
+<TR align="left" valign=top>
+<TD>R</TD> <TD>Timeout for reading reply from the filter. Default: 10s</TD>
+</TR>
+<TR align="left" valign=top>
+<TD>E</TD> <TD>Overall timeout between sending end-of-message to
+ filter and waiting for the final acknowledgment. Default: 5m</TD>
+</TR>
+</TABLE>
+
+<p>
+The following sendmail.mc example specifies three filters. The first
+two rendezvous on Unix-domain sockets in the /var/run directory; the
+third uses an IP socket on port 999.
+<pre>
+ INPUT_MAIL_FILTER(`filter1', `S=unix:/var/run/f1.sock, F=R')
+ INPUT_MAIL_FILTER(`filter2', `S=unix:/var/run/f2.sock, F=T, T=S:1s;R:1s;E:5m')
+ INPUT_MAIL_FILTER(`filter3', `S=inet:999@localhost, T=C:2m')
+
+ define(`confINPUT_MAIL_FILTERS', `filter2,filter1,filter3')
+<hr width="30%">
+ m4 <b>-D_FFR_MILTER</b> ../m4/cf.m4 myconfig.mc &gt; myconfig.cf
+</pre>
+By default, the filters would be run in the order declared,
+i.e. "filter1, filter2, filter3"; however, since
+<code>confINPUT_MAIL_FILTERS</code> is defined, the filters will be
+run "filter2, filter1, filter3". Also note that a filter can be
+defined without adding it to the input filter list by using
+MAIL_FILTER() instead of INPUT_MAIL_FILTER().
+
+<p>
+The above macros will result in the following lines being added to
+your .cf file:
+<PRE>
+ Xfilter1, S=unix:/var/run/f1.sock, F=R
+ Xfilter2, S=unix:/var/run/f2.sock, F=T, T=S:1s;R:1s;E:5m
+ Xfilter3, S=inet:999@localhost, T=C:2m
+
+ O InputMailFilters=filter2,filter1,filter3
+</PRE>
+<p>
+Finally, the sendmail macros accessible via <a
+href="smfi_getsymval.html">smfi_getsymval</a> can be configured by
+defining the following m4 variables (or cf options):
+<table cellspacing="1" cellpadding=4 border=1>
+<tr bgcolor="#dddddd" align=left valign=top>
+<th align="center">In .mc file</th> <th align="center">In .cf file</TH>
+<th align="center">Default Value</th>
+</tr>
+<tr><td>confMILTER_MACROS_CONNECT</td><td>Milter.macros.connect</td>
+<td><code>j, _, {daemon_name}, {if_name}, {if_addr}</code></td></tr>
+<tr><td>confMILTER_MACROS_HELO</td><td>Milter.macros.helo</td>
+<td><code>{tls_version}, {cipher}, {cipher_bits}, {cert_subject},
+{cert_issuer}</code></td></tr>
+<tr><td>confMILTER_MACROS_ENVFROM</td><td>Milter.macros.envfrom</td>
+<td><code>i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author},
+{mail_mailer}, {mail_host}, {mail_addr}</code></td></tr>
+<tr><td>confMILTER_MACROS_ENVRCPT</td><td>Milter.macros.envrcpt</td>
+<td><code>{rcpt_mailer}, {rcpt_host}, {rcpt_addr}</code></td></tr>
+</table>
+For information about available macros and their meanings, please
+consult the sendmail documentation.
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body> </html>
diff --git a/contrib/sendmail/libmilter/docs/other.html b/contrib/sendmail/libmilter/docs/other.html
new file mode 100644
index 0000000..8ec9ffd
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/other.html
@@ -0,0 +1,15 @@
+<html>
+<head><title>Other Resources</title>
+</head>
+<body>
+FAQ? Mailing list? More sample filters?
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/overview.html b/contrib/sendmail/libmilter/docs/overview.html
new file mode 100644
index 0000000..7f1c036
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/overview.html
@@ -0,0 +1,194 @@
+<html>
+<head>
+<title>Technical Overview</title>
+</head>
+<body>
+<!--
+$Id: overview.html,v 1.12 2001/06/01 00:05:03 ca Exp $
+-->
+
+<h1>Technical Overview</h1>
+
+<h2>Contents</h2>
+
+<ul>
+ <li>Initialization
+ <li>Control flow
+ <li>Multithreading
+ <li>Resource Management
+ <li>Signal Handling
+</ul>
+
+<h2>Initialization</h2>
+
+In addition to its own initialization, libmilter expects a filter to initialize several parameters before calling <a href="smfi_main.html">smfi_main</a>:
+<ul>
+ <li>The callbacks the filter wishes to be called, and the types of
+ message modification it intends to perform (required, see <a
+ href="smfi_register.html">smfi_register</a>).
+
+ <li>The socket address to be used when communicating with the MTA
+ (required, see <a href="smfi_setconn.html">smfi_setconn</a>).
+
+ <li>The number of seconds to wait for MTA connections before
+ timing out (optional, see <a
+ href="smfi_settimeout.html">smfi_settimeout</a>).
+</ul>
+<p>
+If the filter fails to initialize libmilter, or if one or more of the
+parameters it has passed are invalid, a subsequent call to smfi_main
+will fail.
+
+<h2>Control flow</h2>
+
+<p>
+The following pseudocode describes the filtering process from the
+perspective of a set of <code>N</code> MTA's, each corresponding to a
+connection. Callbacks are shown beside the processing stages in which
+they are invoked; if no callbacks are defined for a particular stage,
+that stage may be bypassed. Though it is not shown, processing may be
+aborted at any time during a message, in which case the <a
+href="xxfi_abort.html">xxfi_abort</a> callback is invoked and control
+returns to <code>MESSAGE</code>.
+<p>
+<pre>
+For each of N connections
+{
+ For each filter
+ process connection/helo (<a href="xxfi_connect.html">xxfi_connect</a>, <a href="xxfi_helo.html">xxfi_helo</a>)
+MESSAGE:For each message in this connection (sequentially)
+ {
+ For each filter
+ process sender (<a href="xxfi_envfrom.html">xxfi_envfrom</a>)
+ For each recipient
+ {
+ For each filter
+ process recipient (<a href="xxfi_envrcpt.html">xxfi_envrcpt</a>)
+ }
+ For each filter
+ {
+ For each header
+ process header (<a href="xxfi_header.html">xxfi_header</a>)
+ process end of headers (<a href="xxfi_eoh.html">xxfi_eoh</a>)
+ For each body block
+ process this body block (<a href="xxfi_body.html">xxfi_body</a>)
+ process end of message (<a href="xxfi_eom.html">xxfi_eom</a>)
+ }
+ }
+ For each filter
+ process end of connection (<a href="xxfi_close.html">xxfi_close</a>)
+}
+</pre>
+
+<P>Note: Filters are contacted in order defined in config file.</P>
+
+<P>
+To write a filter, a vendor supplies callbacks to process relevant
+parts of a message transaction. The library then controls all
+sequencing, threading, and protocol exchange with the MTA. <a
+href="#figure-3">Figure 3</a> outlines control flow for a filter
+process, showing where different callbacks are invoked.
+</p>
+<div align="center"><a name="figure-3"></a>
+<table border=1 cellspacing=0 cellpadding=2 width="70%">
+<tr bgcolor="#dddddd"><th>SMTP Commands</th><th>Milter Callbacks</th></tr>
+<tr><td>(open SMTP connection)</td><td>xxfi_connect</td></tr>
+<tr><td>HELO ...</td><td>xxfi_helo</td></tr>
+<tr><td>MAIL From: ...</td><td>xxfi_envfrom</td></tr>
+<tr><td>RCPT To: ...</td><td>xxfi_envrcpt</td></tr>
+<tr><td>[more RCPTs]</td><td>[xxfi_envrcpt]</td></tr>
+<tr><td>DATA</td><td>&nbsp;</td></tr>
+<tr><td>Header: ...</td><td>xxfi_header</td></tr>
+<tr><td>[more headers]</td><td>[xxfi_header]</td></tr>
+<tr><td>&nbsp;</td><td>xxfi_eoh</td></tr>
+<tr><td>body... </td><td>xxfi_body</td></tr>
+<tr><td>[more body...]</td><td>[xxfi_body]</td></tr>
+<tr><td>.</td><td>xxfi_eom</td></tr>
+<tr><td>QUIT</td><td>xxfi_close</td></tr>
+<tr><td>(close SMTP connection)</td><td>&nbsp;</td></tr>
+</table>
+<b>Figure 3: Milter callbacks related to an SMTP transaction.</b>
+</div>
+<p>
+Note that although only a single message is shown above, multiple
+messages may be sent in a single connection. Note also that a message
+and/or connection may be aborted by either the remote host or the MTA
+at any point during the SMTP transaction. If this occurs during a
+message (between the MAIL command and the final "."), the filter's <a
+href="xxfi_abort.html">xxfi_abort</a> routine will be called. <a
+href="xxfi_close.html">xxfi_close</a> is called any time the
+connection closes.
+
+<h2>Multithreading</h2>
+
+<p>
+A single filter process may handle any number of connections
+simultaneously. All filtering callbacks must therefore be reentrant,
+and use some appropriate external synchronization methods to access
+global data. Furthermore, since there is not a one-to-one
+correspondence between threads and connections (N connections mapped
+onto M threads, M &lt;= N), connection-specific data must be accessed
+through the handles provided by the Milter library. The programmer
+cannot rely on library-supplied thread-specific data blocks
+(e.g. pthread_getspecific()) to store connection-specific data. See
+the API documentation for <a
+href="smfi_setpriv.html">smfi_setpriv</a> and <a
+href="smfi_getpriv.html">smfi_getpriv</a> for details.
+
+<h2>Resource management</h2>
+
+Since filters are likely to be long-lived, and to handle many
+connections, proper deallocation of per-connection resources is
+important. The lifetime of a connection is bracketed by calls to the
+callbacks <a href="xxfi_connect.html">xxfi_connect</a> and <a
+href="xxfi_close.html">xxfi_close</a>. Therefore connection-specific
+resources (accessed via <a href="smfi_getpriv.html">smfi_getpriv</a>
+and <a href="smfi_setpriv.html">smfi_setpriv</a>) may be allocated in
+<a href="xxfi_connect.html">xxfi_connect</a>, and should be freed in
+<a href="xxfi_close.html">xxfi_close</a>. For further information see
+the <a href="api.html#conn-msg">discussion</a> of message- versus
+connection-oriented routines. In particular, note that there is only
+one connection-specific data pointer per connection.
+<p>
+
+Each message is bracketed by calls to <a
+href="xxfi_envfrom.html">xxfi_envfrom</a> and <a
+href="xxfi_eom.html">xxfi_eom</a> (or <a
+href="xxfi_abort.html">xxfi_abort</a>), implying that message-specific
+resources can be allocated and reclaimed in these routines. Since the
+messages in a connection are processed sequentially by each filter,
+there will be only one active message associated with a given
+connection and filter (and connection-private data block). These
+resources must still be accessed through <a
+href="smfi_getpriv.html">smfi_getpriv</a> and <a
+href="smfi_setpriv.html">smfi_setpriv</a>, and must be reclaimed
+in <a href="xxfi_abort.html">xxfi_abort</a>.
+
+<h2>Signal Handling</h2>
+
+libmilter takes care of signal handling, the filters are
+not influenced directly by signals.
+There are basically two types of signal handlers:
+
+<ol>
+<li><TT>Stop</TT>: no new connections from the MTA will be accepted,
+but existing connections are allowed to continue.
+<li><TT>Abort</TT>: all filters will be stopped as soon as the next
+communication with the MTA happens.
+</ol>
+
+Filters are not terminated asynchronously (except by
+signals that can't be caught).
+In the case of <TT>Abort</TT> the
+<a href="xxfi_abort.html">xxfi_abort</a> callback is invoked.
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000, 2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/sample.html b/contrib/sendmail/libmilter/docs/sample.html
new file mode 100644
index 0000000..7e99704
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/sample.html
@@ -0,0 +1,426 @@
+<html>
+<head><title>A Sample Filter</title></head>
+<body>
+<h1>A Sample Filter</h1>
+
+The following sample logs each message to a separate temporary file,
+adds a recipient given with the -a flag, and rejects a disallowed
+recipient address given with the -r flag. It recognizes the following
+options:
+<p>
+<center>
+<table border="1" cellpadding=2 cellspacing=1>
+<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr>
+<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr>
+<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr>
+<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr>
+</table>
+</center>
+<hr>
+<pre>
+#include "mfapi.h"
+
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;sys/types.h&gt;
+#include &lt;sys/stat.h&gt;
+#include &lt;sysexits.h&gt;
+#include &lt;unistd.h&gt;
+#ifndef bool
+#define bool char
+#define TRUE 1
+#define FALSE 0
+#endif
+
+extern int errno;
+
+
+struct mlfiPriv
+{
+ char *mlfi_fname;
+ char *mlfi_connectfrom;
+ char *mlfi_helofrom;
+ FILE *mlfi_fp;
+};
+
+#define MLFIPRIV ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx))
+
+extern sfsistat mlfi_cleanup(SMFICTX *, bool);
+/* recipients to add and reject (set with -a and -r options) */
+char *add, *reject;
+
+sfsistat
+<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr)
+ SMFICTX *ctx;
+ char *hostname;
+ _SOCK_ADDR *hostaddr;
+{
+ struct mlfiPriv *priv;
+ char *ident;
+
+ /* allocate some private memory */
+ priv = malloc(sizeof *priv);
+ if (priv == NULL)
+ {
+ /* can't accept this message right now */
+ return SMFIS_TEMPFAIL;
+ }
+ memset(priv, '\0', sizeof *priv);
+
+ /* save the private data */
+ <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv);
+
+ ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_");
+ if(!ident) ident = "???";
+ if(!(priv-&gt;mlfi_connectfrom = strdup(ident))) {
+ return SMFIS_TEMPFAIL;
+ }
+ /* Continue processing. */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost)
+ SMFICTX *ctx;
+ char *helohost;
+{
+ char *tls;
+ char *buf;
+ struct mlfiPriv *priv = MLFIPRIV;
+ tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}");
+ if(!tls) tls = "No TLS";
+ if(!helohost) helohost = "???";
+ if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) {
+ return SMFIS_TEMPFAIL;
+ }
+ sprintf(buf, "%s, %s", helohost, tls);
+ if(priv-&gt;mlfi_helofrom)
+ free(priv-&gt;mlfi_helofrom);
+ priv-&gt;mlfi_helofrom = buf;
+ /* Continue processing. */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv)
+ SMFICTX *ctx;
+ char **argv;
+{
+ struct mlfiPriv *priv = MLFIPRIV;
+ char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}");
+ int argc = 0;
+
+ /* open a file to store this message */
+ priv-&gt;mlfi_fname = strdup("/tmp/msg.XXXXXX");
+ mkstemp(priv-&gt;mlfi_fname);
+ if (priv-&gt;mlfi_fname == NULL)
+ return SMFIS_TEMPFAIL;
+ if ((priv-&gt;mlfi_fp = fopen(priv-&gt;mlfi_fname, "w+")) == NULL)
+ {
+ free(priv-&gt;mlfi_fname);
+ return SMFIS_TEMPFAIL;
+ }
+
+ /* count the arguments */
+ while(*argv++) ++argc;
+ /* log the connection information we stored earlier: */
+ if(fprintf(priv-&gt;mlfi_fp, "Connect from %s (%s)\n\n",
+ priv-&gt;mlfi_helofrom, priv-&gt;mlfi_connectfrom) == EOF) {
+ (void) mlfi_cleanup(ctx, FALSE);
+ return SMFIS_TEMPFAIL;
+ }
+ /* log the sender */
+ if(fprintf(priv-&gt;mlfi_fp, "FROM %s (%d argument%s)\n",
+ mailaddr?mailaddr:"???", argc,
+ (argc == 1)?"":"s")
+ == EOF) {
+ (void) mlfi_cleanup(ctx, FALSE);
+ return SMFIS_TEMPFAIL;
+ }
+ /* continue processing */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv)
+ SMFICTX *ctx;
+ char **argv;
+{
+ struct mlfiPriv *priv = MLFIPRIV;
+ char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}");
+ int argc = 0;
+ /* count the arguments */
+ while(*argv++) ++argc;
+ /* log this recipient */
+ if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) {
+ if(fprintf(priv-&gt;mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr)
+ == EOF) {
+ (void) mlfi_cleanup(ctx, FALSE);
+ return SMFIS_TEMPFAIL;
+ }
+ return SMFIS_REJECT;
+ }
+ if(fprintf(priv-&gt;mlfi_fp, "RCPT %s (%d argument%s)\n",
+ rcptaddr?rcptaddr:"???", argc,
+ (argc == 1)?"":"s")
+ == EOF) {
+ (void) mlfi_cleanup(ctx, FALSE);
+ return SMFIS_TEMPFAIL;
+ }
+ /* continue processing */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv)
+ SMFICTX *ctx;
+ char *headerf;
+ unsigned char *headerv;
+{
+ /* write the header to the log file */
+ fprintf(MLFIPRIV-&gt;mlfi_fp, "%s: %s\n", headerf, headerv);
+
+ /* continue processing */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx)
+ SMFICTX *ctx;
+{
+ /* output the blank line between the header and the body */
+ fprintf(MLFIPRIV-&gt;mlfi_fp, "\n");
+
+ /* continue processing */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen)
+ SMFICTX *ctx;
+ unsigned char *bodyp;
+ size_t bodylen;
+{
+ /* output body block to log file */
+ int nwritten;
+ if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV-&gt;mlfi_fp)) != 1)
+ {
+ /* write failed */
+ perror("error logging body");
+ (void) mlfi_cleanup(ctx, FALSE);
+ return SMFIS_TEMPFAIL;
+ }
+
+ /* continue processing */
+ return SMFIS_CONTINUE;
+}
+
+sfsistat
+<a href="xxfi_eom.html">mlfi_eom</a>(ctx)
+ SMFICTX *ctx;
+{
+ bool ok = TRUE;
+ /* change recipients, if requested */
+ if(add)
+ ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS);
+ return mlfi_cleanup(ctx, ok);
+}
+
+sfsistat
+<a href="xxfi_abort.html">mlfi_abort</a>(ctx)
+ SMFICTX *ctx;
+{
+ return mlfi_cleanup(ctx, FALSE);
+}
+
+sfsistat
+mlfi_cleanup(ctx, ok)
+ SMFICTX *ctx;
+ bool ok;
+{
+ sfsistat rstat = SMFIS_CONTINUE;
+ struct mlfiPriv *priv = MLFIPRIV;
+ char *p;
+ char host[512];
+ char hbuf[1024];
+
+ if (priv == NULL)
+ return rstat;
+
+ /* close the archive file */
+ if (priv-&gt;mlfi_fp != NULL && fclose(priv-&gt;mlfi_fp) == EOF)
+ {
+ /* failed; we have to wait until later */
+ fprintf(stderr, "Couldn't close archive file %s: %s\n",
+ priv-&gt;mlfi_fname, strerror(errno));
+ rstat = SMFIS_TEMPFAIL;
+ (void) unlink(priv-&gt;mlfi_fname);
+ }
+ else if (ok)
+ {
+ /* add a header to the message announcing our presence */
+ if (gethostname(host, sizeof host) &lt; 0)
+ strncpy(host, "localhost", sizeof host);
+ p = strrchr(priv-&gt;mlfi_fname, '/');
+ if (p == NULL)
+ p = priv-&gt;mlfi_fname;
+ else
+ p++;
+ snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
+ <a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf);
+ }
+ else
+ {
+ /* message was aborted -- delete the archive file */
+ fprintf(stderr, "Message aborted. Removing %s\n",
+ priv-&gt;mlfi_fname);
+ rstat = SMFIS_TEMPFAIL;
+ (void) unlink(priv-&gt;mlfi_fname);
+ }
+
+ /* release private memory */
+ free(priv-&gt;mlfi_fname);
+
+ /* return status */
+ return rstat;
+}
+
+sfsistat
+<a href="xxfi_close.html">mlfi_close</a>(ctx)
+ SMFICTX *ctx;
+{
+ struct mlfiPriv *priv = MLFIPRIV;
+ if(priv-&gt;mlfi_connectfrom)
+ free(priv-&gt;mlfi_connectfrom);
+ if(priv-&gt;mlfi_helofrom)
+ free(priv-&gt;mlfi_helofrom);
+ free(priv);
+ <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL);
+ return SMFIS_CONTINUE;
+}
+
+struct smfiDesc smfilter =
+{
+ "SampleFilter", /* filter name */
+ SMFI_VERSION, /* version code -- do not change */
+ SMFIF_ADDHDRS, /* flags */
+ <a href="xxfi_connect.html">mlfi_connect</a>, /* connection info filter */
+ <a href="xxfi_helo.html">mlfi_helo</a>, /* SMTP HELO command filter */
+ <a href="xxfi_envfrom.html">mlfi_envfrom</a>, /* envelope sender filter */
+ <a href="xxfi_envrcpt.html">mlfi_envrcpt</a>, /* envelope recipient filter */
+ <a href="xxfi_header.html">mlfi_header</a>, /* header filter */
+ <a href="xxfi_eoh.html">mlfi_eoh</a>, /* end of header */
+ <a href="xxfi_body.html">mlfi_body</a>, /* body block filter */
+ <a href="xxfi_eom.html">mlfi_eom</a>, /* end of message */
+ <a href="xxfi_abort.html">mlfi_abort</a>, /* message aborted */
+ <a href="xxfi_close.html">mlfi_close</a>, /* connection cleanup */
+};
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\
+\t[-a accept-addr]\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int retval;
+ char c;
+ const char *args = "p:t:r:a:h";
+ extern char *optarg;
+
+ /* Process command line options */
+ while ((c = getopt(argc, argv, args)) != (char)EOF)
+ {
+ switch (c)
+ {
+ case 'p':
+ if (optarg == NULL || *optarg == '\0')
+ {
+ (void) fprintf(stderr, "Illegal conn: %s\n",
+ optarg);
+ exit(EX_USAGE);
+ }
+ if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE)
+ {
+ (void) fputs("smfi_setconn failed", stderr);
+ exit(EX_SOFTWARE);
+ }
+ /*
+ ** If we're using a local socket, make sure it doesn't
+ ** already exist.
+ */
+ if(strncmp(optarg, "unix:", 5) == 0)
+ unlink(optarg + 5);
+ else if(strncmp(optarg, "local:", 6) == 0)
+ unlink(optarg + 6);
+ break;
+
+ case 't':
+ if (optarg == NULL || *optarg == '\0')
+ {
+ (void) fprintf(stderr, "Illegal timeout: %s\n",
+ optarg);
+ exit(EX_USAGE);
+ }
+ if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE)
+ {
+ (void) fputs("smfi_settimeout failed", stderr);
+ exit(EX_SOFTWARE);
+ }
+ break;
+
+ case 'r':
+ if (optarg == NULL)
+ {
+ (void) fprintf(stderr, "Illegal reject rcpt: %s\n",
+ optarg);
+ exit(EX_USAGE);
+ }
+ reject = optarg;
+ break;
+
+ case 'a':
+ if (optarg == NULL)
+ {
+ (void) fprintf(stderr, "Illegal add rcpt: %s\n",
+ optarg);
+ exit(EX_USAGE);
+ }
+ add = optarg;
+ smfilter.xxfi_flags |= SMFIF_ADDRCPT;
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+ if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE)
+ {
+ fprintf(stderr, "smfi_register failed\n");
+ exit(EX_UNAVAILABLE);
+ }
+ retval = <a href="smfi_main.html">smfi_main</a>();
+ return retval;
+}
+
+/* eof */
+
+</pre>
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_addheader.html b/contrib/sendmail/libmilter/docs/smfi_addheader.html
new file mode 100644
index 0000000..c6417e2
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_addheader.html
@@ -0,0 +1,94 @@
+<html>
+<head><title>smfi_addheader</title></head>
+<body>
+<h1>smfi_addheader</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_addheader(
+ SMFICTX *ctx,
+ char *headerf,
+ char *headerv
+);
+</pre>
+Add a header to the current message.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>Called only from <a href="xxfi_eom.html">xxfi_eom</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Adds a header to the current message.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>headerf</td>
+ <td>The header name, a non-NULL, null-terminated string.
+ </td></tr>
+ <tr valign="top"><td>headerv</td>
+ <td>The header value to be added, a non-NULL, null-terminated string. This may be the empty string.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_addheader returns MI_FAILURE if:
+<ul><li>headerf or headerv is NULL.
+ <li>Adding headers in the current connection state is invalid.
+ <li>Memory allocation fails.
+ <li>A network error occurs.
+ <li>SMFIF_ADDHDRS was not set when <a href="smfi_register.html">smfi_register</a> was called.
+</ul>
+Otherwise, it returns MI_SUCCESS.
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+<ul><li>smfi_addheader does not change a message's existing headers.
+To change a header's current value, use <a
+href="smfi_chgheader.html">smfi_chgheader</a>.
+ <li>A filter which calls smfi_addheader must have set the SMFIF_ADDHDRS flag in the smfiDesc_str passed to <a href="smfi_register.html">smfi_register</a>.
+ <li>For smfi_chgheader, filter order is important. <b>Later filters will see the header changes made by earlier ones.</b>
+ <li>Neither the name nor the value of the header is checked for
+ standards compliance. However, each line of the header must be under
+ 2048 characters and should be under 998 characters. If longer headers
+ are needed, make them multiline.
+ <b>It is the filter writer's responsibility to ensure that no standards
+ are violated.</b>
+</ul>
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_addrcpt.html b/contrib/sendmail/libmilter/docs/smfi_addrcpt.html
new file mode 100644
index 0000000..d0a5963
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_addrcpt.html
@@ -0,0 +1,80 @@
+<html>
+<head><title>smfi_addrcpt</title></head>
+<body>
+<h1>smfi_addrcpt</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_addrcpt(
+ SMFICTX *ctx,
+ char *rcpt
+);
+</pre>
+Add a recipient for the current message.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>Called only from <a href="xxfi_eom.html">xxfi_eom</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Add a recipient to the message envelope.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>rcpt</td>
+ <td>The new recipient's address.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_addrcpt will fail and return MI_FAILURE if:
+<ul><li>rcpt is NULL.
+ <li>Adding headers in the current connection state is invalid.
+ <li>A network error occurs.
+ <li>SMFIF_ADDRCPT was not set when <a href="smfi_register.html">smfi_register</a> was called.
+</ul>
+Otherwise, it will return MI_SUCCESS.
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+A filter which calls smfi_addrcpt must have set the SMFIF_ADDRCPT flag
+in the smfiDesc_str passed to
+<a href="smfi_register.html">smfi_register</a>.
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_chgheader.html b/contrib/sendmail/libmilter/docs/smfi_chgheader.html
new file mode 100644
index 0000000..4969674
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_chgheader.html
@@ -0,0 +1,96 @@
+<html>
+<head><title>smfi_chgheader</title></head>
+<body>
+<h1>smfi_chgheader</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_chgheader(
+ SMFICTX *ctx,
+ char *headerf,
+ mi_int32 hdridx,
+ char *headerv
+);
+</pre>
+Change or delete a message header.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>Called only from <a href="xxfi_eom.html">xxfi_eom</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Changes a header's value for the current message.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>headerf</td>
+ <td>The header name, a non-NULL, null-terminated string.
+ </td></tr>
+ <tr valign="top"><td>hdridx</td>
+ <td>Header index value (1-based). A hdridx value of 1 will modify the first occurrence of a header named headerf. If hdridx is greater than the number of times headerf appears, a new copy of headerf will be added.
+ </td></tr>
+ <tr valign="top"><td>headerv</td>
+ <td>The new value of the given header. headerv == NULL implies that the header should be deleted.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>
+smfi_chgheader will return MI_FAILURE if
+<ul><li>headerf is NULL
+ <li>Modifying headers in the current connection state is invalid.
+ <li>Memory allocation fails.
+ <li>A network error occurs.
+ <li>SMFIF_CHGHDRS was not set when <a href="smfi_register.html">smfi_register</a> was called.
+</ul>
+Otherwise, it returns MI_SUCCESS.
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+<ul><li>While smfi_chgheader may be used to add new headers, it is more efficient and far safer to use <a href="smfi_addheader.html">smfi_addheader</a>.
+ <li>A filter which calls smfi_chgheader must have set the SMFIF_CHGHDRS flag in the smfiDesc_str passed to <a href="smfi_register.html">smfi_register</a>.
+ <li>For smfi_chgheader, filter order is important. <b>Later filters will see the header changes made by earlier ones.</b>
+ <li>Neither the name nor the value of the header is checked for
+ standards compliance. However, each line of the header must be under
+ 2048 characters and should be under 998 characters. If longer headers
+ are needed, make them multiline.
+ <b>It is the filter writer's responsibility to ensure that no standards
+ are violated.</b>
+</ul>
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_delrcpt.html b/contrib/sendmail/libmilter/docs/smfi_delrcpt.html
new file mode 100644
index 0000000..f86fd2e
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_delrcpt.html
@@ -0,0 +1,79 @@
+<html>
+<head><title>smfi_delrcpt</title></head>
+<body>
+<h1>smfi_delrcpt</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_delrcpt(
+ SMFICTX *ctx;
+ char *rcpt;
+);
+</pre>
+Remove a recipient from the current message's envelope.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>Called only from <a href="xxfi_eom.html">xxfi_eom</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>smfi_delrcpt removes the named recipient from the current message's envelope.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>rcpt</td>
+ <td>The recipient address to be removed, a non-NULL, null-terminated string.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_delrcpt will fail and return MI_FAILURE if:
+<ul>
+ <li>rcpt is NULL.
+ <li>Adding headers in the current connection state is invalid.
+ <li>A network error occurs.
+ <li>SMFIF_DELRCPT was not set when <a href="smfi_register.html">smfi_register</a> was called.
+</ul>
+Otherwise, it will return MI_SUCCESS
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+The addresses to be removed must match exactly. For example, an address and its expanded form do not match.
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_getpriv.html b/contrib/sendmail/libmilter/docs/smfi_getpriv.html
new file mode 100644
index 0000000..8bb6efa
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_getpriv.html
@@ -0,0 +1,59 @@
+<html>
+<head><title>smfi_getpriv</title></head>
+<body>
+<h1>smfi_getpriv</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+void* smfi_getpriv(
+ SMFICTX *ctx
+);
+</pre>
+Get the connection-specific data pointer for this connection.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_getpriv may be called in any of the xxfi_* callbacks.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>None.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_getpriv returns the private data pointer stored by a prior call to <a href="smfi_setpriv.html">smfi_setpriv</a>, or NULL if none has been set.</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_getsymval.html b/contrib/sendmail/libmilter/docs/smfi_getsymval.html
new file mode 100644
index 0000000..d8a3304
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_getsymval.html
@@ -0,0 +1,92 @@
+<html>
+<head><title>smfi_getsymval</title></head>
+<body>
+<h1>smfi_getsymval</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+char* smfi_getsymval(
+ SMFICTX *ctx,
+ char *symname
+);
+</pre>
+Get the value of a sendmail macro.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_getsymval may be called from within any of the xxfi_* callbacks. Which macros are defined will depend on when it is called.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>None.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>The opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>symname</td>
+ <td>The name of a sendmail macro, optinally enclosed in braces ("{" and "}"). <a href="#notes">See below</a> for default macros.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_getsymval returns the value of the given macro as a null-terminated string, or NULL if the macro is not defined.</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th><a name="notes">NOTES</A></th>
+<td>
+By default, the following macros are valid in the given contexts:
+
+<table border="1" cellspacing=0>
+<tr bgcolor="#dddddd"><th>Sent With</th><th>Macros</th></tr>
+<tr><td>xxfi_connect</td> <td>daemon_name, if_name, if_addr, j, _</td></tr>
+<tr><td>xxfi_helo</td> <td>tls_version, cipher, cipher_bits, cert_subject, cert_issuer</td></tr>
+<tr><td>xxfi_envfrom</td> <td>i, auth_type, auth_authen, auth_ssf, auth_author,
+ mail_mailer, mail_host, mail_addr</td></tr>
+<tr><td>xxfi_envrcpt</td> <td>rcpt_mailer, rcpt_host, rcpt_addr</td></tr>
+</table>
+<p>
+All macros stay in effect from the point they are received until the
+end of the connection for the first two sets, the end of the message
+for the third (xxfi_envfrom), and just for each recipient for the
+final set (xxfi_envrcpt).
+<p>
+The macro list can be changed using the confMILTER_MACROS_* options in
+sendmail.mc. The scopes of such macros will be determined by when
+they are set by sendmail. For descriptions of macros' values, please
+see the "Sendmail Installation and Operation Guide" provided with your
+sendmail distribution.
+
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_main.html b/contrib/sendmail/libmilter/docs/smfi_main.html
new file mode 100644
index 0000000..9652eaa
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_main.html
@@ -0,0 +1,48 @@
+<html>
+<head><title>smfi_main</title></head>
+<body>
+<h1>smfi_main</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_main(
+);
+</pre>
+Hand control to libmilter event loop.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_main is called after a filter's initialization is complete.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>smfi_main hands control to the Milter event loop.</td>
+</tr>
+</table>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_main will return MI_FAILURE if it fails to establish a connection. This may occur for any of a variety of reasons (e.g. invalid address passed to <a href="smfi_setconn.html">smfi_setconn</a>). The reason for the failure will be logged. Otherwise, smfi_main will return MI_SUCCESS.</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_register.html b/contrib/sendmail/libmilter/docs/smfi_register.html
new file mode 100644
index 0000000..705b3a4
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_register.html
@@ -0,0 +1,160 @@
+<html>
+<head><title>smfi_register</title></head>
+<body>
+<h1>smfi_register</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_register(
+ smfiDesc_str descr
+);
+</pre>
+Register a set of filter callbacks.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=1>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_register must be called before smfi_main</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>smfi_register creates a filter using the information given in the
+smfiDesc_str argument. Multiple calls to smfi_register within a
+single process are not allowed.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>descr</td>
+ <td>
+A filter descriptor of type smfiDesc_str describing the filter's
+functions. The structure has the following members:
+<pre>
+struct smfiDesc
+{
+ char *xxfi_name; /* filter name */
+ int xxfi_version; /* version code -- do not change */
+ unsigned long xxfi_flags; /* <a href="#flags">flags</a> */
+
+ /* connection info filter */
+ sfsistat (*<a href="xxfi_connect.html">xxfi_connect</a>)(SMFICTX *, char *, _SOCK_ADDR *);
+ /* SMTP HELO command filter */
+ sfsistat (*<a href="xxfi_helo.html">xxfi_helo</a>)(SMFICTX *, char *);
+ /* envelope sender filter */
+ sfsistat (*<a href="xxfi_envfrom.html">xxfi_envfrom</a>)(SMFICTX *, char **);
+ /* envelope recipient filter */
+ sfsistat (*<a href="xxfi_envrcpt.html">xxfi_envrcpt</a>)(SMFICTX *, char **);
+ /* header filter */
+ sfsistat (*<a href="xxfi_header.html">xxfi_header</a>)(SMFICTX *, char *, char *);
+ /* end of header */
+ sfsistat (*<a href="xxfi_eoh.html">xxfi_eoh</a>)(SMFICTX *);
+ /* body block */
+ sfsistat (*<a href="xxfi_body.html">xxfi_body</a>)(SMFICTX *, unsigned char *, size_t);
+ /* end of message */
+ sfsistat (*<a href="xxfi_eom.html">xxfi_eom</a>)(SMFICTX *);
+ /* message aborted */
+ sfsistat (*<a href="xxfi_abort.html">xxfi_abort</a>)(SMFICTX *);
+ /* connection cleanup */
+ sfsistat (*<a href="xxfi_close.html">xxfi_close</a>)(SMFICTX *);
+};
+</pre>
+
+A NULL value for any callback function indicates that the filter does
+not wish to process the given type of information, simply returning
+SMFIS_CONTINUE.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>
+smfi_register may return MI_FAILURE for any of the following reasons:
+<ul>
+<li>memory allocation failed.
+<li>incompatible version or illegal flags value.
+</ul>
+
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+
+<a name="flags"></A>
+The xxfi_flags field should contain the bitwise OR of zero or more of
+the following values, describing the actions the filter may take:
+<TABLE BORDER CELLPADDING="1" cellspacing=1>
+<tr valign="top" bgcolor="#dddddd"><th align="left">Flag</th><th align="center">Description</th></tr>
+ <TR align="left" valign=top>
+ <TD>
+ SMFIF_ADDHDRS
+ </TD>
+ <TD>
+ This filter may add headers.
+ </TD>
+ </TR>
+ <TR align="left" valign=top>
+ <TD>
+ SMFIF_CHGHDRS
+ </TD>
+ <TD>
+ This filter may change and/or delete headers.
+ </TD>
+ </TR>
+ <TR align="left" valign=top>
+ <TD VALIGN="TOP">
+ SMFIF_CHGBODY
+ </TD>
+ <TD>
+ This filter may replace the body during filtering.
+ This may have significant performance impact
+ if other filters do body filtering after this filter.
+ </TD>
+ </TR>
+ <TR>
+ <TD VALIGN="TOP">
+ SMFIF_ADDRCPT
+ </TD>
+ <TD>
+ This filter may add recipients to the message.
+ </TD>
+ </TR>
+ <TR>
+ <TD VALIGN="TOP">
+ SMFIF_DELRCPT
+ </TD>
+ <TD>
+ This filter may remove recipients from the message.
+ </TD>
+ </TR>
+</TABLE>
+
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_replacebody.html b/contrib/sendmail/libmilter/docs/smfi_replacebody.html
new file mode 100644
index 0000000..204c2dc
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_replacebody.html
@@ -0,0 +1,90 @@
+<html>
+<head><title>smfi_replacebody</title></head>
+<body>
+<h1>smfi_replacebody</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_replacebody(
+ SMFICTX *ctx,
+ unsigned char *bodyp,
+ int bodylen
+);
+</pre>
+Replace message-body data.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>Called only from <a href="xxfi_eom.html">xxfi_eom</a>. smfi_replacebody may be called more than once.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>smfi_replacebody replaces the body of the current message. If called
+more than once, subsequent calls result in data being appended to the new
+body.
+</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>bodyp</td>
+ <td>A pointer to the start of the new body data, which does not have to be null-terminated. If bodyp is NULL, it is treated as having length == 0. Body data should be in CR/LF form.
+ </td></tr>
+ <tr valign="top"><td>bodylen</td>
+ <td>The number of data bytes pointed to by bodyp.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_replacebody fails and returns MI_FAILURE if:
+<ul>
+ <li>bodyp == NULL and bodylen &gt; 0.
+ <li>Changing the body in the current connection state is invalid.
+ <li>A network error occurs.
+ <li>SMFIF_CHGBODY was not set when <a href="smfi_register.html">smfi_register</a> was called.
+</ul>
+Otherwise, it will return MI_SUCCESS.
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+<ul>
+ <li>Since the message body may be very large, setting SMFIF_CHGBODY may significantly affect filter performance.
+ <li>If a filter sets SMFIF_CHGBODY but does not call smfi_replacebody, the original body remains unchanged.
+ <li>For smfi_replacebody, filter order is important. <b>Later filters will see the new body contents created by earlier ones.</b>
+</ul>
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_setconn.html b/contrib/sendmail/libmilter/docs/smfi_setconn.html
new file mode 100644
index 0000000..0d46a5b
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_setconn.html
@@ -0,0 +1,77 @@
+<html>
+<head><title>smfi_setconn</title></head>
+<body>
+<h1>smfi_setconn</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_setconn(
+ char *oconn;
+);
+</pre>
+Set the socket through which this filter should communicate with sendmail.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_setconn must be called once before <a href="smfi_main.html">smfi_main</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Sets the socket through which the filter communicates with sendmail.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>oconn</td>
+ <td>The address of the desired communication socket.
+ The address should be a NULL-terminated string in "proto:address"
+ format:
+ <ul>
+ <li><code>{unix|local}:/path/to/file</code> -- A named pipe.
+ <li><code>inet:port@{hostname|ip-address}</code> -- An IPV4 socket.
+ <li><code>inet6:port@{hostname|ip-address}</code> -- An IPV6 socket.
+ </ul>
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_setconn will not fail on an invalid address. The failure will
+only be detected in <a href="smfi_main.html">smfi_main</a></td>
+</tr>
+
+<tr>
+<th valign="top" align=left>NOTES</th>
+
+<td>
+<ul><li>If possible, filters should not run as root when communicating over unix/local domain sockets.
+ <li>Unix/local sockets should have their permissions set to 0600 (read/write permission only for the socket's owner).
+</ul>
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_setpriv.html b/contrib/sendmail/libmilter/docs/smfi_setpriv.html
new file mode 100644
index 0000000..e800cc8
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_setpriv.html
@@ -0,0 +1,77 @@
+<html>
+<head><title>smfi_setpriv</title></head>
+<body>
+<h1>smfi_setpriv</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_setpriv(
+ SMFICTX *ctx,
+ void *privatedata
+);
+</pre>
+Set the private data pointer for this connection.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_setpriv may be called in any of the xxfi_* callbacks.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Sets the private data pointer for the context ctx.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>privatedata</td>
+ <td>Pointer to private data. This value will be returned by subsequent calls to <a href="smfi_getpriv.html">smfi_getpriv</a> using ctx.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_setpriv returns MI_FAILURE if ctx is an invalid context.
+Otherwise, it returns MI_SUCCESS.</td>
+</tr>
+
+<tr>
+<th valign="top" align=left>NOTES</th>
+
+<td>There is only one private data pointer per connection; multiple
+calls to smfi_setpriv with different values will cause previous values
+to be lost.
+<P>
+Before a filter terminates it should release the private data
+and set the pointer to NULL.
+</td>
+
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_setreply.html b/contrib/sendmail/libmilter/docs/smfi_setreply.html
new file mode 100644
index 0000000..962f167
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_setreply.html
@@ -0,0 +1,92 @@
+<html>
+<head><title>smfi_setreply</title></head>
+<body>
+<h1>smfi_setreply</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_setreply(
+ SMFICTX *ctx,
+ char *rcode,
+ char *xcode,
+ char *message
+);
+</pre>
+Set the default SMTP error reply code.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_setreply may be called from any of the xxfi_ callbacks.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Directly set the SMTP error reply code for this connection. This code
+will be used on subsequent error replies resulting from actions taken by
+this filter.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>rcode</td>
+ <td>The three-digit (RFC 821) SMTP reply code, as a null-terminated string. rcode cannot be NULL, and must be a valid reply code.
+ </td></tr>
+ <tr valign="top"><td>xcode</td>
+ <td>The extended (RFC 2034) reply code. If xcode is NULL, no extended code is used. Otherwise, xcode must conform to RFC 2034.
+ </td></tr>
+ <tr valign="top"><td>message</td>
+ <td>The text part of the SMTP reply. If message is NULL, an empty message is used.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_setreply will fail and return MI_FAILURE if:
+<ul>
+ <li>The rcode or xcode argument is invalid.
+ <li>A memory-allocation failure occurs.
+</ul>
+Otherwise, it return MI_SUCCESS.
+</td>
+</tr>
+
+<!----------- Notes ---------->
+<tr align="left" valign=top>
+<th>NOTES</th>
+<td>
+<ul>
+<li>Values passed to smfi_setreply are not checked for standards compliance.
+<li>For details about reply codes and their meanings, please see RFC's
+<a href="http://www.cis.ohio-state.edu/htbin/rfc/rfc821.html">821</a>
+and <a href="http://www.cis.ohio-state.edu/htbin/rfc/rfc2034.html">2034</a>.
+</ul>
+</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/smfi_settimeout.html b/contrib/sendmail/libmilter/docs/smfi_settimeout.html
new file mode 100644
index 0000000..a9e870a
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/smfi_settimeout.html
@@ -0,0 +1,60 @@
+<html>
+<head><title>smfi_settimeout</title></head>
+<body>
+<h1>smfi_settimeout</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+int smfi_settimeout(
+ int otimeout
+);
+</pre>
+Set the filter's connection timeout value.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>smfi_settimeout should only be called before <a href="smfi_main.html">smfi_main</a>.</td>
+</tr>
+<tr align="left" valign=top>
+<th width="80">Effects</th>
+<td>Sets the number of seconds libmilter will wait for an MTA connection before timing out a socket. If smfi_settimeout is not called, a default timeout of 1800 seconds is used.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>otimeout</td>
+ <td>The number of seconds to wait before timing out (&gt; 0). Zero means
+no wait, <b>not</b> "wait forever".
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>RETURN VALUES</th>
+
+<td>smfi_settimeout always returns MI_SUCCESS.</td>
+</tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_abort.html b/contrib/sendmail/libmilter/docs/xxfi_abort.html
new file mode 100644
index 0000000..aeddf6f
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_abort.html
@@ -0,0 +1,80 @@
+<html>
+<head><title>xxfi_abort</title></head>
+<body>
+<h1>xxfi_abort</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_abort)(
+ SMFICTX * ctx
+);
+</pre>
+Handle the current message's being aborted.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_abort may be called at any time during message processing (i.e. between some message-oriented routine and <a href="xxfi_eom.html">xxfi_eom</a>).</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>
+<ul>
+<li>xxfi_abort must reclaim any resources allocated on a per-message
+basis, and must be tolerant of being called between any two
+message-oriented callbacks.
+
+<li>Calls to xxfi_abort and <a href="xxfi_eom.html">xxfi_eom</a> are
+mutually exclusive.
+
+<li>xxfi_abort is not responsible for reclaiming connection-specific
+data, since <a href="xxfi_close.html">xxfi_close</a> is always called
+when a connection is closed.
+
+<li>Since the current message is already being aborted, the return
+value is currently ignored.
+
+<li>xxfi_abort is only called if the message is aborted outside the
+filter's control <b>and</b> the filter has not completed its
+message-oriented processing. For example, if a filter has already
+returned SMFIS_ACCEPT, SMFIS_REJECT, or SMFIS_DISCARD from a
+message-oriented routine, xxfi_abort will not be called even if the
+message is later aborted outside its control.
+</ul>
+</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_body.html b/contrib/sendmail/libmilter/docs/xxfi_body.html
new file mode 100644
index 0000000..b19e0d4
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_body.html
@@ -0,0 +1,80 @@
+<html>
+<head><title>xxfi_body</title></head>
+<body>
+<h1>xxfi_body</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_body)(
+ SMFICTX * ctx,
+ unsigned char * bodyp,
+ size_t len
+);
+</pre>
+Handle a piece of a message's body.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_body is called zero or more times between xxfi_eoh and xxfi_eom.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>bodyp</td>
+ <td>Pointer to the start of this block of body data. bodyp is not valid outside this call to xxfi_body.
+ </td></tr>
+ <tr valign="top"><td>len</td>
+ <td>The amount of data pointed to by bodyp.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>
+<ul>
+<li>bodyp points to a sequence of bytes.
+It is <em>not</em> a C string (a sequence of characters that is terminated by '\0').
+Therefore, do not use the usual C string functions like strlen() on this byte block.
+Moreover, the byte sequence may contain '\0' characters inside the block.
+Hence even if a trailing '\0' is added, C string functions may still fail
+to work as expected.
+<li>Since message bodies can be very large, defining xxfi_body can
+significantly impact filter performance.
+<li>End-of-lines are represented as received from SMTP (normally CR/LF).
+<li>Later filters will see body changes made by earlier ones.
+<li>Message bodies may be sent in multiple chunks, with one call to
+ xxfi_body per chunk.
+</ul>
+</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_close.html b/contrib/sendmail/libmilter/docs/xxfi_close.html
new file mode 100644
index 0000000..07742be
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_close.html
@@ -0,0 +1,66 @@
+<html>
+<head><title>xxfi_close</title></head>
+<body>
+<h1>xxfi_close</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_close)(
+ SMFICTX * ctx
+);
+</pre>
+The current connection is being closed.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_close is always called once at the end of each connection.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>
+<ul>
+<li>xxfi_close is called on close even if the previous mail
+transaction was aborted.
+<li>xxfi_close is responsible for freeing any resources allocated on a
+per-connection basis.
+<li>Since the connection is already closing, the return value is
+currently ignored.
+</ul>
+</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_connect.html b/contrib/sendmail/libmilter/docs/xxfi_connect.html
new file mode 100644
index 0000000..1710285
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_connect.html
@@ -0,0 +1,90 @@
+<html>
+<head><title>xxfi_connect</title></head>
+<body>
+<h1>xxfi_connect</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_connect)(
+ SMFICTX *ctx,
+ char *hostname,
+ _SOCK_ADDR *hostaddr);
+</pre>
+</td></tr>
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr>
+<th valign="top" align=left width=80>Called When</th>
+<td>Once, at the start of each SMTP connection.</td>
+</tr>
+<tr>
+<th valign="top" align=left width=80>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+<!--
+This callback function is invoked on each connection to the mail
+filter program. The callback is to be implemented by the Milter
+application developers. The name of the callback can be any valid
+function name. The function pointer is to be assigned to the
+smfiDesc.xxfi_connect and the pointer to the smfiDesc structure
+is passed to smfi_register().
+</td></tr>
+-->
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr><td>ctx</td>
+ <td>the opaque context structure.
+ </td></tr>
+ <tr><td>hostname</td>
+ <td>the host name of the message sender, as determined by a
+ reverse lookup on the host address. If the reverse lookup
+ fails, hostname will contain the message sender's IP
+ address enclosed in square brackets (e.g. `[a.b.c.d]').
+ </td></tr>
+ <tr><td>hostaddr</td>
+ <td>the host address, as determined by a getpeername() call on the SMTP socket.
+ NULL if the type is not supported in the current version or if
+ the SMTP connection is made via stdin.
+ </td></tr>
+ </table>
+</td></tr>
+<!----------- Return values ---------->
+<!--
+<tr>
+<th valign="top" align=left>SPECIAL RETURN VALUES</th>
+<td><table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Return value</th><th>Description</th></tr>
+ <tr valign="top">
+ <td>SMFIS_DISCARD</td>
+ <td>Not meaningful, as
+ this is only meaningful from message-oriented routines.
+ </td>
+ </tr>
+</table>
+</tr>
+-->
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>If an earlier filter rejects the connection in its xxfi_connect()
+routine, this filter's xxfi_connect() will not be called.</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_envfrom.html b/contrib/sendmail/libmilter/docs/xxfi_envfrom.html
new file mode 100644
index 0000000..d023c40
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_envfrom.html
@@ -0,0 +1,92 @@
+<html>
+<head><title>xxfi_envfrom</title></head>
+<body>
+<h1>xxfi_envfrom</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_envfrom)(
+ SMFICTX * ctx,
+ char ** argv
+);
+</pre>
+Handle the envelope FROM command.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_envfrom is called once at the beginning of each message, before xxfi_envrcpt.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>argv</td>
+ <td>Null-terminated SMTP command arguments;
+ argv[0] is guaranteed to be the sender address.
+ Later arguments are the ESMTP arguments.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>SPECIAL RETURN VALUES</th>
+<td><table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Return value</th><th>Description</th></tr>
+ <tr valign="top">
+ <td>SMFIS_TEMPFAIL</td>
+ <td>Reject this sender and message with a temporary error; a new sender (and hence a new message) may subsequently be specified. <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_REJECT</td>
+ <td>Reject this sender and message; a new sender/message may be specified. <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_DISCARD</td>
+ <td>Accept and silently discard this message. <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_ACCEPT</td>
+ <td>Accept this message. <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+</table>
+</tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>For more details on ESTMP responses, please see RFC
+<a href="http://www.cis.ohio-state.edu/rfc/rfc1869.txt">1869</a>.</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html b/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html
new file mode 100644
index 0000000..f13626a
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html
@@ -0,0 +1,94 @@
+<html>
+<head><title>xxfi_envrcpt</title></head>
+<body>
+<h1>xxfi_envrcpt</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_envrcpt)(
+ SMFICTX * ctx,
+ char ** argv
+);
+</pre>
+Handle the envelope RCPT command.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_envrcpt is called once per recipient, hence one or more times per message, immediately after xxfi_envfrom.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>argv</td>
+ <td>Null-terminated SMTP command arguments;
+ argv[0] is guaranteed to be the recipient address.
+ Later arguments are the ESMTP arguments.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Return values ---------->
+<tr>
+<th valign="top" align=left>SPECIAL RETURN VALUES</th>
+<td><table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Return value</th><th>Description</th></tr>
+ <tr valign="top">
+ <td>SMFIS_TEMPFAIL</td>
+ <td>Temporarily fail for this particular recipient; further recipients
+ maystill be sent. <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_REJECT</td>
+ <td>Reject this particular recipient; further recipients maystill be sent.
+ <a href="xxfi_abort.html">xxfi_abort</a> is not called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_DISCARD</td>
+ <td>Accept and discard the message. <a href="xxfi_abort.html">xxfi_abort</a> will be called.
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>SMFIS_ACCEPT</td>
+ <td>Accept recipient. <a href="xxfi_abort.html">xxfi_abort</a> will not be called.
+ </td>
+ </tr>
+</table>
+</tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>For more details on ESTMP responses, please see RFC
+<a href="http://www.cis.ohio-state.edu/rfc/rfc1869.txt">1869</a>.</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_eoh.html b/contrib/sendmail/libmilter/docs/xxfi_eoh.html
new file mode 100644
index 0000000..46c7925
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_eoh.html
@@ -0,0 +1,53 @@
+<html>
+<head><title>xxfi_eoh</title></head>
+<body>
+<h1>xxfi_eoh</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_eoh)(
+ SMFICTX * ctx
+);
+</pre>
+Handle the end of message headers.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_eoh is called once after all headers have been sent and processed.
+</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ </table>
+</td></tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_eom.html b/contrib/sendmail/libmilter/docs/xxfi_eom.html
new file mode 100644
index 0000000..40f6dee
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_eom.html
@@ -0,0 +1,58 @@
+<html>
+<head><title>xxfi_eom</title></head>
+<body>
+<h1>xxfi_eom</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_eom)(
+ SMFICTX * ctx
+);
+</pre>
+End of a message.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_eom is called once after all calls to <a href="xxfi_body.html">xxfi_body</a> for a given message.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>A filter is required to make all its modifications to the message headers, body, and envelope in xxfi_eom. Modifications are made via the smfi_* routines.
+</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_header.html b/contrib/sendmail/libmilter/docs/xxfi_header.html
new file mode 100644
index 0000000..a6c6322
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_header.html
@@ -0,0 +1,74 @@
+<html>
+<head><title>xxfi_header</title></head>
+<body>
+<h1>xxfi_header</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_header)(
+ SMFICTX * ctx,
+ char * headerf,
+ char * headerv
+);
+</pre>
+Handle a message header.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th>
+<td>xxfi_header is called zero or more times between xxfi_envrcpt and xxfi_eoh, once per message header.</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>headerf</td>
+ <td> Header field name.
+ </td></tr>
+ <tr valign="top"><td>headerv</td>
+ <td>Header field value. The
+ content of the header may include folded white space (i.e. multiple
+ lines with following white space). The trailing line terminator (CR/LF)
+ is removed.
+ </td></tr>
+ </table>
+</td></tr>
+
+<!----------- Notes ---------->
+<tr>
+<th valign="top" align=left>NOTES</th>
+<td>
+<ul>
+<li>Later filters will see header changes/additions made by earlier ones.
+<li>For much more detail about header format, please see
+RFC <a href="http://www.cis.ohio-state.edu/htbin/rfc/rfc822.html">822</a>
+</ul>
+</td>
+</tr>
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/docs/xxfi_helo.html b/contrib/sendmail/libmilter/docs/xxfi_helo.html
new file mode 100644
index 0000000..b1aa9e9
--- /dev/null
+++ b/contrib/sendmail/libmilter/docs/xxfi_helo.html
@@ -0,0 +1,59 @@
+<html>
+<head><title>xxfi_helo</title></head>
+<body>
+<h1>xxfi_helo</h1>
+
+<table border="0" cellspacing=4 cellpadding=4>
+<!---------- Synopsis ----------->
+<tr><th valign="top" align=left width=150>SYNOPSIS</th><td>
+<pre>
+#include &lt;libmilter/mfapi.h&gt;
+sfsistat (*xxfi_helo)(
+ SMFICTX * ctx,
+ char * helohost
+);
+</pre>
+Handle the HELO/EHLO command.
+</td></tr>
+
+<!----------- Description ---------->
+<tr><th valign="top" align=left>DESCRIPTION</th><td>
+<table border="1" cellspacing=1 cellpadding=4>
+<tr align="left" valign=top>
+<th width="80">Called When</th> <td>xxfi_helo is called whenever the client
+sends a HELO/EHLO command. It may therefore be called between zero and
+three times</td>
+</tr>
+<tr align="left" valign=top>
+<th>Default Behavior</th>
+<td>Do nothing; return SMFIS_CONTINUE.</td>
+</tr>
+</table>
+
+<!----------- Arguments ---------->
+<tr><th valign="top" align=left>ARGUMENTS</th><td>
+ <table border="1" cellspacing=0>
+ <tr bgcolor="#dddddd"><th>Argument</th><th>Description</th></tr>
+ <tr valign="top"><td>ctx</td>
+ <td>Opaque context structure.
+ </td></tr>
+ <tr valign="top"><td>helohost</td>
+ <td>Value passed to HELO/EHLO command, which should be
+ the domain name of the sending host (but is, in practice,
+ anything the sending host wants to send).
+ </td></tr>
+ </table>
+</td></tr>
+
+</table>
+
+<hr size="1">
+<font size="-1">
+Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+All rights reserved.
+<br>
+By using this file, you agree to the terms and conditions set
+forth in the <a href="LICENSE.txt">LICENSE</a>.
+</font>
+</body>
+</html>
diff --git a/contrib/sendmail/libmilter/engine.c b/contrib/sendmail/libmilter/engine.c
index 0fd48eb..aabfe6c 100644
--- a/contrib/sendmail/libmilter/engine.c
+++ b/contrib/sendmail/libmilter/engine.c
@@ -8,13 +8,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: engine.c,v 8.67.4.17 2001/01/22 19:00:16 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: engine.c,v 8.102 2001/12/13 17:10:00 ca Exp $")
-#if _FFR_MILTER
#include "libmilter.h"
-#include "sendmail/useful.h"
#if NETINET || NETINET6
# include <arpa/inet.h>
@@ -118,13 +115,16 @@ static int dec_arg2 __P((char *, size_t, char **, char **));
** is set in the NX_* value
** this function is coded in trans_ok(), see below.
*/
+
#define MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */
#define NX_INIT (MASK(ST_OPTS))
#define NX_OPTS (MASK(ST_CONN))
#define NX_CONN (MASK(ST_HELO) | MASK(ST_MAIL))
#define NX_HELO (MASK(ST_HELO) | MASK(ST_MAIL))
#define NX_MAIL (MASK(ST_RCPT) | MASK(ST_ABRT))
-#define NX_RCPT (MASK(ST_HDRS) | MASK(ST_EOHS) | MASK(ST_RCPT) | MASK(ST_ABRT))
+#define NX_RCPT (MASK(ST_HDRS) | MASK(ST_EOHS) | \
+ MASK(ST_BODY) | MASK(ST_ENDM) | \
+ MASK(ST_RCPT) | MASK(ST_ABRT))
#define NX_HDRS (MASK(ST_EOHS) | MASK(ST_HDRS) | MASK(ST_ABRT))
#define NX_EOHS (MASK(ST_BODY) | MASK(ST_ENDM) | MASK(ST_ABRT))
#define NX_BODY (MASK(ST_ENDM) | MASK(ST_BODY) | MASK(ST_ABRT))
@@ -172,8 +172,9 @@ static cmdfct cmds[] =
#define _SMFIS_OPTIONS 22
#define _SMFIS_NOREPLY 23
#define _SMFIS_FAIL (-1)
+#define _SMFIS_NONE (-2)
- /*
+/*
** MI_ENGINE -- receive commands and process them
**
** Parameters:
@@ -208,6 +209,7 @@ mi_engine(ctx)
fi_abort = ctx->ctx_smfi->xxfi_abort;
mi_clr_macros(ctx, 0);
fix_stm(ctx);
+ r = _SMFIS_NONE;
do
{
/* call abort only if in a mail transaction */
@@ -217,17 +219,29 @@ mi_engine(ctx)
if (mi_stop() == MILTER_ABRT)
{
if (ctx->ctx_dbg > 3)
- dprintf("[%d] milter_abort\n",
+ sm_dprintf("[%d] milter_abort\n",
(int) ctx->ctx_id);
ret = MI_FAILURE;
break;
}
+
+ /*
+ ** Notice: buf is allocated by mi_rd_cmd() and it will
+ ** usually be free()d after it has been used in f().
+ ** However, if the function returns _SMFIS_KEEP then buf
+ ** contains macros and will not be free()d.
+ ** Hence r must be set to _SMFIS_NONE if a new buf is
+ ** allocated to avoid problem with housekeeping, esp.
+ ** if the code "break"s out of the loop.
+ */
+
+ r = _SMFIS_NONE;
if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len,
ctx->ctx_smfi->xxfi_name)) == NULL &&
cmd < SMFIC_VALIDCMD)
{
if (ctx->ctx_dbg > 5)
- dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
+ sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
(int) ctx->ctx_id, (int) cmd);
/*
@@ -240,7 +254,7 @@ mi_engine(ctx)
break;
}
if (ctx->ctx_dbg > 4)
- dprintf("[%d] got cmd '%c' len %d\n",
+ sm_dprintf("[%d] got cmd '%c' len %d\n",
(int) ctx->ctx_id, cmd, len);
for (i = 0; i < ncmds; i++)
{
@@ -251,7 +265,7 @@ mi_engine(ctx)
{
/* unknown command */
if (ctx->ctx_dbg > 1)
- dprintf("[%d] cmd '%c' unknown\n",
+ sm_dprintf("[%d] cmd '%c' unknown\n",
(int) ctx->ctx_id, cmd);
ret = MI_FAILURE;
break;
@@ -260,7 +274,7 @@ mi_engine(ctx)
{
/* stop for now */
if (ctx->ctx_dbg > 1)
- dprintf("[%d] cmd '%c' not impl\n",
+ sm_dprintf("[%d] cmd '%c' not impl\n",
(int) ctx->ctx_id, cmd);
ret = MI_FAILURE;
break;
@@ -269,14 +283,14 @@ mi_engine(ctx)
/* is new state ok? */
newstate = cmds[i].cm_next;
if (ctx->ctx_dbg > 5)
- dprintf("[%d] cur %x new %x nextmask %x\n",
+ sm_dprintf("[%d] cur %x new %x nextmask %x\n",
(int) ctx->ctx_id,
curstate, newstate, next_states[curstate]);
if (newstate != ST_NONE && !trans_ok(curstate, newstate))
{
if (ctx->ctx_dbg > 1)
- dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
+ sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
(int) ctx->ctx_id,
curstate, MASK(curstate),
newstate, MASK(newstate),
@@ -293,7 +307,11 @@ mi_engine(ctx)
curstate = ST_HELO;
if (!trans_ok(curstate, newstate))
+ {
+ free(buf);
+ buf = NULL;
continue;
+ }
}
arg.a_len = len;
arg.a_buf = buf;
@@ -337,7 +355,7 @@ mi_engine(ctx)
else if (r == _SMFIS_ABORT)
{
if (ctx->ctx_dbg > 5)
- dprintf("[%d] function returned abort\n",
+ sm_dprintf("[%d] function returned abort\n",
(int) ctx->ctx_id);
ret = MI_FAILURE;
break;
@@ -354,12 +372,12 @@ mi_engine(ctx)
/* close must always be called */
if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
(void) (*fi_close)(ctx);
- if (buf != NULL)
+ if (r != _SMFIS_KEEP && buf != NULL)
free(buf);
mi_clr_macros(ctx, 0);
return ret;
}
- /*
+/*
** SENDREPLY -- send a reply to the MTA
**
** Parameters:
@@ -462,7 +480,7 @@ mi_clr_macros(ctx, m)
}
}
}
- /*
+/*
** ST_OPTIONNEG -- negotiate options
**
** Parameters:
@@ -543,7 +561,7 @@ st_optionneg(g)
return _SMFIS_OPTIONS;
}
- /*
+/*
** ST_CONNECTINFO -- receive connection information
**
** Parameters:
@@ -560,7 +578,7 @@ st_connectinfo(g)
size_t l;
size_t i;
char *s, family;
- u_short port = 0;
+ unsigned short port = 0;
_SOCK_ADDR sockaddr;
sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
@@ -617,11 +635,11 @@ st_connectinfo(g)
# if NETINET6
if (family == SMFIA_INET6)
{
- if (inet_pton(AF_INET6, s + i,
- &sockaddr.sin6.sin6_addr) != 1)
+ if (mi_inet_pton(AF_INET6, s + i,
+ &sockaddr.sin6.sin6_addr) != 1)
{
smi_log(SMI_LOG_ERR,
- "%s: connect[%d]: inet_pton failed",
+ "%s: connect[%d]: mi_inet_pton failed",
g->a_ctx->ctx_smfi->xxfi_name,
(int) g->a_ctx->ctx_id);
return _SMFIS_ABORT;
@@ -635,7 +653,7 @@ st_connectinfo(g)
# if NETUNIX
if (family == SMFIA_UNIX)
{
- if (strlcpy(sockaddr.sunix.sun_path, s + i,
+ if (sm_strlcpy(sockaddr.sunix.sun_path, s + i,
sizeof sockaddr.sunix.sun_path) >=
sizeof sockaddr.sunix.sun_path)
{
@@ -660,7 +678,7 @@ st_connectinfo(g)
return (*fi_connect)(g->a_ctx, g->a_buf,
family != SMFIA_UNKNOWN ? &sockaddr : NULL);
}
- /*
+/*
** ST_EOH -- end of headers
**
** Parameters:
@@ -683,7 +701,7 @@ st_eoh(g)
return (*fi_eoh)(g->a_ctx);
return SMFIS_CONTINUE;
}
- /*
+/*
** ST_HELO -- helo/ehlo command
**
** Parameters:
@@ -706,7 +724,7 @@ st_helo(g)
return (*fi_helo)(g->a_ctx, g->a_buf);
return SMFIS_CONTINUE;
}
- /*
+/*
** ST_HEADER -- header line
**
** Parameters:
@@ -734,24 +752,24 @@ st_header(g)
return _SMFIS_ABORT;
}
-#define ARGV_FCT(lf, rf, idx) \
- char **argv; \
- sfsistat (*lf) __P((SMFICTX *, char **)); \
- int r; \
- \
- if (g == NULL) \
- return _SMFIS_ABORT; \
- mi_clr_macros(g->a_ctx, g->a_idx + 1); \
- if (g->a_ctx->ctx_smfi == NULL || \
- (lf = g->a_ctx->ctx_smfi->rf) == NULL) \
- return SMFIS_CONTINUE; \
+#define ARGV_FCT(lf, rf, idx) \
+ char **argv; \
+ sfsistat (*lf) __P((SMFICTX *, char **)); \
+ int r; \
+ \
+ if (g == NULL) \
+ return _SMFIS_ABORT; \
+ mi_clr_macros(g->a_ctx, g->a_idx + 1); \
+ if (g->a_ctx->ctx_smfi == NULL || \
+ (lf = g->a_ctx->ctx_smfi->rf) == NULL) \
+ return SMFIS_CONTINUE; \
if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \
- return _SMFIS_ABORT; \
- r = (*lf)(g->a_ctx, argv); \
- free(argv); \
+ return _SMFIS_ABORT; \
+ r = (*lf)(g->a_ctx, argv); \
+ free(argv); \
return r;
- /*
+/*
** ST_SENDER -- MAIL FROM command
**
** Parameters:
@@ -767,7 +785,7 @@ st_sender(g)
{
ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
}
- /*
+/*
** ST_RCPT -- RCPT TO command
**
** Parameters:
@@ -783,7 +801,7 @@ st_rcpt(g)
{
ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
}
- /*
+/*
** ST_MACROS -- deal with macros received from the MTA
**
** Parameters:
@@ -833,7 +851,7 @@ st_macros(g)
g->a_ctx->ctx_mac_buf[i] = g->a_buf;
return _SMFIS_KEEP;
}
- /*
+/*
** ST_QUIT -- quit command
**
** Parameters:
@@ -849,7 +867,7 @@ st_quit(g)
{
return _SMFIS_NOREPLY;
}
- /*
+/*
** ST_BODYCHUNK -- deal with a piece of the mail body
**
** Parameters:
@@ -863,16 +881,17 @@ static int
st_bodychunk(g)
genarg *g;
{
- sfsistat (*fi_body) __P((SMFICTX *, u_char *, size_t));
+ sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
if (g == NULL)
return _SMFIS_ABORT;
if (g->a_ctx->ctx_smfi != NULL &&
(fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL)
- return (*fi_body)(g->a_ctx, (u_char *)g->a_buf, g->a_len);
+ return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
+ g->a_len);
return SMFIS_CONTINUE;
}
- /*
+/*
** ST_BODYEND -- deal with the last piece of the mail body
**
** Parameters:
@@ -890,7 +909,7 @@ st_bodyend(g)
genarg *g;
{
sfsistat r;
- sfsistat (*fi_body) __P((SMFICTX *, u_char *, size_t));
+ sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
sfsistat (*fi_eom) __P((SMFICTX *));
if (g == NULL)
@@ -907,7 +926,8 @@ st_bodyend(g)
timeout.tv_sec = g->a_ctx->ctx_timeout;
timeout.tv_usec = 0;
sd = g->a_ctx->ctx_sd;
- r = (*fi_body)(g->a_ctx, (u_char *)g->a_buf, g->a_len);
+ r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
+ g->a_len);
if (r != SMFIS_CONTINUE &&
sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
return _SMFIS_ABORT;
@@ -918,7 +938,7 @@ st_bodyend(g)
return (*fi_eom)(g->a_ctx);
return r;
}
- /*
+/*
** ST_ABORTFCT -- deal with aborts
**
** Parameters:
@@ -941,7 +961,7 @@ st_abortfct(g)
(void) (*fi_abort)(g->a_ctx);
return _SMFIS_NOREPLY;
}
- /*
+/*
** TRANS_OK -- is the state transition ok?
**
** Parameters:
@@ -963,13 +983,14 @@ trans_ok(old, new)
{
/* is this state transition allowed? */
if ((MASK(new) & next_states[s]) != 0)
- return TRUE;
+ return true;
/*
** no: try next state;
** this works since the relevant states are ordered
** strict sequentially
*/
+
n = s + 1;
/*
@@ -977,14 +998,15 @@ trans_ok(old, new)
** see fix_stm() which sets this bit for those
** states which the filter program is not interested in
*/
+
if (bitset(NX_SKIP, next_states[n]))
s = n;
else
- return FALSE;
+ return false;
} while (s <= ST_LAST);
- return FALSE;
+ return false;
}
- /*
+/*
** FIX_STM -- add "skip" bits to the state transition table
**
** Parameters:
@@ -1001,7 +1023,7 @@ static void
fix_stm(ctx)
SMFICTX_PTR ctx;
{
- u_long fl;
+ unsigned long fl;
if (ctx == NULL || ctx->ctx_smfi == NULL)
return;
@@ -1021,7 +1043,7 @@ fix_stm(ctx)
if (bitset(SMFIP_NOBODY, fl))
next_states[ST_BODY] |= NX_SKIP;
}
- /*
+/*
** DEC_ARGV -- split a buffer into a list of strings, NULL terminated
**
** Parameters:
@@ -1065,7 +1087,7 @@ dec_argv(buf, len)
s[elem] = NULL;
return s;
}
- /*
+/*
** DEC_ARG2 -- split a buffer into two strings
**
** Parameters:
@@ -1094,7 +1116,7 @@ dec_arg2(buf, len, s1, s2)
*s2 = buf + i + 1;
return MI_SUCCESS;
}
- /*
+/*
** SENDOK -- is it ok for the filter to send stuff to the MTA?
**
** Parameters:
@@ -1111,9 +1133,12 @@ mi_sendok(ctx, flag)
int flag;
{
if (ctx == NULL || ctx->ctx_smfi == NULL)
- return FALSE;
+ return false;
+
+ /* did the milter request this operation? */
if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags))
- return FALSE;
+ return false;
+
+ /* are we in the correct state? It must be "End of Message". */
return ctx->ctx_state == ST_ENDM;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/handler.c b/contrib/sendmail/libmilter/handler.c
index 2ee5203..29ea446 100644
--- a/contrib/sendmail/libmilter/handler.c
+++ b/contrib/sendmail/libmilter/handler.c
@@ -8,11 +8,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: handler.c,v 8.19.4.3 2000/12/29 19:45:39 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: handler.c,v 8.29 2001/11/15 00:17:15 msk Exp $")
-#if _FFR_MILTER
#include "libmilter.h"
@@ -45,7 +43,7 @@ mi_handle_session(ctx)
ret = mi_engine(ctx);
if (ValidSocket(ctx->ctx_sd))
{
- (void) close(ctx->ctx_sd);
+ (void) closesocket(ctx->ctx_sd);
ctx->ctx_sd = INVALID_SOCKET;
}
if (ctx->ctx_reply != NULL)
@@ -64,4 +62,3 @@ mi_handle_session(ctx)
ctx = NULL;
return ret;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/libmilter.h b/contrib/sendmail/libmilter/libmilter.h
index 49ac70f..d135aab 100644
--- a/contrib/sendmail/libmilter/libmilter.h
+++ b/contrib/sendmail/libmilter/libmilter.h
@@ -13,12 +13,13 @@
#ifndef _LIBMILTER_H
# define _LIBMILTER_H 1
+
+#include <sm/gen.h>
+
#ifdef _DEFINE
# define EXTERN
# define INIT(x) = x
-# ifndef lint
-static char MilterlId[] = "@(#)$Id: libmilter.h,v 8.3.6.16 2001/06/07 23:21:35 geir Exp $";
-# endif /* ! lint */
+SM_IDSTR(MilterlId, "@(#)$Id: libmilter.h,v 8.32 2001/11/29 02:21:02 ca Exp $")
#else /* _DEFINE */
# define EXTERN extern
# define INIT(x)
@@ -31,15 +32,12 @@ static char MilterlId[] = "@(#)$Id: libmilter.h,v 8.3.6.16 2001/06/07 23:21:35 g
#include "libmilter/milter.h"
-#ifndef __P
-# include "sendmail/cdefs.h"
-#endif /* ! __P */
-#include "sendmail/useful.h"
-
# define ValidSocket(sd) ((sd) >= 0)
-# define INVALID_SOCKET -1
-# define MI_SOCK_READ(s, b, l) (read(s, b, l))
-# define MI_SOCK_WRITE(s, b, l) (write(s, b, l))
+# define INVALID_SOCKET (-1)
+# define closesocket close
+# define MI_SOCK_READ(s, b, l) read(s, b, l)
+# define MI_SOCK_READ_FAIL(x) ((x) < 0)
+# define MI_SOCK_WRITE(s, b, l) write(s, b, l)
# define thread_create(ptid,wr,arg) pthread_create(ptid, NULL, wr, arg)
# define sthread_get_id() pthread_self()
@@ -61,16 +59,19 @@ typedef pthread_mutex_t smutex_t;
#define MI_TIMEOUT 7210 /* default timeout for read/write */
#define MI_CHK_TIME 5 /* checking whether to terminate */
-#if SOMAXCONN > 20
-# define MI_SOMAXCONN SOMAXCONN
-#else /* SOMAXCONN */
-# define MI_SOMAXCONN 20
-#endif /* SOMAXCONN */
+#ifndef MI_SOMAXCONN
+# if SOMAXCONN > 20
+# define MI_SOMAXCONN SOMAXCONN
+# else /* SOMAXCONN */
+# define MI_SOMAXCONN 20
+# endif /* SOMAXCONN */
+#endif /* ! MI_SOMAXCONN */
/* maximum number of repeated failures in mi_listener() */
#define MAX_FAILS_M 16 /* malloc() */
#define MAX_FAILS_T 16 /* thread creation */
#define MAX_FAILS_A 16 /* accept() */
+#define MAX_FAILS_S 16 /* select() */
/* internal "commands", i.e., error codes */
#define SMFIC_TIMEOUT ((char) 1) /* timeout */
@@ -84,6 +85,7 @@ typedef pthread_mutex_t smutex_t;
/* hack */
#define smi_log syslog
+#define sm_dprintf printf
#define milter_ret int
#define SMI_LOG_ERR LOG_ERR
#define SMI_LOG_FATAL LOG_ERR
@@ -106,6 +108,7 @@ extern int mi_control_startup __P((char *));
extern void mi_stop_milters __P((int));
extern void mi_clean_signals __P((void));
extern struct hostent *mi_gethostbyname __P((char *, int));
+extern int mi_inet_pton __P((int, const char *, void *));
extern void mi_closener __P((void));
/* communication functions */
@@ -113,4 +116,5 @@ extern char *mi_rd_cmd __P((socket_t, struct timeval *, char *, size_t *, char *
extern int mi_wr_cmd __P((socket_t, struct timeval *, int, char *, size_t));
extern bool mi_sendok __P((SMFICTX_PTR, int));
+
#endif /* !_LIBMILTER_H */
diff --git a/contrib/sendmail/libmilter/listener.c b/contrib/sendmail/libmilter/listener.c
index 6a59955..9b75ce0 100644
--- a/contrib/sendmail/libmilter/listener.c
+++ b/contrib/sendmail/libmilter/listener.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,22 +8,24 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: listener.c,v 8.38.2.1.2.22 2001/05/16 17:15:58 ca Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: listener.c,v 8.81 2002/01/08 23:14:23 ca Exp $")
-#if _FFR_MILTER
/*
** listener.c -- threaded network listener
*/
#include "libmilter.h"
+#include <sm/errstring.h>
# if NETINET || NETINET6
# include <arpa/inet.h>
# endif /* NETINET || NETINET6 */
- /*
+
+static smutex_t L_Mutex;
+
+/*
** MI_MILTEROPEN -- setup socket to listen on
**
** Parameters:
@@ -35,8 +37,15 @@ static char id[] = "@(#)$Id: listener.c,v 8.38.2.1.2.22 2001/05/16 17:15:58 ca E
**
** Returns:
** socket upon success, error code otherwise.
+**
+** Side effect:
+** sets sockpath if UNIX socket.
*/
+#if NETUNIX
+static char *sockpath = NULL;
+#endif /* NETUNIX */
+
static socket_t
mi_milteropen(conn, backlog, socksize, family, name)
char *conn;
@@ -47,6 +56,7 @@ mi_milteropen(conn, backlog, socksize, family, name)
{
socket_t sock;
int sockopt = 1;
+ size_t len = 0;
char *p;
char *colon;
char *at;
@@ -157,15 +167,16 @@ mi_milteropen(conn, backlog, socksize, family, name)
# endif /* 0 */
at = colon;
- if (strlcpy(addr.sunix.sun_path, colon,
- sizeof addr.sunix.sun_path) >=
- sizeof addr.sunix.sun_path)
+ len = strlen(colon) + 1;
+ if (len >= sizeof addr.sunix.sun_path)
{
errno = EINVAL;
smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
name, colon);
return INVALID_SOCKET;
}
+ (void) sm_strlcpy(addr.sunix.sun_path, colon,
+ sizeof addr.sunix.sun_path);
# if 0
errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
S_IRUSR|S_IWUSR, NULL);
@@ -179,7 +190,6 @@ mi_milteropen(conn, backlog, socksize, family, name)
return INVALID_SOCKET;
}
# endif /* 0 */
-
}
#endif /* NETUNIX */
@@ -196,7 +206,7 @@ mi_milteropen(conn, backlog, socksize, family, name)
# endif /* NETINET6 */
)
{
- u_short port;
+ unsigned short port;
/* Parse port@host */
at = strchr(colon, '@');
@@ -221,7 +231,7 @@ mi_milteropen(conn, backlog, socksize, family, name)
*at = '\0';
if (isascii(*colon) && isdigit(*colon))
- port = htons((u_short) atoi(colon));
+ port = htons((unsigned short) atoi(colon));
else
{
# ifdef NO_GETSERVBYNAME
@@ -252,7 +262,7 @@ mi_milteropen(conn, backlog, socksize, family, name)
end = strchr(at, ']');
if (end != NULL)
{
- bool found = FALSE;
+ bool found = false;
# if NETINET
unsigned long hid = INADDR_NONE;
# endif /* NETINET */
@@ -263,23 +273,22 @@ mi_milteropen(conn, backlog, socksize, family, name)
*end = '\0';
# if NETINET
if (addr.sa.sa_family == AF_INET &&
- (hid = inet_addr(&at[1])) !=
- INADDR_NONE)
+ (hid = inet_addr(&at[1])) != INADDR_NONE)
{
addr.sin.sin_addr.s_addr = hid;
addr.sin.sin_port = port;
- found = TRUE;
+ found = true;
}
# endif /* NETINET */
# if NETINET6
(void) memset(&hid6, '\0', sizeof hid6);
if (addr.sa.sa_family == AF_INET6 &&
- inet_pton(AF_INET6, &at[1],
- &hid6.sin6_addr) == 1)
+ mi_inet_pton(AF_INET6, &at[1],
+ &hid6.sin6_addr) == 1)
{
addr.sin6.sin6_addr = hid6.sin6_addr;
addr.sin6.sin6_port = port;
- found = TRUE;
+ found = true;
}
# endif /* NETINET6 */
*end = ']';
@@ -338,9 +347,9 @@ mi_milteropen(conn, backlog, socksize, family, name)
name, at, hp->h_addrtype);
return INVALID_SOCKET;
}
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
}
}
else
@@ -367,7 +376,7 @@ mi_milteropen(conn, backlog, socksize, family, name)
{
smi_log(SMI_LOG_ERR,
"%s: Unable to create new socket: %s",
- name, strerror(errno));
+ name, sm_errstring(errno));
return INVALID_SOCKET;
}
@@ -375,8 +384,9 @@ mi_milteropen(conn, backlog, socksize, family, name)
sizeof(sockopt)) == -1)
{
smi_log(SMI_LOG_ERR,
- "%s: Unable to setsockopt: %s", name, strerror(errno));
- (void) close(sock);
+ "%s: Unable to setsockopt: %s", name,
+ sm_errstring(errno));
+ (void) closesocket(sock);
return INVALID_SOCKET;
}
@@ -384,22 +394,45 @@ mi_milteropen(conn, backlog, socksize, family, name)
{
smi_log(SMI_LOG_ERR,
"%s: Unable to bind to port %s: %s",
- name, conn, strerror(errno));
- (void) close(sock);
+ name, conn, sm_errstring(errno));
+ (void) closesocket(sock);
return INVALID_SOCKET;
}
if (listen(sock, backlog) < 0)
{
smi_log(SMI_LOG_ERR,
- "%s: listen call failed: %s", name, strerror(errno));
- (void) close(sock);
+ "%s: listen call failed: %s", name,
+ sm_errstring(errno));
+ (void) closesocket(sock);
return INVALID_SOCKET;
}
+
+#if NETUNIX
+ if (addr.sa.sa_family == AF_UNIX && len > 0)
+ {
+ /*
+ ** Set global variable sockpath so the UNIX socket can be
+ ** unlink()ed at exit.
+ */
+
+ sockpath = (char *) malloc(len);
+ if (sockpath != NULL)
+ (void) sm_strlcpy(sockpath, colon, len);
+ else
+ {
+ smi_log(SMI_LOG_ERR,
+ "%s: can't malloc(%d) for sockpath: %s",
+ name, len, sm_errstring(errno));
+ (void) closesocket(sock);
+ return INVALID_SOCKET;
+ }
+ }
+#endif /* NETUNIX */
*family = addr.sa.sa_family;
return sock;
}
- /*
+/*
** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
**
** Parameters:
@@ -418,11 +451,12 @@ mi_thread_handle_wrapper(arg)
static socket_t listenfd = INVALID_SOCKET;
-static smutex_t L_Mutex;
-
- /*
+/*
** MI_CLOSENER -- close listen socket
**
+** NOTE: It is assumed that this function is called from a
+** function that has a mutex lock (currently mi_stop_milters()).
+**
** Parameters:
** none.
**
@@ -436,13 +470,54 @@ mi_closener()
(void) smutex_lock(&L_Mutex);
if (ValidSocket(listenfd))
{
- (void) close(listenfd);
+#if NETUNIX
+ bool removable;
+ struct stat sockinfo;
+ struct stat fileinfo;
+
+ removable = sockpath != NULL &&
+#if _FFR_MILTER_ROOT_UNSAFE
+ geteuid() != 0 &&
+#endif /* _FFR_MILTER_ROOT_UNSAFE */
+ fstat(listenfd, &sockinfo) == 0 &&
+ (S_ISFIFO(sockinfo.st_mode)
+# ifdef S_ISSOCK
+ || S_ISSOCK(sockinfo.st_mode)
+# endif /* S_ISSOCK */
+ );
+#endif /* NETUNIX */
+
+ (void) closesocket(listenfd);
listenfd = INVALID_SOCKET;
+
+#if NETUNIX
+ /* XXX sleep() some time before doing this? */
+ if (sockpath != NULL)
+ {
+ if (removable &&
+ stat(sockpath, &fileinfo) == 0 &&
+ ((fileinfo.st_dev == sockinfo.st_dev &&
+ fileinfo.st_ino == sockinfo.st_ino)
+# ifdef S_ISSOCK
+ || S_ISSOCK(fileinfo.st_mode)
+# endif /* S_ISSOCK */
+ )
+ &&
+ (S_ISFIFO(fileinfo.st_mode)
+# ifdef S_ISSOCK
+ || S_ISSOCK(fileinfo.st_mode)
+# endif /* S_ISSOCK */
+ ))
+ (void) unlink(sockpath);
+ free(sockpath);
+ sockpath = NULL;
+ }
+#endif /* NETUNIX */
}
(void) smutex_unlock(&L_Mutex);
}
- /*
+/*
** MI_LISTENER -- Generic listener harness
**
** Open up listen port
@@ -460,7 +535,7 @@ mi_closener()
** MI_FAILURE -- Network initialization failed.
*/
-# if BROKEN_PTHREAD_SLEEP
+#if BROKEN_PTHREAD_SLEEP
/*
** Solaris 2.6, perhaps others, gets an internal threads library panic
@@ -480,7 +555,7 @@ mi_closener()
** 0
*/
-# define MI_SLEEP(s) \
+# define MI_SLEEP(s) \
{ \
int rs = 0; \
struct timeval st; \
@@ -496,9 +571,9 @@ mi_closener()
rs, errno); \
} \
}
-# else /* BROKEN_PTHREAD_SLEEP */
-# define MI_SLEEP(s) sleep((s))
-# endif /* BROKEN_PTHREAD_SLEEP */
+#else /* BROKEN_PTHREAD_SLEEP */
+# define MI_SLEEP(s) sleep((s))
+#endif /* BROKEN_PTHREAD_SLEEP */
int
mi_listener(conn, dbg, smfi, timeout, backlog)
@@ -513,9 +588,10 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
int sockopt = 1;
int r;
int ret = MI_SUCCESS;
- int mcnt = 0;
- int tcnt = 0;
- int acnt = 0;
+ int mcnt = 0; /* error count for malloc() failures */
+ int tcnt = 0; /* error count for thread_create() failures */
+ int acnt = 0; /* error count for accept() failures */
+ int scnt = 0; /* error count for select() failures */
int save_errno = 0;
sthread_t thread_id;
_SOCK_ADDR cliaddr;
@@ -564,8 +640,8 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
/* select on interface ports */
FD_ZERO(&readset);
FD_ZERO(&excset);
- FD_SET((u_int) listenfd, &readset);
- FD_SET((u_int) listenfd, &excset);
+ FD_SET((unsigned int) listenfd, &readset);
+ FD_SET((unsigned int) listenfd, &excset);
chktime.tv_sec = MI_CHK_TIME;
chktime.tv_usec = 0;
r = select(listenfd + 1, &readset, NULL, &excset, &chktime);
@@ -580,16 +656,30 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
(void) smutex_unlock(&L_Mutex);
if (save_errno == EINTR)
continue;
- ret = MI_FAILURE;
- break;
+ scnt++;
+ smi_log(SMI_LOG_ERR,
+ "%s: select() failed (%s), %s",
+ smfi->xxfi_name, sm_errstring(save_errno),
+ scnt >= MAX_FAILS_S ? "abort" : "try again");
+ MI_SLEEP(scnt);
+ if (scnt >= MAX_FAILS_S)
+ {
+ ret = MI_FAILURE;
+ break;
+ }
+ continue;
}
if (!FD_ISSET(listenfd, &readset))
{
/* some error: just stop for now... */
ret = MI_FAILURE;
(void) smutex_unlock(&L_Mutex);
+ smi_log(SMI_LOG_ERR,
+ "%s: select() returned exception for socket, abort",
+ smfi->xxfi_name);
break;
}
+ scnt = 0; /* reset error counter for select() */
memset(&cliaddr, '\0', sizeof cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
@@ -610,19 +700,20 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
# endif /* BSD4_4_SOCKADDR */
cliaddr.sa.sa_family != family))
{
- (void) close(connfd);
+ (void) closesocket(connfd);
connfd = INVALID_SOCKET;
save_errno = EINVAL;
}
if (!ValidSocket(connfd))
{
- smi_log(SMI_LOG_ERR,
- "%s: accept() returned invalid socket (%s)",
- smfi->xxfi_name, strerror(save_errno));
if (save_errno == EINTR)
continue;
acnt++;
+ smi_log(SMI_LOG_ERR,
+ "%s: accept() returned invalid socket (%s), %s",
+ smfi->xxfi_name, sm_errstring(save_errno),
+ acnt >= MAX_FAILS_A ? "abort" : "try again");
MI_SLEEP(acnt);
if (acnt >= MAX_FAILS_A)
{
@@ -631,20 +722,22 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
}
continue;
}
+ acnt = 0; /* reset error counter for accept() */
if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
(void *) &sockopt, sizeof sockopt) < 0)
{
- smi_log(SMI_LOG_WARN, "%s: setsockopt() failed",
- smfi->xxfi_name);
+ smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
+ smfi->xxfi_name, sm_errstring(errno));
/* XXX: continue? */
}
if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
{
- (void) close(connfd);
- smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed",
- smfi->xxfi_name);
+ (void) closesocket(connfd);
mcnt++;
+ smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
+ smfi->xxfi_name, sm_errstring(save_errno),
+ mcnt >= MAX_FAILS_M ? "abort" : "try again");
MI_SLEEP(mcnt);
if (mcnt >= MAX_FAILS_M)
{
@@ -653,8 +746,7 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
}
continue;
}
- mcnt = 0;
- acnt = 0;
+ mcnt = 0; /* reset error counter for malloc() */
memset(ctx, '\0', sizeof *ctx);
ctx->ctx_sd = connfd;
ctx->ctx_dbg = dbg;
@@ -685,12 +777,13 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
mi_thread_handle_wrapper,
(void *) ctx)) != 0)
{
- smi_log(SMI_LOG_ERR,
- "%s: thread_create() failed: %d",
- smfi->xxfi_name, r);
tcnt++;
+ smi_log(SMI_LOG_ERR,
+ "%s: thread_create() failed: %d, %s",
+ smfi->xxfi_name, r,
+ tcnt >= MAX_FAILS_T ? "abort" : "try again");
MI_SLEEP(tcnt);
- (void) close(connfd);
+ (void) closesocket(connfd);
free(ctx);
if (tcnt >= MAX_FAILS_T)
{
@@ -708,4 +801,3 @@ mi_listener(conn, dbg, smfi, timeout, backlog)
(void) smutex_destroy(&L_Mutex);
return ret;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/main.c b/contrib/sendmail/libmilter/main.c
index 6afebdb..ee440e3 100644
--- a/contrib/sendmail/libmilter/main.c
+++ b/contrib/sendmail/libmilter/main.c
@@ -8,11 +8,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: main.c,v 8.34.4.11 2001/05/07 22:06:37 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: main.c,v 8.53 2001/11/29 02:21:02 ca Exp $")
-#if _FFR_MILTER
#define _DEFINE 1
#include "libmilter.h"
#include <fcntl.h>
@@ -51,7 +49,7 @@ smfi_register(smfilter)
smfi->xxfi_name = (char *) malloc(len);
if (smfi->xxfi_name == NULL)
return MI_FAILURE;
- (void) strlcpy(smfi->xxfi_name, smfilter.xxfi_name, len);
+ (void) sm_strlcpy(smfi->xxfi_name, smfilter.xxfi_name, len);
/* compare milter version with hard coded version */
if (smfi->xxfi_version != SMFI_VERSION)
@@ -61,13 +59,16 @@ smfi_register(smfilter)
"%s: smfi_register: version mismatch application: %d != milter: %d",
smfi->xxfi_name, smfi->xxfi_version,
(int) SMFI_VERSION);
+
+ /* XXX how about smfi? */
+ free(smfi->xxfi_name);
return MI_FAILURE;
}
return MI_SUCCESS;
}
- /*
+/*
** SMFI_STOP -- stop milter
**
** Parameters:
@@ -84,11 +85,26 @@ smfi_stop()
return MI_SUCCESS;
}
+/*
+** default values for some variables.
+** Most of these can be changed with the functions below.
+*/
+
static int dbg = 0;
static char *conn = NULL;
static int timeout = MI_TIMEOUT;
static int backlog= MI_SOMAXCONN;
+/*
+** SMFI_SETDBG -- set debug level.
+**
+** Parameters:
+** odbg -- new debug level.
+**
+** Returns:
+** MI_SUCCESS
+*/
+
int
smfi_setdbg(odbg)
int odbg;
@@ -97,6 +113,16 @@ smfi_setdbg(odbg)
return MI_SUCCESS;
}
+/*
+** SMFI_SETTIMEOUT -- set timeout (for read/write).
+**
+** Parameters:
+** otimeout -- new timeout.
+**
+** Returns:
+** MI_SUCCESS
+*/
+
int
smfi_settimeout(otimeout)
int otimeout;
@@ -105,6 +131,16 @@ smfi_settimeout(otimeout)
return MI_SUCCESS;
}
+/*
+** SMFI_SETCONN -- set connection information (socket description)
+**
+** Parameters:
+** oconn -- new connection information.
+**
+** Returns:
+** MI_SUCCESS/MI_FAILURE
+*/
+
int
smfi_setconn(oconn)
char *oconn;
@@ -116,11 +152,21 @@ smfi_setconn(oconn)
l = strlen(oconn) + 1;
if ((conn = (char *) malloc(l)) == NULL)
return MI_FAILURE;
- if (strlcpy(conn, oconn, l) >= l)
+ if (sm_strlcpy(conn, oconn, l) >= l)
return MI_FAILURE;
return MI_SUCCESS;
}
+/*
+** SMFI_SETBACKLOG -- set backlog
+**
+** Parameters:
+** odbg -- new backlog.
+**
+** Returns:
+** MI_SUCCESS/MI_FAILURE
+*/
+
int
smfi_setbacklog(obacklog)
int obacklog;
@@ -132,11 +178,22 @@ smfi_setbacklog(obacklog)
}
+/*
+** SMFI_MAIN -- setup milter connnection and start listener.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** MI_SUCCESS/MI_FAILURE
+*/
+
int
smfi_main()
{
+ int r;
- signal(SIGPIPE, SIG_IGN);
+ (void) signal(SIGPIPE, SIG_IGN);
if (conn == NULL)
{
smi_log(SMI_LOG_FATAL, "%s: missing connection information",
@@ -152,12 +209,11 @@ smfi_main()
smfi->xxfi_name);
return MI_FAILURE;
}
-
+ r = MI_SUCCESS;
/* Startup the listener */
if (mi_listener(conn, dbg, smfi, timeout, backlog) != MI_SUCCESS)
- return MI_FAILURE;
+ r = MI_FAILURE;
- return MI_SUCCESS;
+ return r;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/signal.c b/contrib/sendmail/libmilter/signal.c
index 0bc5081..b160f5d 100644
--- a/contrib/sendmail/libmilter/signal.c
+++ b/contrib/sendmail/libmilter/signal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,11 +8,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: signal.c,v 8.10.4.8 2000/11/20 21:15:37 ca Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: signal.c,v 8.35 2002/01/10 01:34:55 ca Exp $")
-#if _FFR_MILTER
#include "libmilter.h"
/*
@@ -23,7 +21,7 @@ static smutex_t M_Mutex;
static int MilterStop = MILTER_CONT;
- /*
+/*
** MI_STOP -- return value of MilterStop
**
** Parameters:
@@ -38,7 +36,7 @@ mi_stop()
{
return MilterStop;
}
- /*
+/*
** MI_STOP_MILTERS -- set value of MilterStop
**
** Parameters:
@@ -60,7 +58,7 @@ mi_stop_milters(v)
mi_closener();
(void) smutex_unlock(&M_Mutex);
}
- /*
+/*
** MI_CLEAN_SIGNALS -- clean up signal handler thread
**
** Parameters:
@@ -75,7 +73,7 @@ mi_clean_signals()
{
(void) smutex_destroy(&M_Mutex);
}
- /*
+/*
** MI_SIGNAL_THREAD -- thread to deal with signals
**
** Parameters:
@@ -100,18 +98,18 @@ mi_signal_thread(name)
sigaddset(&set, SIGINT);
errs = 0;
- while (TRUE)
+ while (true)
{
sig = 0;
-#ifdef SOLARIS
+#if defined(SOLARIS) || defined(__svr5__)
if ((sig = sigwait(&set)) < 0)
-#else /* SOLARIS */
+#else /* defined(SOLARIS) || defined(__svr5__) */
if (sigwait(&set, &sig) != 0)
-#endif /* SOLARIS */
+#endif /* defined(SOLARIS) || defined(__svr5__) */
{
smi_log(SMI_LOG_ERR,
- "%s: sigwait returned error: %s",
- (char *)name, strerror(errno));
+ "%s: sigwait returned error: %d",
+ (char *)name, errno);
if (++errs > MAX_FAILS_T)
{
mi_stop_milters(MILTER_ABRT);
@@ -138,7 +136,7 @@ mi_signal_thread(name)
}
}
}
- /*
+/*
** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
**
** Parameters:
@@ -153,6 +151,7 @@ mi_spawn_signal_thread(name)
char *name;
{
sthread_t tid;
+ int r;
sigset_t set;
/* Mask HUP and KILL signals */
@@ -167,16 +166,17 @@ mi_spawn_signal_thread(name)
"%s: Couldn't mask HUP and KILL signals", name);
return MI_FAILURE;
}
- if (thread_create(&tid, mi_signal_thread,
- (void *)name) != MI_SUCCESS)
+ r = thread_create(&tid, mi_signal_thread, (void *)name);
+ if (r != 0)
{
smi_log(SMI_LOG_ERR,
- "%s: Couldn't start signal thread", name);
+ "%s: Couldn't start signal thread: %d",
+ name, r);
return MI_FAILURE;
}
return MI_SUCCESS;
}
- /*
+/*
** MI_CONTROL_STARTUP -- startup for thread to handle signals
**
** Parameters:
@@ -212,4 +212,3 @@ mi_control_startup(name)
}
return MI_SUCCESS;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libmilter/sm_gethost.c b/contrib/sendmail/libmilter/sm_gethost.c
index c1e80b1..1714741 100644
--- a/contrib/sendmail/libmilter/sm_gethost.c
+++ b/contrib/sendmail/libmilter/sm_gethost.c
@@ -8,17 +8,15 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: sm_gethost.c,v 8.7.8.11 2001/07/21 00:10:23 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: sm_gethost.c,v 8.26 2001/09/11 04:04:45 gshapiro Exp $")
-#if _FFR_MILTER
#include <sendmail.h>
#if NETINET || NETINET6
# include <arpa/inet.h>
#endif /* NETINET || NETINET6 */
- /*
+/*
** MI_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
**
** Some operating systems have wierd problems with the gethostbyXXX
@@ -48,7 +46,7 @@ getipnodebyname(name, family, flags, err)
int flags;
int *err;
{
- bool resv6 = TRUE;
+ bool resv6 = true;
struct hostent *h;
if (family == AF_INET6)
@@ -59,13 +57,12 @@ getipnodebyname(name, family, flags, err)
}
SM_SET_H_ERRNO(0);
h = gethostbyname(name);
- *err = h_errno;
if (family == AF_INET6 && !resv6)
_res.options &= ~RES_USE_INET6;
+ *err = h_errno;
return h;
}
-# if _FFR_FREEHOSTENT
void
freehostent(h)
struct hostent *h;
@@ -77,7 +74,6 @@ freehostent(h)
return;
}
-# endif /* _FFR_FREEHOSTENT */
#endif /* NEEDSGETIPNODE && NETINET6 */
struct hostent *
@@ -117,4 +113,33 @@ mi_gethostbyname(name, family)
#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
return h;
}
-#endif /* _FFR_MILTER */
+
+#if NETINET6
+/*
+** MI_INET_PTON -- convert printed form to network address.
+**
+** Wrapper for inet_pton() which handles IPv6: labels.
+**
+** Parameters:
+** family -- address family
+** src -- string
+** dst -- destination address structure
+**
+** Returns:
+** 1 if the address was valid
+** 0 if the address wasn't parseable
+** -1 if error
+*/
+
+int
+mi_inet_pton(family, src, dst)
+ int family;
+ const char *src;
+ void *dst;
+{
+ if (family == AF_INET6 &&
+ strncasecmp(src, "IPv6:", 5) == 0)
+ src += 5;
+ return inet_pton(family, src, dst);
+}
+#endif /* NETINET6 */
diff --git a/contrib/sendmail/libmilter/smfi.c b/contrib/sendmail/libmilter/smfi.c
index e034aa8..fd564d5 100644
--- a/contrib/sendmail/libmilter/smfi.c
+++ b/contrib/sendmail/libmilter/smfi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,13 +8,14 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $";
-#endif /* ! lint */
-
-#if _FFR_MILTER
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: smfi.c,v 8.57 2001/11/20 18:47:49 ca Exp $")
+#include <sm/varargs.h>
#include "libmilter.h"
-#include "sendmail/useful.h"
+
+/* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
+#define MAXREPLYLEN 980 /* max. length of a reply string */
+#define MAXREPLIES 32 /* max. number of reply strings */
/*
** SMFI_ADDHEADER -- send a new header to the MTA
@@ -110,7 +111,7 @@ smfi_chgheader(ctx, headerf, hdridx, headerv)
free(buf);
return r;
}
- /*
+/*
** SMFI_ADDRCPT -- send an additional recipient to the MTA
**
** Parameters:
@@ -138,7 +139,7 @@ smfi_addrcpt(ctx, rcpt)
len = strlen(rcpt) + 1;
return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
}
- /*
+/*
** SMFI_DELRCPT -- send a recipient to be removed to the MTA
**
** Parameters:
@@ -166,7 +167,7 @@ smfi_delrcpt(ctx, rcpt)
len = strlen(rcpt) + 1;
return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
}
- /*
+/*
** SMFI_REPLACEBODY -- send a body chunk to the MTA
**
** Parameters:
@@ -181,13 +182,14 @@ smfi_delrcpt(ctx, rcpt)
int
smfi_replacebody(ctx, bodyp, bodylen)
SMFICTX *ctx;
- u_char *bodyp;
+ unsigned char *bodyp;
int bodylen;
{
int len, off, r;
struct timeval timeout;
- if (bodyp == NULL && bodylen > 0)
+ if (bodylen < 0 ||
+ (bodyp == NULL && bodylen > 0))
return MI_FAILURE;
if (!mi_sendok(ctx, SMFIF_CHGBODY))
return MI_FAILURE;
@@ -208,7 +210,46 @@ smfi_replacebody(ctx, bodyp, bodylen)
}
return MI_SUCCESS;
}
- /*
+#if _FFR_QUARANTINE
+/*
+** SMFI_QUARANTINE -- quarantine an envelope
+**
+** Parameters:
+** ctx -- Opaque context structure
+** reason -- why?
+**
+** Returns:
+** MI_SUCCESS/MI_FAILURE
+*/
+
+int
+smfi_quarantine(ctx, reason)
+ SMFICTX *ctx;
+ char *reason;
+{
+ size_t len;
+ int r;
+ char *buf;
+ struct timeval timeout;
+
+ if (reason == NULL || *reason == '\0')
+ return MI_FAILURE;
+ if (!mi_sendok(ctx, SMFIF_QUARANTINE))
+ return MI_FAILURE;
+ timeout.tv_sec = ctx->ctx_timeout;
+ timeout.tv_usec = 0;
+ len = strlen(reason) + 1;
+ buf = malloc(len);
+ if (buf == NULL)
+ return MI_FAILURE;
+ (void) memcpy(buf, reason, len);
+ r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
+ free(buf);
+ return r;
+}
+#endif /* _FFR_QUARANTINE */
+
+/*
** MYISENHSC -- check whether a string contains an enhanced status code
**
** Parameters:
@@ -247,7 +288,8 @@ myisenhsc(s, delim)
return 0;
return l + h;
}
- /*
+
+/*
** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
**
** Parameters:
@@ -267,35 +309,170 @@ smfi_setreply(ctx, rcode, xcode, message)
char *xcode;
char *message;
{
- size_t len, l1, l2, l3;
+ size_t len;
char *buf;
if (rcode == NULL || ctx == NULL)
return MI_FAILURE;
- l1 = strlen(rcode) + 1;
- if (l1 != 4)
+
+ /* ### <sp> \0 */
+ len = strlen(rcode) + 2;
+ if (len != 5)
return MI_FAILURE;
if ((rcode[0] != '4' && rcode[0] != '5') ||
!isascii(rcode[1]) || !isdigit(rcode[1]) ||
!isascii(rcode[2]) || !isdigit(rcode[2]))
return MI_FAILURE;
- l2 = xcode == NULL ? 1 : strlen(xcode) + 1;
- if (xcode != NULL && !myisenhsc(xcode, '\0'))
+ if (xcode != NULL)
+ {
+ if (!myisenhsc(xcode, '\0'))
+ return MI_FAILURE;
+ len += strlen(xcode) + 1;
+ }
+ if (message != NULL)
+ {
+ size_t ml;
+
+ /* XXX check also for unprintable chars? */
+ if (strpbrk(message, "\r\n") != NULL)
+ return MI_FAILURE;
+ ml = strlen(message);
+ if (ml > MAXREPLYLEN)
+ return MI_FAILURE;
+ len += ml + 1;
+ }
+ buf = malloc(len);
+ if (buf == NULL)
+ return MI_FAILURE; /* oops */
+ (void) sm_strlcpy(buf, rcode, len);
+ (void) sm_strlcat(buf, " ", len);
+ if (xcode != NULL)
+ (void) sm_strlcat(buf, xcode, len);
+ if (message != NULL)
+ {
+ if (xcode != NULL)
+ (void) sm_strlcat(buf, " ", len);
+ (void) sm_strlcat(buf, message, len);
+ }
+ if (ctx->ctx_reply != NULL)
+ free(ctx->ctx_reply);
+ ctx->ctx_reply = buf;
+ return MI_SUCCESS;
+}
+
+#if _FFR_MULTILINE
+/*
+** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
+**
+** Parameters:
+** ctx -- Opaque context structure
+** rcode -- The three-digit (RFC 821) SMTP reply code.
+** xcode -- The extended (RFC 2034) reply code.
+** txt, ... -- The text part of the SMTP reply,
+** MUST be terminated with NULL.
+**
+** Returns:
+** MI_SUCCESS/MI_FAILURE
+*/
+
+int
+#if SM_VA_STD
+smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
+#else /* SM_VA_STD */
+smfi_setmlreply(ctx, rcode, xcode, va_alist)
+ SMFICTX *ctx;
+ const char *rcode;
+ const char *xcode;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ size_t len;
+ size_t rlen;
+ int args;
+ char *buf, *txt;
+ const char *xc;
+ char repl[16];
+ SM_VA_LOCAL_DECL
+
+ if (rcode == NULL || ctx == NULL)
+ return MI_FAILURE;
+
+ /* ### <sp> */
+ len = strlen(rcode) + 1;
+ if (len != 4)
return MI_FAILURE;
- l3 = message == NULL ? 1 : strlen(message) + 1;
- len = l1 + l2 + l3;
+ if ((rcode[0] != '4' && rcode[0] != '5') ||
+ !isascii(rcode[1]) || !isdigit(rcode[1]) ||
+ !isascii(rcode[2]) || !isdigit(rcode[2]))
+ return MI_FAILURE;
+ if (xcode != NULL)
+ {
+ if (!myisenhsc(xcode, '\0'))
+ return MI_FAILURE;
+ xc = xcode;
+ }
+ else
+ {
+ if (rcode[0] == '4')
+ xc = "4.0.0";
+ else
+ xc = "5.0.0";
+ }
+
+ /* add trailing space */
+ len += strlen(xc) + 1;
+ rlen = len;
+ args = 0;
+ SM_VA_START(ap, xcode);
+ while ((txt = SM_VA_ARG(ap, char *)) != NULL)
+ {
+ size_t tl;
+
+ tl = strlen(txt);
+ if (tl > MAXREPLYLEN)
+ return MI_FAILURE;
+
+ /* this text, reply codes, \r\n */
+ len += tl + 2 + rlen;
+ if (++args > MAXREPLIES)
+ return MI_FAILURE;
+
+ /* XXX check also for unprintable chars? */
+ if (strpbrk(txt, "\r\n") != NULL)
+ return MI_FAILURE;
+ }
+ SM_VA_END(ap);
+
+ /* trailing '\0' */
+ ++len;
buf = malloc(len);
if (buf == NULL)
return MI_FAILURE; /* oops */
- (void) snprintf(buf, len, "%s %s %s", rcode,
- xcode == NULL ? "" : xcode,
- message == NULL ? "" : message);
+ (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
+ (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
+ xc, " ");
+ SM_VA_START(ap, xcode);
+ txt = SM_VA_ARG(ap, char *);
+ if (txt != NULL)
+ {
+ (void) sm_strlcat2(buf, " ", txt, len);
+ while ((txt = SM_VA_ARG(ap, char *)) != NULL)
+ {
+ if (--args <= 1)
+ repl[3] = ' ';
+ (void) sm_strlcat2(buf, "\r\n", repl, len);
+ (void) sm_strlcat(buf, txt, len);
+ }
+ }
if (ctx->ctx_reply != NULL)
free(ctx->ctx_reply);
ctx->ctx_reply = buf;
+ SM_VA_END(ap);
return MI_SUCCESS;
}
- /*
+#endif /* _FFR_MULTILINE */
+
+/*
** SMFI_SETPRIV -- set private data
**
** Parameters:
@@ -316,7 +493,7 @@ smfi_setpriv(ctx, privatedata)
ctx->ctx_privdata = privatedata;
return MI_SUCCESS;
}
- /*
+/*
** SMFI_GETPRIV -- get private data
**
** Parameters:
@@ -334,7 +511,7 @@ smfi_getpriv(ctx)
return NULL;
return ctx->ctx_privdata;
}
- /*
+/*
** SMFI_GETSYMVAL -- get the value of a macro
**
** See explanation in mfapi.h about layout of the structures.
@@ -397,4 +574,3 @@ smfi_getsymval(ctx, symname)
}
return NULL;
}
-#endif /* _FFR_MILTER */
diff --git a/contrib/sendmail/libsm/Makefile b/contrib/sendmail/libsm/Makefile
new file mode 100644
index 0000000..c6c1a29
--- /dev/null
+++ b/contrib/sendmail/libsm/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.1 2000/03/27 19:26:48 dmoen Exp $
+
+SHELL= /bin/sh
+BUILD= ./Build
+OPTIONS= $(CONFIG) $(FLAGS)
+
+all: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+clean: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+install: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+
+fresh: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) -c
+
+FRC:
diff --git a/contrib/sendmail/libsm/Makefile.m4 b/contrib/sendmail/libsm/Makefile.m4
new file mode 100644
index 0000000..957eb09
--- /dev/null
+++ b/contrib/sendmail/libsm/Makefile.m4
@@ -0,0 +1,36 @@
+define(`confREQUIRE_LIBUNIX')
+include(confBUILDTOOLSDIR`/M4/switch.m4')
+
+define(`confREQUIRE_LIBSM', `true')
+PREPENDDEF(`confENVDEF', `confMAPDEF')
+bldPRODUCT_START(`library', `libsm')
+define(`bldSOURCES', ` assert.c debug.c errstring.c exc.c heap.c match.c rpool.c strdup.c strerror.c strl.c clrerr.c fclose.c feof.c ferror.c fflush.c fget.c fpos.c findfp.c flags.c fopen.c fprintf.c fpurge.c fput.c fread.c fscanf.c fseek.c fvwrite.c fwalk.c fwrite.c get.c makebuf.c put.c refill.c rewind.c setvbuf.c smstdio.c snprintf.c sscanf.c stdio.c strio.c ungetc.c vasprintf.c vfprintf.c vfscanf.c vprintf.c vsnprintf.c vsprintf.c vsscanf.c wbuf.c wsetup.c string.c stringf.c xtrap.c strto.c test.c path.c strcasecmp.c strrevcmp.c signal.c clock.c config.c shm.c mbdb.c strexit.c cf.c ldap.c niprop.c mpeix.c ')
+bldPRODUCT_END
+dnl sem.c msg.c
+dnl syslogio.c
+
+include(confBUILDTOOLSDIR`/M4/'bldM4_TYPE_DIR`/sm-test.m4')
+smtest(`t-event', `run')
+smtest(`t-exc', `run')
+smtest(`t-rpool', `run')
+smtest(`t-string', `run')
+smtest(`t-smstdio', `run')
+smtest(`t-match', `run')
+smtest(`t-strio', `run')
+smtest(`t-heap', `run')
+smtest(`t-fopen', `run')
+smtest(`t-strl', `run')
+smtest(`t-strrevcmp', `run')
+smtest(`t-types', `run')
+smtest(`t-path', `run')
+smtest(`t-float', `run')
+smtest(`t-scanf', `run')
+smtest(`t-shm', `run')
+dnl smtest(`t-sem', `run')
+dnl smtest(`t-msg', `run')
+smtest(`t-cf')
+smtest(`b-strcmp')
+dnl SM_CONF_STRL cannot be turned off
+dnl smtest(`b-strl')
+
+bldFINISH
diff --git a/contrib/sendmail/libsm/README b/contrib/sendmail/libsm/README
new file mode 100644
index 0000000..ffd43ca
--- /dev/null
+++ b/contrib/sendmail/libsm/README
@@ -0,0 +1,126 @@
+# Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: README,v 1.20 2002/01/09 18:05:39 ca Exp $
+#
+
+Libsm is a library of generally useful C abstractions.
+For documentation, see index.html.
+
+Libsm stands alone; it depends on no other sendmail libraries,
+and the only sendmail header files it depends on are its own,
+which reside in ../include/sm.
+
+The t-*.c files are regression tests.
+These tests are incomplete: we do not yet test all of the APIs,
+and we have not yet converted all tests to use the test harness.
+If a test fails read the explanation it generates. Sometimes it
+is sufficient to change a compile time flag, which are also listed
+below. If that does not help, check the sendmail/README files for
+problems on your OS.
+
+The b-*.c files are benchmarks that compare system routines with
+those provided by libsm. By default sendmail uses the routines
+provided by the OS. In several cases, the routines provided by
+libsm are faster than those of the OS. If your OS provides the
+routines, you can compare the performance of them with the libsm
+versions by running the programs with the option -d (by default
+the programs just issue an explanation when/how to use them).
+The programs are:
+
+b-strcmp.c tests strcasecmp().
+
++----------------------+
+| CONFIGURATION MACROS |
++----------------------+
+
+Libsm uses a set of C preprocessor macros to specify platform specific
+features of the C compiler and standard C libraries.
+
+If you are porting sendmail to a new platform, you may need to tweak
+the values of some of these macros.
+
+The following macros are given default values in <sm/config.h>.
+If the default value is wrong for a given platform, then a platform
+specific value is specified in one of two ways:
+
+ - A -D option is added to the confENVDEF macro; this change can be made
+ to the platform M4 file in devtools/OS, or to the site.config.m4
+ file in devtools/Site.
+
+ - The confSM_OS_HEADER macro in the platform M4 file defines sm_os_foo,
+ which forces "sm/os/sm_os_foo.h" to be included by "sm/config.h" via a
+ link that is made from "sm_os.h" to "sm/os/sm_os_foo.h". Platform
+ specific configuration macro settings are added to <sm/os/sm_os_foo.h>.
+
+SM_CONF_STDBOOL_H
+ Set to 1 if the header file <stdbool.h> exists,
+ and defines true, false and bool.
+
+SM_CONF_SYS_CDEFS_H
+ Set to 1 if the header file <sys/cdefs.h> exists,
+ and defines __P. You may need to do this to eliminate
+ warnings about __P being multiply defined.
+
+SM_CONF_STDDEF_H
+ Set to 0 if the header file <stddef.h> does not exist.
+
+SM_CONF_SETITIMER
+ Set to 0 if the setitimer function is not available.
+
+SM_CONF_SYSEXITS_H
+ Set to 1 if <sysexits.h> exists, and sets the EX_* macros
+ to values different from the default BSD values in <sm/sysexits.h>.
+
+SM_CONF_UID_GID
+ Set to 0 if <sys/types.h> does not define uid_t and gid_t.
+
+SM_CONF_SSIZE_T
+ Set to 0 if <sys/types.h> does not define ssize_t.
+
+SM_CONF_BROKEN_SIZE_T
+ Set to 1 if size_t is not unsigned.
+
+SM_CONF_LONGLONG
+ Set to 1 if your C compiler supports the 'long long' type.
+ This will be set automatically if you use gcc or a C compiler
+ that conforms to the 1999 ISO C standard.
+
+SM_CONF_QUAD_T
+ Set to 1 if your C compiler does not support 'long long',
+ but <sys/types.h> defines quad_t as an integral type.
+
+SM_CONF_SHM
+ Set to 1 if System V shared memory APIs are available.
+
+SM_CONF_MSG
+ Set to 1 if System V message queues are available.
+
+SM_CONF_SEM
+ Set to 1 if semaphores are available.
+
+SM_CONF_BROKEN_STRTOD
+ Set to 1 if your strtod() does not work properly.
+
+SM_CONF_GETOPT
+ Set to 1 if your operating system does not include getopt(3).
+
+SM_IO_MAX_BUF_FILE
+ Set this to a useful buffer size for regular files if stat(2)
+ does not return a value for st_blksize that is the
+ "optimal blocksize for I/O".
+
+SM_IO_MAX_BUF
+ Set this to a useful maximum buffer size for other than
+ regular files if stat(2) does not return a value for
+ st_blksize that is the "optimal blocksize for I/O".
+
+SM_IO_MIN_BUF
+ Set this to a useful minimum buffer size for other than
+ regular files if stat(2) does not return a value for
+ st_blksize that is the "optimal blocksize for I/O".
+
diff --git a/contrib/sendmail/libsm/assert.c b/contrib/sendmail/libsm/assert.c
new file mode 100644
index 0000000..efad1ec
--- /dev/null
+++ b/contrib/sendmail/libsm/assert.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: assert.c,v 1.25 2001/09/11 04:04:47 gshapiro Exp $")
+
+/*
+** Abnormal program termination and assertion checking.
+** For documentation, see assert.html.
+*/
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sm/assert.h>
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/varargs.h>
+
+/*
+** Debug categories that are used to guard expensive assertion checks.
+*/
+
+SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
+ "@(#)$Debug: sm_check_assert - check assertions $");
+
+SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
+ "@(#)$Debug: sm_check_require - check function preconditions $");
+
+SM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure",
+ "@(#)$Debug: sm_check_ensure - check function postconditions $");
+
+/*
+** Debug category: send self SIGSTOP on fatal error,
+** so that you can run a debugger on the stopped process.
+*/
+
+SM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop",
+ "@(#)$Debug: sm_abort_stop - stop process on fatal error $");
+
+/*
+** SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program
+** termination.
+**
+** The goal is to display an error message without disturbing the
+** process state too much, then dump core.
+**
+** Parameters:
+** filename -- filename (can be NULL).
+** lineno -- line number.
+** msg -- message.
+**
+** Returns:
+** doesn't return.
+*/
+
+static void
+sm_abort_defaulthandler __P((
+ const char *filename,
+ int lineno,
+ const char *msg));
+
+static void
+sm_abort_defaulthandler(filename, lineno, msg)
+ const char *filename;
+ int lineno;
+ const char *msg;
+{
+ if (filename != NULL)
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename,
+ lineno, msg);
+ else
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg);
+ sm_io_flush(smioerr, SM_TIME_DEFAULT);
+#ifdef SIGSTOP
+ if (sm_debug_active(&SmAbortStop, 1))
+ kill(getpid(), SIGSTOP);
+#endif /* SIGSTOP */
+ abort();
+}
+
+/*
+** This is the action to be taken to cause abnormal program termination.
+*/
+
+static SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler;
+
+/*
+** SM_ABORT_SETHANDLER -- Set handler for SM_ABORT()
+**
+** This allows you to set a handler function for causing abnormal
+** program termination; it is called when a logic bug is detected.
+**
+** Parameters:
+** f -- handler.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_abort_sethandler(f)
+ SM_ABORT_HANDLER_T f;
+{
+ if (f == NULL)
+ SmAbortHandler = sm_abort_defaulthandler;
+ else
+ SmAbortHandler = f;
+}
+
+/*
+** SM_ABORT -- Call it when you have detected a logic bug.
+**
+** Parameters:
+** fmt -- format string.
+** ... -- arguments.
+**
+** Returns:
+** doesn't.
+*/
+
+void
+#if SM_VA_STD
+sm_abort(char *fmt, ...)
+#else /* SM_VA_STD */
+sm_abort(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ char msg[128];
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, fmt);
+ sm_vsnprintf(msg, sizeof msg, fmt, ap);
+ SM_VA_END(ap);
+ sm_abort_at(NULL, 0, msg);
+}
+
+/*
+** SM_ABORT_AT -- Initiate abnormal program termination.
+**
+** This is the low level function that is called to initiate abnormal
+** program termination. It prints an error message and terminates the
+** program. It is called by sm_abort and by the assertion macros.
+** If filename != NULL then filename and lineno specify the line of source
+** code at which the bug was detected.
+**
+** Parameters:
+** filename -- filename (can be NULL).
+** lineno -- line number.
+** msg -- message.
+**
+** Returns:
+** doesn't.
+*/
+
+void
+sm_abort_at(filename, lineno, msg)
+ const char *filename;
+ int lineno;
+ const char *msg;
+{
+ SM_TRY
+ (*SmAbortHandler)(filename, lineno, msg);
+ SM_EXCEPT(exc, "*")
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "exception raised by abort handler:\n");
+ sm_exc_print(exc, smioerr);
+ sm_io_flush(smioerr, SM_TIME_DEFAULT);
+ SM_END_TRY
+
+ /*
+ ** SmAbortHandler isn't supposed to return.
+ ** Since it has, let's make sure that the program is terminated.
+ */
+
+ abort();
+}
diff --git a/contrib/sendmail/libsm/assert.html b/contrib/sendmail/libsm/assert.html
new file mode 100644
index 0000000..a325199
--- /dev/null
+++ b/contrib/sendmail/libsm/assert.html
@@ -0,0 +1,359 @@
+<html>
+<head>
+ <title> libsm : Assert and Abort </title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Assert and Abort </h1>
+ <br> $Id: assert.html,v 1.6 2001/08/27 21:47:03 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+This package contains abstractions
+for assertion checking and abnormal program termination.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/assert.h&gt;
+
+/*
+** abnormal program termination
+*/
+
+void sm_abort_at(char *filename, int lineno, char *msg);
+typedef void (*SM_ABORT_HANDLER)(char *filename, int lineno, char *msg);
+void sm_abort_sethandler(SM_ABORT_HANDLER);
+void sm_abort(char *fmt, ...)
+
+/*
+** assertion checking
+*/
+
+SM_REQUIRE(expression)
+SM_ASSERT(expression)
+SM_ENSURE(expression)
+
+extern SM_DEBUG_T SmExpensiveRequire;
+extern SM_DEBUG_T SmExpensiveAssert;
+extern SM_DEBUG_T SmExpensiveEnsure;
+
+#if SM_CHECK_REQUIRE
+#if SM_CHECK_ASSERT
+#if SM_CHECK_ENSURE
+
+cc -DSM_CHECK_ALL=0 -DSM_CHECK_REQUIRE=1 ...
+</pre>
+
+<h2> Abnormal Program Termination </h2>
+
+The functions sm_abort and sm_abort_at are used to report a logic
+bug and terminate the program. They can be invoked directly,
+and they are also used by the assertion checking macros.
+
+<dl>
+<dt>
+ void sm_abort_at(char *filename, int lineno, char *msg)
+<dd>
+ This is the low level interface for causing abnormal program
+ termination. It is intended to be invoked from a
+ macro, such as the assertion checking macros.
+
+ If filename != NULL then filename and lineno specify the line
+ of source code on which the logic bug is detected. These
+ arguments are normally either set to __FILE__ and __LINE__
+ from an assertion checking macro, or they are set to NULL and 0.
+
+ The default action is to print an error message to smioerr
+ using the arguments, and then call abort(). This default
+ behaviour can be changed by calling sm_abort_sethandler.
+<p>
+<dt>
+ void sm_abort_sethandler(SM_ABORT_HANDLER handler)
+<dd>
+ Install 'handler' as the callback function that is invoked
+ by sm_abort_at. This callback function is passed the same
+ arguments as sm_abort_at, and is expected to log an error
+ message and terminate the program. The callback function should
+ not raise an exception or perform cleanup: see Rationale.
+
+ sm_abort_sethandler is intended to be called once, from main(),
+ before any additional threads are created: see Rationale.
+ You should not use sm_abort_sethandler to
+ switch back and forth between several handlers;
+ this is particularly dangerous when there are
+ multiple threads, or when you are in a library routine.
+<p>
+<dt>
+ void sm_abort(char *fmt, ...)
+<dd>
+ This is the high level interface for causing abnormal program
+ termination. It takes printf arguments. There is no need to
+ include a trailing newline in the format string; a trailing newline
+ will be printed if appropriate by the handler function.
+</dl>
+
+<h2> Assertions </h2>
+
+ The assertion handling package
+ supports a style of programming in which assertions are used
+ liberally throughout the code, both as a form of documentation,
+ and as a way of detecting bugs in the code by performing runtime checks.
+<p>
+ There are three kinds of assertion:
+<dl>
+<dt>
+ SM_REQUIRE(expr)
+<dd>
+ This is an assertion used at the beginning of a function
+ to check that the preconditions for calling the function
+ have been satisfied by the caller.
+<p>
+<dt>
+ SM_ENSURE(expr)
+<dd>
+ This is an assertion used just before returning from a function
+ to check that the function has satisfied all of the postconditions
+ that it is required to satisfy by its contract with the caller.
+<p>
+<dt>
+ SM_ASSERT(expr)
+<dd>
+ This is an assertion that is used in the middle of a function,
+ to check loop invariants, and for any other kind of check that is
+ not a "require" or "ensure" check.
+</dl>
+ If any of the above assertion macros fail, then sm_abort_at
+ is called. By default, a message is printed to stderr and the
+ program is aborted. For example, if SM_REQUIRE(arg &gt; 0) fails
+ because arg &lt;= 0, then the message
+<blockquote><pre>
+foo.c:47: SM_REQUIRE(arg &gt; 0) failed
+</pre></blockquote>
+ is printed to stderr, and abort() is called.
+ You can change this default behaviour using sm_abort_sethandler.
+
+<h2> How To Disable Assertion Checking At Compile Time </h2>
+
+ You can use compile time macros to selectively enable or disable
+ each of the three kinds of assertions, for performance reasons.
+ For example, you might want to enable SM_REQUIRE checking
+ (because it finds the most bugs), but disable the other two types.
+<p>
+ By default, all three types of assertion are enabled.
+ You can selectively disable individual assertion types
+ by setting one or more of the following cpp macros to 0
+ before &lt;sm/assert.h&gt; is included for the first time:
+<blockquote>
+ SM_CHECK_REQUIRE<br>
+ SM_CHECK_ENSURE<br>
+ SM_CHECK_ASSERT<br>
+</blockquote>
+ Or, you can define SM_CHECK_ALL as 0 to disable all assertion
+ types, then selectively define one or more of SM_CHECK_REQUIRE,
+ SM_CHECK_ENSURE or SM_CHECK_ASSERT as 1. For example,
+ to disable all assertions except for SM_REQUIRE, you can use
+ these C compiler flags:
+<blockquote>
+ -DSM_CHECK_ALL=0 -DSM_CHECK_REQUIRE=1
+</blockquote>
+
+ After &lt;sm/assert.h&gt; is included, the macros
+ SM_CHECK_REQUIRE, SM_CHECK_ENSURE and SM_CHECK_ASSERT
+ are each set to either 0 or 1.
+
+<h2> How To Write Complex or Expensive Assertions </h2>
+
+ Sometimes an assertion check requires more code than a simple
+ boolean expression.
+ For example, it might require an entire statement block
+ with its own local variables.
+ You can code such assertion checks by making them conditional on
+ SM_CHECK_REQUIRE, SM_CHECK_ENSURE or SM_CHECK_ASSERT,
+ and using sm_abort to signal failure.
+<p>
+ Sometimes an assertion check is significantly more expensive
+ than one or two comparisons.
+ In such cases, it is not uncommon for developers to comment out
+ the assertion once the code is unit tested.
+ Please don't do this: it makes it hard to turn the assertion
+ check back on for the purposes of regression testing.
+ What you should do instead is make the assertion check conditional
+ on one of these predefined debug objects:
+<blockquote>
+ SmExpensiveRequire<br>
+ SmExpensiveAssert<br>
+ SmExpensiveEnsure
+</blockquote>
+ By doing this, you bring the cost of the assertion checking code
+ back down to a single comparison, unless expensive assertion checking
+ has been explicitly enabled.
+ By the way, the corresponding debug category names are
+<blockquote>
+ sm_check_require<br>
+ sm_check_assert<br>
+ sm_check_ensure
+</blockquote>
+ What activation level should you check for?
+ Higher levels correspond to more expensive assertion checks.
+ Here are some basic guidelines:
+<blockquote>
+ level 1: &lt; 10 basic C operations<br>
+ level 2: &lt; 100 basic C operations<br>
+ level 3: &lt; 1000 basic C operations<br>
+ ...
+</blockquote>
+
+<p>
+ Here's a contrived example of both techniques:
+<blockquote><pre>
+void
+w_munge(WIDGET *w)
+{
+ SM_REQUIRE(w != NULL);
+#if SM_CHECK_REQUIRE
+ /*
+ ** We run this check at level 3 because we expect to check a few hundred
+ ** table entries.
+ */
+
+ if (sm_debug_active(&SmExpensiveRequire, 3))
+ {
+ int i;
+
+ for (i = 0; i &lt; WIDGET_MAX; ++i)
+ {
+ if (w[i] == NULL)
+ sm_abort("w_munge: NULL entry %d in widget table", i);
+ }
+ }
+#endif /* SM_CHECK_REQUIRE */
+</pre></blockquote>
+
+<h2> Other Guidelines </h2>
+
+ You should resist the urge to write SM_ASSERT(0) when the code has
+ reached an impossible place. It's better to call sm_abort, because
+ then you can generate a better error message. For example,
+<blockquote><pre>
+switch (foo)
+{
+ ...
+ default:
+ sm_abort("impossible value %d for foo", foo);
+}
+</pre></blockquote>
+ Note that I did not bother to guard the default clause of the switch
+ statement with #if SM_CHECK_ASSERT ... #endif, because there is
+ probably no performance gain to be had by disabling this particular check.
+<p>
+ Avoid including code that has side effects inside of assert macros,
+ or inside of SM_CHECK_* guards. You don't want the program to stop
+ working if assertion checking is disabled.
+
+<h2> Rationale for Logic Bug Handling </h2>
+
+ When a logic bug is detected, our philosophy is to log an error message
+ and terminate the program, dumping core if possible.
+ It is not a good idea to raise an exception, attempt cleanup,
+ or continue program execution. Here's why.
+<p>
+ First of all, to facilitate post-mortem analysis, we want to dump core
+ on detecting a logic bug, disturbing the process image as little as
+ possible before dumping core. We don't want to raise an exception
+ and unwind the stack, executing cleanup code, before dumping core,
+ because that would obliterate information we need to analyze the cause
+ of the abort.
+<p>
+ Second, it is a bad idea to raise an exception on an assertion failure
+ because this places unacceptable restrictions on code that uses
+ the assertion macros.
+ The reason is this: the sendmail code must be written so that
+ anywhere it is possible for an assertion to be raised, the code
+ will catch the exception and clean up if necessary, restoring
+ data structure invariants and freeing resources as required.
+ If an assertion failure was signalled by raising an exception,
+ then every time you added an assertion, you would need to check
+ both the function containing the assertion and its callers to see
+ if any exception handling code needed to be added to clean up properly
+ on assertion failure. That is far too great a burden.
+<p>
+ It is a bad idea to attempt cleanup upon detecting a logic bug
+ for several reasons:
+<ul>
+<li>If you need to perform cleanup actions in order to preserve the
+ integrity of the data that the program is handling, then the
+ program is not fault tolerant, and needs to be redesigned.
+ There are several reasons why a program might be terminated unexpectedly:
+ the system might crash, the program might receive a signal 9,
+ the program might be terminated by a memory fault (possibly as a
+ side effect of earlier data structure corruption), and the program
+ might detect a logic bug and terminate itself. Note that executing
+ cleanup actions is not feasible in most of the above cases.
+ If the program has a fault tolerant design, then it will not lose
+ data even if the system crashes in the middle of an operation.
+<p>
+<li>If the cause of the logic bug is earlier data structure corruption,
+ then cleanup actions intended to preserve the integrity of the data
+ that the program is handling might cause more harm than good: they
+ might cause information to be corrupted or lost.
+<p>
+<li>If the program uses threads, then cleanup is much more problematic.
+ Suppose that thread A is holding some locks, and is in the middle of
+ modifying a shared data structure. The locks are needed because the
+ data structure is currently in an inconsistent state. At this point,
+ a logic bug is detected deep in a library routine called by A.
+ How do we get all of the running threads to stop what they are doing
+ and perform their thread-specific cleanup actions before terminating?
+ We may not be able to get B to clean up and terminate cleanly until
+ A has restored the invariants on the data structure it is modifying
+ and releases its locks. So, we raise an exception and unwind the stack,
+ restoring data structure invariants and releasing locks at each level
+ of abstraction, and performing an orderly shutdown. There are certainly
+ many classes of error conditions for which using the exception mechanism
+ to perform an orderly shutdown is appropriate and feasible, but there
+ are also classes of error conditions for which exception handling and
+ orderly shutdown is dangerous or impossible. The abnormal program
+ termination system is intended for this second class of error conditions.
+ If you want to trigger orderly shutdown, don't call sm_abort:
+ raise an exception instead.
+</ul>
+<p>
+ Here is a strategy for making sendmail fault tolerant.
+ Sendmail is structured as a collection of processes. The "root" process
+ does as little as possible, except spawn children to do all of the real
+ work, monitor the children, and act as traffic cop.
+ We use exceptions to signal expected but infrequent error conditions,
+ so that the process encountering the exceptional condition can clean up
+ and keep going. (Worker processes are intended to be long lived, in
+ order to minimize forking and increase performance.) But when a bug
+ is detected in a sendmail worker process, the worker process does minimal
+ or no cleanup and then dies. A bug might be detected in several ways:
+ the process might dereference a NULL pointer, receive a signal 11,
+ core dump and die, or an assertion might fail, in which case the process
+ commits suicide. Either way, the root process detects the death of the
+ worker, logs the event, and spawns another worker.
+
+<h2> Rationale for Naming Conventions </h2>
+
+ The names "require" and "ensure" come from the writings of Bertrand Meyer,
+ a prominent evangelist for assertion checking who has written a number of
+ papers about the "Design By Contract" programming methodology,
+ and who created the Eiffel programming language.
+ Many other assertion checking packages for C also have "require" and
+ "ensure" assertion types. In short, we are conforming to a de-facto
+ standard.
+<p>
+ We use the names <tt>SM_REQUIRE</tt>, <tt>SM_ASSERT</tt>
+ and <tt>SM_ENSURE</tt> in preference to to <tt>REQUIRE</tt>,
+ <tt>ASSERT</tt> and <tt>ENSURE</tt> because at least two other
+ open source libraries (libisc and libnana) define <tt>REQUIRE</tt>
+ and <tt>ENSURE</tt> macros, and many libraries define <tt>ASSERT</tt>.
+ We want to avoid name conflicts with other libraries.
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/b-strcmp.c b/contrib/sendmail/libsm/b-strcmp.c
new file mode 100644
index 0000000..a713bc6
--- /dev/null
+++ b/contrib/sendmail/libsm/b-strcmp.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: b-strcmp.c,v 1.12 2001/09/11 04:04:47 gshapiro Exp $")
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sm/string.h>
+
+#define toseconds(x, y) (x.tv_sec - y.tv_sec)
+#define SIZE 512
+#define LOOPS 4000000L /* initial number of loops */
+#define MAXTIME 30L /* "maximum" time to run single test */
+
+void
+fatal(str)
+ char *str;
+{
+ perror(str);
+ exit(1);
+}
+
+void
+purpose()
+{
+ printf("This program benchmarks the performance differences between\n");
+ printf("strcasecmp() and sm_strcasecmp().\n");
+ printf("These tests may take several minutes to complete.\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ long a;
+ int k;
+ bool doit = false;
+ long loops;
+ long j;
+ long one, two;
+ struct timeval t1, t2;
+ char src1[SIZE], src2[SIZE];
+
+# define OPTIONS "d"
+ while ((k = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) k)
+ {
+ case 'd':
+ doit = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!doit)
+ {
+ purpose();
+ printf("If you want to run it, specify -d as option.\n");
+ return 0;
+ }
+
+ /* Run-time comments to the user */
+ purpose();
+ printf("\n");
+ for (k = 0; k < 3; k++)
+ {
+ switch (k)
+ {
+ case 0:
+ (void) sm_strlcpy(src1, "1234567890", SIZE);
+ (void) sm_strlcpy(src2, "1234567890", SIZE);
+ break;
+ case 1:
+ (void) sm_strlcpy(src1, "1234567890", SIZE);
+ (void) sm_strlcpy(src2, "1234567891", SIZE);
+ break;
+ case 2:
+ (void) sm_strlcpy(src1, "1234567892", SIZE);
+ (void) sm_strlcpy(src2, "1234567891", SIZE);
+ break;
+ }
+ printf("Test %d: strcasecmp(%s, %s) versus sm_strcasecmp()\n",
+ k, src1, src2);
+ loops = LOOPS;
+ for (;;)
+ {
+ j = 0;
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+ for (a = 0; a < loops; a++)
+ j += strcasecmp(src1, src2);
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+ one = toseconds(t2, t1);
+ printf("\tstrcasecmp() result: %ld seconds [%ld]\n",
+ one, j);
+
+ j = 0;
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+ for (a = 0; a < loops; a++)
+ j += sm_strcasecmp(src1, src2);
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+ two = toseconds(t2, t1);
+ printf("\tsm_strcasecmp() result: %ld seconds [%ld]\n",
+ two, j);
+
+ if (abs(one - two) > 2)
+ break;
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ break;
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ }
+ }
+ }
+
+ printf("\n\n");
+ printf("Interpreting the results:\n");
+ printf("\tFor differences larger than 2 seconds, the lower value is\n");
+ printf("\tbetter and that function should be used for performance\n");
+ printf("\treasons.\n\n");
+ printf("This program will re-run the tests when the difference is\n");
+ printf("less than 2 seconds.\n");
+ printf("The result will vary depending on the compiler optimization\n"); printf("level used. Compiling the sendmail libsm library with a\n");
+ printf("better optimization level can change the results.\n");
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/b-strl.c b/contrib/sendmail/libsm/b-strl.c
new file mode 100644
index 0000000..a696154
--- /dev/null
+++ b/contrib/sendmail/libsm/b-strl.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
+** Compile this program using a command line similar to:
+** cc -O -L../OBJ/libsm -o b-strl b-strl.c -lsm
+** where "OBJ" is the name of the object directory for the platform
+** you are compiling on.
+** Then run the program:
+** ./b-strl
+** and read the output for results and how to interpret the results.
+*/
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: b-strl.c,v 1.24 2001/09/11 04:04:47 gshapiro Exp $")
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sm/string.h>
+
+#define SRC_SIZE 512
+#define toseconds(x, y) (x.tv_sec - y.tv_sec)
+#define LOOPS 4000000L /* initial number of loops */
+#define MAXTIME 30L /* "maximum" time to run single test */
+
+void
+fatal(str)
+ char *str;
+{
+ perror(str);
+ exit(1);
+}
+
+void
+purpose()
+{
+ printf("This program benchmarks the performance differences between\n");
+ printf("strlcpy() and sm_strlcpy(), and strlcat() and sm_strlcat().\n");
+ printf("These tests may take several minutes to complete.\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#if !SM_CONF_STRL
+ printf("The configuration indicates the system needs the libsm\n");
+ printf("versions of strlcpy(3) and strlcat(3). Thus, performing\n");
+ printf("these tests will not be of much use.\n");
+ printf("If your OS has strlcpy(3) and strlcat(3) then set the macro\n");
+ printf("SM_CONF_STRL to 1 in your site.config.m4 file\n");
+ printf("(located in ../devtools/Site) and recompile this program.\n");
+#else /* !SM_CONF_STRL */
+ int ch;
+ long a;
+ bool doit = false;
+ long loops = LOOPS;
+ long one, two;
+ struct timeval t1, t2;
+ char dest[SRC_SIZE], source[SRC_SIZE];
+
+# define OPTIONS "d"
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) ch)
+ {
+ case 'd':
+ doit = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!doit)
+ {
+ purpose();
+ printf("If you want to run it, specify -d as option.\n");
+ return 0;
+ }
+
+ /*
+ ** Let's place a small string at the head of dest for
+ ** catenation to happen (it'll be ignored for the copy).
+ */
+ (void) sm_strlcpy(dest, "a small string at the start! ", SRC_SIZE - 1);
+
+ /*
+ ** Let's place a larger string into source for the catenation and
+ ** the copy.
+ */
+ (void) strlcpy(source,
+ " This is the longer string that will be used for catenation and copying for the the performace testing. The longer the string being catenated or copied the greater the difference in measureable performance\n",
+ SRC_SIZE - 1);
+
+ /* Run-time comments to the user */
+ purpose();
+ printf("\n");
+ printf("Test 1: strlcat() versus sm_strlcat()\n");
+
+redo_cat:
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ strlcat(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tstrlcat() result: %ld seconds\n", one = toseconds(t2, t1));
+
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ sm_strlcat(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tsm_strlcat() result: %ld seconds\n", two = toseconds(t2, t1));
+
+ if (one - two >= -2 && one - two <= 2)
+ {
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ goto redo_cat;
+ }
+ }
+
+ printf("\n");
+ printf("Test 2: strlcpy() versus sm_strlpy()\n");
+ loops = LOOPS;
+redo_cpy:
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ strlcpy(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tstrlcpy() result: %ld seconds\n", one = toseconds(t2, t1));
+
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ sm_strlcpy(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tsm_strlcpy() result: %ld seconds\n", two = toseconds(t2, t1));
+
+ if (one - two >= -2 && one - two <= 2)
+ {
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ goto redo_cpy;
+ }
+ }
+
+ printf("\n\n");
+ printf("Interpreting the results:\n");
+ printf("\tFor differences larger than 2 seconds, the lower value is\n");
+ printf("\tbetter and that function should be used for performance\n");
+ printf("\treasons.\n\n");
+ printf("This program will re-run the tests when the difference is\n");
+ printf("less than 2 seconds.\n");
+ printf("The result will vary depending on the compiler optimization\n"); printf("level used. Compiling the sendmail libsm library with a\n");
+ printf("better optimization level can change the results.\n");
+#endif /* !SM_CONF_STRL */
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/cdefs.html b/contrib/sendmail/libsm/cdefs.html
new file mode 100644
index 0000000..33e45ac
--- /dev/null
+++ b/contrib/sendmail/libsm/cdefs.html
@@ -0,0 +1,107 @@
+<html>
+<head>
+ <title>libsm : C Language Portability Macros</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : C Language Portability Macros </h1>
+ <br> $Id: cdefs.html,v 1.2 2000/12/07 17:33:09 dmoen Exp $
+</center>
+
+<h2> Description </h2>
+
+The header file <tt>&lt;sm/cdefs.h&gt;</tt>
+defines portable interfaces to non-portable features
+of various C compilers.
+It also assists you in writing C header files that are compatible
+with C++.
+
+<dl>
+<dt>
+<tt> __P(parameterlist) </tt>
+<dd>
+ This macro is used to write portable function prototypes.
+ For example,
+
+<blockquote><pre>
+int foo __P((int));
+</pre></blockquote>
+
+<dt>
+<tt> __CONCAT(x,y) </tt>
+<dd>
+ This macro concatenates two tokens x and y,
+ forming a single token xy.
+ Warning: make sure there is no white space around the arguments x and y.
+ <p>
+
+<dt>
+<tt> __STRING(x) </tt>
+<dd>
+ This macro converts the token sequence x into a string literal.
+ <p>
+
+<dt>
+<tt> __BEGIN_DECLS, __END_DECLS </tt>
+<dd>
+ These macros are used to write C header files that are compatible
+ with C++ compilers.
+ Put <tt>__BEGIN_DECLS</tt> before the first function or variable
+ declaration in your header file,
+ and put <tt>__END_DECLS</tt> after the last function or variable
+ declaration.
+ <p>
+
+<dt>
+<tt> const, signed, volatile </tt>
+<dd>
+ For pre-ANSI C compilers, <tt>const</tt>, <tt>signed</tt>
+ and <tt>volatile</tt> are defined as empty macros.
+ This means you can use these keywords without introducing
+ portability problems.
+ <p>
+
+<dt>
+<tt> SM_DEAD(function_declaration) </tt>
+<dd>
+ This macro modifies a prototype of a function
+ that does not return to its caller.
+ With some versions of gcc, this will result in slightly better code,
+ and can suppress some useless warnings produced by gcc -Wall.
+ For example,
+
+<blockquote><pre>
+SM_DEAD(void exit __P((int)));
+</pre></blockquote>
+
+<dt>
+<tt> SM_UNUSED(variable_declaration) </tt>
+<dd>
+ This macro modifies a definition of an unused
+ local variable, global variable or function parameter
+ in order to suppress compiler warnings.
+ Examples:
+
+<blockquote><pre>
+SM_UNUSED(static const char Id[]) = "@(#)$Id: cdefs.html,v 1.2 2000/12/07 17:33:09 dmoen Exp $";
+void
+foo(x)
+ SM_UNUSED(int x);
+{
+ SM_UNUSED(int y) = 0;
+ return 0;
+}
+void
+bar(SM_UNUSED(int x))
+{
+ return 0;
+}
+</pre></blockquote>
+
+</dl>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/cf.c b/contrib/sendmail/libsm/cf.c
new file mode 100644
index 0000000..d217875
--- /dev/null
+++ b/contrib/sendmail/libsm/cf.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: cf.c,v 1.6 2001/09/11 04:04:47 gshapiro Exp $")
+
+#include <ctype.h>
+#include <errno.h>
+
+#include <sm/cf.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/heap.h>
+
+/*
+** SM_CF_GETOPT -- look up option values in the sendmail.cf file
+**
+** Open the sendmail.cf file and parse all of the 'O' directives.
+** Each time one of the options named in the option vector optv
+** is found, store a malloced copy of the option value in optv.
+**
+** Parameters:
+** path -- pathname of sendmail.cf file
+** optc -- size of option vector
+** optv -- pointer to option vector
+**
+** Results:
+** 0 on success, or an errno value on failure.
+** An exception is raised on malloc failure.
+*/
+
+int
+sm_cf_getopt(path, optc, optv)
+ char *path;
+ int optc;
+ SM_CF_OPT_T *optv;
+{
+ SM_FILE_T *cfp;
+ char buf[2048];
+ char *p;
+ char *id;
+ char *idend;
+ char *val;
+ int i;
+
+ cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, path, SM_IO_RDONLY, NULL);
+ if (cfp == NULL)
+ return errno;
+
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
+ {
+ p = strchr(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ if (buf[0] != 'O' || buf[1] != ' ')
+ continue;
+
+ id = &buf[2];
+ val = strchr(id, '=');
+ if (val == NULL)
+ val = idend = id + strlen(id);
+ else
+ {
+ idend = val;
+ ++val;
+ while (*val == ' ')
+ ++val;
+ while (idend > id && idend[-1] == ' ')
+ --idend;
+ *idend = '\0';
+ }
+
+ for (i = 0; i < optc; ++i)
+ {
+ if (sm_strcasecmp(optv[i].opt_name, id) == 0)
+ {
+ optv[i].opt_val = sm_strdup_x(val);
+ break;
+ }
+ }
+ }
+ if (sm_io_error(cfp))
+ {
+ int save_errno = errno;
+
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+ errno = save_errno;
+ return errno;
+ }
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/clock.c b/contrib/sendmail/libsm/clock.c
new file mode 100644
index 0000000..eed1ded
--- /dev/null
+++ b/contrib/sendmail/libsm/clock.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: clock.c,v 1.34 2001/11/05 18:33:20 ca Exp $")
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+#include <sm/heap.h>
+#include <sm/debug.h>
+#include <sm/bitops.h>
+#include <sm/clock.h>
+#include "local.h"
+
+#ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+#endif /* ! sigmask */
+
+static void sm_endsleep __P((void));
+
+
+/*
+** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
+**
+** Events are stored in a sorted list for fast processing.
+** An event only applies to the process that set it.
+** Source is #ifdef'd to work with older OS's that don't have setitimer()
+** (that is, don't have a timer granularity less than 1 second).
+**
+** Parameters:
+** intvl -- interval until next event occurs (milliseconds).
+** func -- function to call on event.
+** arg -- argument to func on event.
+**
+** Returns:
+** On success returns the SM_EVENT entry created.
+** On failure returns NULL.
+**
+** Side Effects:
+** none.
+*/
+
+static SM_EVENT *volatile SmEventQueue; /* head of event queue */
+static SM_EVENT *volatile SmFreeEventList; /* list of free events */
+
+SM_EVENT *
+sm_seteventm(intvl, func, arg)
+ int intvl;
+ void (*func)();
+ int arg;
+{
+ ENTER_CRITICAL();
+ if (SmFreeEventList == NULL)
+ {
+ SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
+ SmFreeEventList->ev_link = NULL;
+ }
+ LEAVE_CRITICAL();
+
+ return sm_sigsafe_seteventm(intvl, func, arg);
+}
+
+/*
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+SM_EVENT *
+sm_sigsafe_seteventm(intvl, func, arg)
+ int intvl;
+ void (*func)();
+ int arg;
+{
+ register SM_EVENT **evp;
+ register SM_EVENT *ev;
+#if SM_CONF_SETITIMER
+ auto struct timeval now, nowi, ival;
+ auto struct itimerval itime;
+#else /* SM_CONF_SETITIMER */
+ auto time_t now, nowi;
+#endif /* SM_CONF_SETITIMER */
+ int wasblocked;
+
+ /* negative times are not allowed */
+ if (intvl <= 0)
+ return NULL;
+
+ wasblocked = sm_blocksignal(SIGALRM);
+#if SM_CONF_SETITIMER
+ ival.tv_sec = intvl / 1000;
+ ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
+ (void) gettimeofday(&now, NULL);
+ nowi = now;
+ timeradd(&now, &ival, &nowi);
+#else /* SM_CONF_SETITIMER */
+ now = time(NULL);
+ nowi = now + (time_t)(intvl / 1000);
+#endif /* SM_CONF_SETITIMER */
+
+ /* search event queue for correct position */
+ for (evp = (SM_EVENT **) (&SmEventQueue);
+ (ev = *evp) != NULL;
+ evp = &ev->ev_link)
+ {
+#if SM_CONF_SETITIMER
+ if (timercmp(&(ev->ev_time), &nowi, >=))
+#else /* SM_CONF_SETITIMER */
+ if (ev->ev_time >= nowi)
+#endif /* SM_CONF_SETITIMER */
+ break;
+ }
+
+ ENTER_CRITICAL();
+ if (SmFreeEventList == NULL)
+ {
+ /*
+ ** This shouldn't happen. If called from sm_seteventm(),
+ ** we have just malloced a SmFreeEventList entry. If
+ ** called from a signal handler, it should have been
+ ** from an existing event which sm_tick() just added to
+ ** SmFreeEventList.
+ */
+
+ LEAVE_CRITICAL();
+ return NULL;
+ }
+ else
+ {
+ ev = SmFreeEventList;
+ SmFreeEventList = ev->ev_link;
+ }
+ LEAVE_CRITICAL();
+
+ /* insert new event */
+ ev->ev_time = nowi;
+ ev->ev_func = func;
+ ev->ev_arg = arg;
+ ev->ev_pid = getpid();
+ ENTER_CRITICAL();
+ ev->ev_link = *evp;
+ *evp = ev;
+ LEAVE_CRITICAL();
+
+ (void) sm_signal(SIGALRM, sm_tick);
+# if SM_CONF_SETITIMER
+ timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
+ itime.it_interval.tv_sec = 0;
+ itime.it_interval.tv_usec = 0;
+ if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
+ itime.it_value.tv_usec = 1000;
+ (void) setitimer(ITIMER_REAL, &itime, NULL);
+# else /* SM_CONF_SETITIMER */
+ intvl = SmEventQueue->ev_time - now;
+ (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
+# endif /* SM_CONF_SETITIMER */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+ return ev;
+}
+/*
+** SM_CLREVENT -- remove an event from the event queue.
+**
+** Parameters:
+** ev -- pointer to event to remove.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** arranges for event ev to not happen.
+*/
+
+void
+sm_clrevent(ev)
+ register SM_EVENT *ev;
+{
+ register SM_EVENT **evp;
+ int wasblocked;
+# if SM_CONF_SETITIMER
+ struct itimerval clr;
+# endif /* SM_CONF_SETITIMER */
+
+ if (ev == NULL)
+ return;
+
+ /* find the parent event */
+ wasblocked = sm_blocksignal(SIGALRM);
+ for (evp = (SM_EVENT **) (&SmEventQueue);
+ *evp != NULL;
+ evp = &(*evp)->ev_link)
+ {
+ if (*evp == ev)
+ break;
+ }
+
+ /* now remove it */
+ if (*evp != NULL)
+ {
+ ENTER_CRITICAL();
+ *evp = ev->ev_link;
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = ev;
+ LEAVE_CRITICAL();
+ }
+
+ /* restore clocks and pick up anything spare */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+ if (SmEventQueue != NULL)
+ (void) kill(getpid(), SIGALRM);
+ else
+ {
+ /* nothing left in event queue, no need for an alarm */
+# if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+# else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+# endif /* SM_CONF_SETITIMER */
+ }
+}
+/*
+** SM_CLEAR_EVENTS -- remove all events from the event queue.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_clear_events()
+{
+ register SM_EVENT *ev;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+#endif /* SM_CONF_SETITIMER */
+ int wasblocked;
+
+ if (SmEventQueue == NULL)
+ return;
+
+ /* nothing will be left in event queue, no need for an alarm */
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+#endif /* SM_CONF_SETITIMER */
+ wasblocked = sm_blocksignal(SIGALRM);
+
+ /* find the end of the EventQueue */
+ for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
+ continue;
+
+ ENTER_CRITICAL();
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = SmEventQueue;
+ SmEventQueue = NULL;
+ LEAVE_CRITICAL();
+
+ /* restore clocks and pick up anything spare */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+}
+/*
+** SM_TICK -- take a clock tick
+**
+** Called by the alarm clock. This routine runs events as needed.
+** Always called as a signal handler, so we assume that SIGALRM
+** has been blocked.
+**
+** Parameters:
+** One that is ignored; for compatibility with signal handlers.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** calls the next function in EventQueue.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED */
+SIGFUNC_DECL
+sm_tick(sig)
+ int sig;
+{
+ register SM_EVENT *ev;
+ pid_t mypid;
+ int save_errno = errno;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+ struct timeval now;
+#else /* SM_CONF_SETITIMER */
+ register time_t now;
+#endif /* SM_CONF_SETITIMER */
+
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+
+ FIX_SYSV_SIGNAL(sig, sm_tick);
+ errno = save_errno;
+ CHECK_CRITICAL(sig);
+
+ mypid = getpid();
+ while (PendingSignal != 0)
+ {
+ int sigbit = 0;
+ int sig = 0;
+
+ if (bitset(PEND_SIGHUP, PendingSignal))
+ {
+ sigbit = PEND_SIGHUP;
+ sig = SIGHUP;
+ }
+ else if (bitset(PEND_SIGINT, PendingSignal))
+ {
+ sigbit = PEND_SIGINT;
+ sig = SIGINT;
+ }
+ else if (bitset(PEND_SIGTERM, PendingSignal))
+ {
+ sigbit = PEND_SIGTERM;
+ sig = SIGTERM;
+ }
+ else if (bitset(PEND_SIGUSR1, PendingSignal))
+ {
+ sigbit = PEND_SIGUSR1;
+ sig = SIGUSR1;
+ }
+ else
+ {
+ /* If we get here, we are in trouble */
+ abort();
+ }
+ PendingSignal &= ~sigbit;
+ kill(mypid, sig);
+ }
+
+#if SM_CONF_SETITIMER
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+ while ((ev = SmEventQueue) != NULL &&
+ (ev->ev_pid != mypid ||
+#if SM_CONF_SETITIMER
+ timercmp(&ev->ev_time, &now, <=)
+#else /* SM_CONF_SETITIMER */
+ ev->ev_time <= now
+#endif /* SM_CONF_SETITIMER */
+ ))
+ {
+ void (*f)();
+ int arg;
+ pid_t pid;
+
+ /* process the event on the top of the queue */
+ ev = SmEventQueue;
+ SmEventQueue = SmEventQueue->ev_link;
+
+ /* we must be careful in here because ev_func may not return */
+ f = ev->ev_func;
+ arg = ev->ev_arg;
+ pid = ev->ev_pid;
+ ENTER_CRITICAL();
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = ev;
+ LEAVE_CRITICAL();
+ if (pid != getpid())
+ continue;
+ if (SmEventQueue != NULL)
+ {
+#if SM_CONF_SETITIMER
+ if (timercmp(&SmEventQueue->ev_time, &now, >))
+ {
+ timersub(&SmEventQueue->ev_time, &now,
+ &clr.it_value);
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ }
+ else
+ {
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 3;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ }
+#else /* SM_CONF_SETITIMER */
+ if (SmEventQueue->ev_time > now)
+ (void) alarm((unsigned) (SmEventQueue->ev_time
+ - now));
+ else
+ (void) alarm(3);
+#endif /* SM_CONF_SETITIMER */
+ }
+
+ /* call ev_func */
+ errno = save_errno;
+ (*f)(arg);
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+ }
+ if (SmEventQueue != NULL)
+ {
+#if SM_CONF_SETITIMER
+ timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm((unsigned) (SmEventQueue->ev_time - now));
+#endif /* SM_CONF_SETITIMER */
+ }
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+/*
+** SLEEP -- a version of sleep that works with this stuff
+**
+** Because Unix sleep uses the alarm facility, I must reimplement
+** it here.
+**
+** Parameters:
+** intvl -- time to sleep.
+**
+** Returns:
+** zero.
+**
+** Side Effects:
+** waits for intvl time. However, other events can
+** be run during that interval.
+*/
+
+
+static bool volatile SmSleepDone;
+
+#ifndef SLEEP_T
+# define SLEEP_T unsigned int
+#endif /* ! SLEEP_T */
+
+SLEEP_T
+sleep(intvl)
+ unsigned int intvl;
+{
+ int was_held;
+
+ if (intvl == 0)
+ return (SLEEP_T) 0;
+ SmSleepDone = false;
+ (void) sm_setevent((time_t) intvl, sm_endsleep, 0);
+ was_held = sm_releasesignal(SIGALRM);
+ while (!SmSleepDone)
+ (void) pause();
+ if (was_held > 0)
+ (void) sm_blocksignal(SIGALRM);
+ return (SLEEP_T) 0;
+}
+
+static void
+sm_endsleep()
+{
+ /*
+ ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+ ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+ ** DOING.
+ */
+
+ SmSleepDone = true;
+}
+
diff --git a/contrib/sendmail/libsm/clrerr.c b/contrib/sendmail/libsm/clrerr.c
new file mode 100644
index 0000000..5b1a8a8
--- /dev/null
+++ b/contrib/sendmail/libsm/clrerr.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: clrerr.c,v 1.13 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_CLEARERR -- public function to clear a file pointer's error status
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Returns:
+** nothing.
+*/
+#undef sm_io_clearerr
+
+void
+sm_io_clearerr(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ sm_clearerr(fp);
+}
diff --git a/contrib/sendmail/libsm/config.c b/contrib/sendmail/libsm/config.c
new file mode 100644
index 0000000..064539d
--- /dev/null
+++ b/contrib/sendmail/libsm/config.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: config.c,v 1.26 2001/12/14 00:26:18 ca Exp $")
+
+#include <stdlib.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/conf.h>
+
+/*
+** PUTENV -- emulation of putenv() in terms of setenv()
+**
+** Not needed on Posix-compliant systems.
+** This doesn't have full Posix semantics, but it's good enough
+** for sendmail.
+**
+** Parameter:
+** env -- the environment to put.
+**
+** Returns:
+** 0 on success, < 0 on failure.
+*/
+
+#if NEEDPUTENV
+
+# if NEEDPUTENV == 2 /* no setenv(3) call available */
+
+int
+putenv(str)
+ char *str;
+{
+ char **current;
+ int matchlen, envlen = 0;
+ char *tmp;
+ char **newenv;
+ static bool first = true;
+ extern char **environ;
+
+ /*
+ ** find out how much of str to match when searching
+ ** for a string to replace.
+ */
+
+ if ((tmp = strchr(str, '=')) == NULL || tmp == str)
+ matchlen = strlen(str);
+ else
+ matchlen = (int) (tmp - str);
+ ++matchlen;
+
+ /*
+ ** Search for an existing string in the environment and find the
+ ** length of environ. If found, replace and exit.
+ */
+
+ for (current = environ; *current != NULL; current++)
+ {
+ ++envlen;
+
+ if (strncmp(str, *current, matchlen) == 0)
+ {
+ /* found it, now insert the new version */
+ *current = (char *) str;
+ return 0;
+ }
+ }
+
+ /*
+ ** There wasn't already a slot so add space for a new slot.
+ ** If this is our first time through, use malloc(), else realloc().
+ */
+
+ if (first)
+ {
+ newenv = (char **) sm_malloc(sizeof(char *) * (envlen + 2));
+ if (newenv == NULL)
+ return -1;
+
+ first = false;
+ (void) memcpy(newenv, environ, sizeof(char *) * envlen);
+ }
+ else
+ {
+ newenv = (char **) sm_realloc((char *) environ,
+ sizeof(char *) * (envlen + 2));
+ if (newenv == NULL)
+ return -1;
+ }
+
+ /* actually add in the new entry */
+ environ = newenv;
+ environ[envlen] = (char *) str;
+ environ[envlen + 1] = NULL;
+
+ return 0;
+}
+
+# else /* NEEDPUTENV == 2 */
+
+int
+putenv(env)
+ char *env;
+{
+ char *p;
+ int l;
+ char nbuf[100];
+
+ p = strchr(env, '=');
+ if (p == NULL)
+ return 0;
+ l = p - env;
+ if (l > sizeof nbuf - 1)
+ l = sizeof nbuf - 1;
+ memmove(nbuf, env, l);
+ nbuf[l] = '\0';
+ return setenv(nbuf, ++p, 1);
+}
+
+# endif /* NEEDPUTENV == 2 */
+#endif /* NEEDPUTENV */
+/*
+** UNSETENV -- remove a variable from the environment
+**
+** Not needed on newer systems.
+**
+** Parameters:
+** name -- the string name of the environment variable to be
+** deleted from the current environment.
+**
+** Returns:
+** none.
+**
+** Globals:
+** environ -- a pointer to the current environment.
+**
+** Side Effects:
+** Modifies environ.
+*/
+
+#if !HASUNSETENV
+
+void
+unsetenv(name)
+ char *name;
+{
+ extern char **environ;
+ register char **pp;
+ int len = strlen(name);
+
+ for (pp = environ; *pp != NULL; pp++)
+ {
+ if (strncmp(name, *pp, len) == 0 &&
+ ((*pp)[len] == '=' || (*pp)[len] == '\0'))
+ break;
+ }
+
+ for (; *pp != NULL; pp++)
+ *pp = pp[1];
+}
+
+#endif /* !HASUNSETENV */
+
+char *SmCompileOptions[] =
+{
+#if SM_CONF_BROKEN_STRTOD
+ "SM_CONF_BROKEN_STRTOD",
+#endif /* SM_CONF_BROKEN_STRTOD */
+#if SM_CONF_GETOPT
+ "SM_CONF_GETOPT",
+#endif /* SM_CONF_GETOPT */
+#if SM_CONF_LONGLONG
+ "SM_CONF_LONGLONG",
+#endif /* SM_CONF_LONGLONG */
+#if SM_CONF_MEMCHR
+ "SM_CONF_MEMCHR",
+#endif /* SM_CONF_MEMCHR */
+#if SM_CONF_MSG
+ "SM_CONF_MSG",
+#endif /* SM_CONF_MSG */
+#if SM_CONF_QUAD_T
+ "SM_CONF_QUAD_T",
+#endif /* SM_CONF_QUAD_T */
+#if SM_CONF_SEM
+ "SM_CONF_SEM",
+#endif /* SM_CONF_SEM */
+#if SM_CONF_SETITIMER
+ "SM_CONF_SETITIMER",
+#endif /* SM_CONF_SETITIMER */
+#if SM_CONF_SHM
+ "SM_CONF_SHM",
+#endif /* SM_CONF_SHM */
+#if SM_CONF_SHM_DELAY
+ "SM_CONF_SHM_DELAY",
+#endif /* SM_CONF_SHM_DELAY */
+#if SM_CONF_SSIZE_T
+ "SM_CONF_SSIZE_T",
+#endif /* SM_CONF_SSIZE_T */
+#if SM_CONF_STDBOOL_H
+ "SM_CONF_STDBOOL_H",
+#endif /* SM_CONF_STDBOOL_H */
+#if SM_CONF_STDDEF_H
+ "SM_CONF_STDDEF_H",
+#endif /* SM_CONF_STDDEF_H */
+
+#if 0
+/* XXX this is always enabled (for now) */
+#if SM_CONF_STRL
+ "SM_CONF_STRL",
+#endif /* SM_CONF_STRL */
+#endif /* 0 */
+
+#if SM_CONF_SYS_CDEFS_H
+ "SM_CONF_SYS_CDEFS_H",
+#endif /* SM_CONF_SYS_CDEFS_H */
+#if SM_CONF_SYSEXITS_H
+ "SM_CONF_SYSEXITS_H",
+#endif /* SM_CONF_SYSEXITS_H */
+#if SM_CONF_UID_GID
+ "SM_CONF_UID_GID",
+#endif /* SM_CONF_UID_GID */
+#if SM_HEAP_CHECK
+ "SM_HEAP_CHECK",
+#endif /* SM_HEAP_CHECK */
+#if defined(SM_OS_NAME) && defined(__STDC__)
+ "SM_OS=sm_os_" SM_OS_NAME,
+#endif /* defined(SM_OS_NAME) && defined(__STDC__) */
+#if SM_VA_STD
+ "SM_VA_STD",
+#endif /* SM_VA_STD */
+ NULL
+};
diff --git a/contrib/sendmail/libsm/debug.c b/contrib/sendmail/libsm/debug.c
new file mode 100644
index 0000000..37e5e82
--- /dev/null
+++ b/contrib/sendmail/libsm/debug.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: debug.c,v 1.28 2001/09/25 19:57:05 gshapiro Exp $")
+
+/*
+** libsm debugging and tracing
+** For documentation, see debug.html.
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include <sm/debug.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+#include <sm/heap.h>
+
+/*
+** Abstractions for printing trace messages.
+*/
+
+/*
+** The output file to which trace output is directed.
+** There is a controversy over whether this variable
+** should be process global or thread local.
+** To make the interface more abstract, we've hidden the
+** variable behind access functions.
+*/
+
+static SM_FILE_T *SmDebugOutput = smioout;
+
+/*
+** SM_DEBUG_FILE -- Returns current debug file pointer.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** current debug file pointer.
+*/
+
+SM_FILE_T *
+sm_debug_file()
+{
+ return SmDebugOutput;
+}
+
+/*
+** SM_DEBUG_SETFILE -- Sets debug file pointer.
+**
+** Parameters:
+** fp -- new debug file pointer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets SmDebugOutput.
+*/
+
+void
+sm_debug_setfile(fp)
+ SM_FILE_T *fp;
+{
+ SmDebugOutput = fp;
+}
+
+/*
+** SM_DPRINTF -- printf() for debug output.
+**
+** Parameters:
+** fmt -- format for printf()
+**
+** Returns:
+** none.
+*/
+
+void
+#if SM_VA_STD
+sm_dprintf(char *fmt, ...)
+#else /* SM_VA_STD */
+sm_dprintf(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ SM_VA_LOCAL_DECL
+
+ if (SmDebugOutput == NULL)
+ return;
+ SM_VA_START(ap, fmt);
+ sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
+ SM_VA_END(ap);
+}
+
+/*
+** SM_DFLUSH -- Flush debug output.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_dflush()
+{
+ sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
+}
+
+/*
+** This is the internal database of debug settings.
+** The semantics of looking up a setting in the settings database
+** are that the *last* setting specified in a -d option on the sendmail
+** command line that matches a given SM_DEBUG structure is the one that is
+** used. That is necessary to conform to the existing semantics of
+** the sendmail -d option. We store the settings as a linked list in
+** reverse order, so when we do a lookup, we take the *first* entry
+** that matches.
+*/
+
+typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
+struct sm_debug_setting
+{
+ const char *ds_pattern;
+ unsigned int ds_level;
+ SM_DEBUG_SETTING_T *ds_next;
+};
+SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
+
+/*
+** We keep a linked list of SM_DEBUG structures that have been initialized,
+** for use by sm_debug_reset.
+*/
+
+SM_DEBUG_T *SmDebugInitialized = NULL;
+
+const char SmDebugMagic[] = "sm_debug";
+
+/*
+** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
+**
+** Reset all SM_DEBUG structures back to the uninitialized state.
+** This is used by sm_debug_addsetting to ensure that references to
+** SM_DEBUG structures that occur before sendmail processes its -d flags
+** do not cause those structures to be permanently forced to level 0.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_debug_reset()
+{
+ SM_DEBUG_T *debug;
+
+ for (debug = SmDebugInitialized;
+ debug != NULL;
+ debug = debug->debug_next)
+ {
+ debug->debug_level = SM_DEBUG_UNKNOWN;
+ }
+ SmDebugInitialized = NULL;
+}
+
+/*
+** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
+**
+** Parameters:
+** pattern -- a shell-style glob pattern (see sm_match).
+** WARNING: the storage for 'pattern' will be owned by
+** the debug package, so it should either be a string
+** literal or the result of a call to sm_strdup_x.
+** level -- a non-negative integer.
+**
+** Returns:
+** none.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void
+sm_debug_addsetting_x(pattern, level)
+ const char *pattern;
+ int level;
+{
+ SM_DEBUG_SETTING_T *s;
+
+ SM_REQUIRE(pattern != NULL);
+ SM_REQUIRE(level >= 0);
+ s = sm_malloc_x(sizeof(SM_DEBUG_SETTING_T));
+ s->ds_pattern = pattern;
+ s->ds_level = (unsigned int) level;
+ s->ds_next = SmDebugSettings;
+ SmDebugSettings = s;
+ sm_debug_reset();
+}
+
+/*
+** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
+**
+** Parameters:
+** s -- Points to a non-empty \0 or , terminated string,
+** of which the initial character is not a digit.
+**
+** Returns:
+** pointer to terminating \0 or , character.
+**
+** Exceptions:
+** F:sm.heap -- out of memory.
+**
+** Side Effects:
+** adds the setting to the database.
+*/
+
+static const char *
+parse_named_setting_x(s)
+ register const char *s;
+{
+ const char *pat, *endpat;
+ int level;
+
+ pat = s;
+ while (*s != '\0' && *s != ',' && *s != '.')
+ ++s;
+ endpat = s;
+ if (*s == '.')
+ {
+ ++s;
+ level = 0;
+ while (isascii(*s) && isdigit(*s))
+ {
+ level = level * 10 + (*s - '0');
+ ++s;
+ }
+ if (level < 0)
+ level = 0;
+ }
+ else
+ level = 1;
+
+ sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
+
+ /* skip trailing junk */
+ while (*s != '\0' && *s != ',')
+ ++s;
+
+ return s;
+}
+
+/*
+** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
+**
+** Parameters:
+** s -- a list of debug settings, eg the argument to the
+** sendmail -d option.
+**
+** The syntax of the string s is as follows:
+**
+** <settings> ::= <setting> | <settings> "," <setting>
+** <setting> ::= <categories> | <categories> "." <level>
+** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
+**
+** However, note that we skip over anything we don't
+** understand, rather than report an error.
+**
+** Returns:
+** none.
+**
+** Exceptions:
+** F:sm.heap -- out of memory
+**
+** Side Effects:
+** updates the database of debug settings.
+*/
+
+void
+sm_debug_addsettings_x(s)
+ register const char *s;
+{
+ for (;;)
+ {
+ if (*s == '\0')
+ return;
+ if (*s == ',')
+ {
+ ++s;
+ continue;
+ }
+ s = parse_named_setting_x(s);
+ }
+}
+
+/*
+** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
+**
+** Parameters:
+** debug -- debug object.
+**
+** Returns:
+** Activation level of the specified debug object.
+**
+** Side Effects:
+** Ensures that the debug object is initialized.
+*/
+
+int
+sm_debug_loadlevel(debug)
+ SM_DEBUG_T *debug;
+{
+ if (debug->debug_level == SM_DEBUG_UNKNOWN)
+ {
+ SM_DEBUG_SETTING_T *s;
+
+ for (s = SmDebugSettings; s != NULL; s = s->ds_next)
+ {
+ if (sm_match(debug->debug_name, s->ds_pattern))
+ {
+ debug->debug_level = s->ds_level;
+ goto initialized;
+ }
+ }
+ debug->debug_level = 0;
+ initialized:
+ debug->debug_next = SmDebugInitialized;
+ SmDebugInitialized = debug;
+ }
+ return (int) debug->debug_level;
+}
+
+/*
+** SM_DEBUG_LOADACTIVE -- Activation level reached?
+**
+** Parameters:
+** debug -- debug object.
+** level -- level to check.
+**
+** Returns:
+** true iff the activation level of the specified debug
+** object >= level.
+**
+** Side Effects:
+** Ensures that the debug object is initialized.
+*/
+
+bool
+sm_debug_loadactive(debug, level)
+ SM_DEBUG_T *debug;
+ int level;
+{
+ return sm_debug_loadlevel(debug) >= level;
+}
diff --git a/contrib/sendmail/libsm/debug.html b/contrib/sendmail/libsm/debug.html
new file mode 100644
index 0000000..41fa124
--- /dev/null
+++ b/contrib/sendmail/libsm/debug.html
@@ -0,0 +1,276 @@
+<html>
+<head>
+ <title>libsm : Debugging and Tracing</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Debugging and Tracing </h1>
+ <br> $Id: debug.html,v 1.8 2000/12/08 21:41:41 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The debug and trace package provides abstractions for writing trace
+messages, and abstractions for enabling and disabling debug and
+trace code at run time.
+
+<p>
+Sendmail 8.11 and earlier has a <tt>-d</tt> option which
+lets you turn on debug and trace code.
+Debug categories are integers from 0 to 99, with the sole exception
+of "ANSI", which is a named debug category.
+
+<p>
+The libsm debug package supports named debug categories.
+Debug category names have the form of C identifiers.
+For example, <tt>sm_trace_heap</tt> controls the output of trace
+messages from the sm heap package, while <tt>sm_check_heap</tt>
+controls the argument validity checking and memory leak detection
+features of the sm heap package.
+
+<p>
+In sendmail 8.12, the <tt>-d</tt> flag is generalized
+to support both the original style numeric categories, for backwards
+compatibility, and the new style named categories implemented by libsm.
+With this change,
+"-dANSI" is implemented using a libsm named debug category.
+You will be able to set a collection of named debug categories to
+the same activation level by specifying a glob pattern.
+For example,
+<dl>
+<dt>
+ <tt> -dANSI </tt>
+<dd>
+ sets the named category "ANSI" to level 1,
+<dt>
+ <tt> -dfoo_*.3 </tt>
+<dd>
+ sets all named categories matching the glob pattern "foo_*" to level 3,
+<dt>
+ <tt> -d0-99.1 </tt>
+<dd>
+ sets the numeric categories 0 through 99 to level 1, and
+<dt>
+ <tt> -dANSI,foo_*.3,0-99.1 </tt>
+<dd>
+ does all of the above.
+</dl>
+
+<p>
+For sendmail 9.x, I propose to drop support for numeric debug categories,
+and just use named debug categories.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/debug.h&gt;
+
+/*
+** abstractions for printing trace messages
+*/
+void sm_dprintf(char *fmt, ...)
+void sm_dflush()
+void sm_debug_setfile(SM_FILE_T *)
+
+/*
+** abstractions for setting and testing debug activation levels
+*/
+void sm_debug_addsettings(char *settings)
+void sm_debug_addsetting(char *pattern, int level)
+
+typedef struct sm_debug SM_DEBUG_T;
+SM_DEBUG_T dbg = SM_DEBUG_INITIALIZER("name", "@(#)$Debug: name - description $");
+
+bool sm_debug_active(SM_DEBUG_T *debug, int level)
+int sm_debug_level(SM_DEBUG_T *debug)
+bool sm_debug_unknown(SM_DEBUG_T *debug)
+</pre>
+
+<h2> Naming Conventions </h2>
+
+All debug categories defined by libsm have names of the form <tt>sm_*</tt>.
+Debug categories that turn on trace output have names of the form
+<tt>*_trace_*</tt>.
+Debug categories that turn on run time checks have names of the form
+<tt>*_check_*</tt>.
+Here are all of the libsm debug categories as of March 2000:
+
+<table>
+ <tr>
+ <td>Variable name</td>
+ <td>Category name</td>
+ <td>Meaning</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveAssert</td>
+ <td>sm_check_assert</td>
+ <td>enable expensive SM_ASSERT checking</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveRequire</td>
+ <td>sm_check_require</td>
+ <td>enable expensive SM_REQUIRE checking</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveEnsure</td>
+ <td>sm_check_ensure</td>
+ <td>enable expensive SM_ENSURE checking</td>
+ </tr>
+ <tr>
+ <td>SmHeapTrace</td>
+ <td>sm_trace_heap</td>
+ <td>trace sm_{malloc,realloc,free} calls</td>
+ </tr>
+ <tr>
+ <td>SmHeapCheck</td>
+ <td>sm_check_heap</td>
+ <td>enable checking and memory leak detection in sm_{malloc,realloc,free}</td>
+ </tr>
+</table>
+
+<h2> Function Reference </h2>
+
+<dl>
+<dt>
+<tt> SM_DEBUG_INITIALIZER </tt>
+<dd>
+ To create a new debug category, use the SM_DEBUG_INITIALIZER macro
+ to initialize a static variable of type SM_DEBUG_T. For example,
+<blockquote><pre>
+SM_DEBUG_T ANSI_debug = SM_DEBUG_INITIALIZER("ANSI",
+ "@(#)$Debug: ANSI - enable reverse video in debug output $");
+</pre></blockquote>
+ There is no centralized table of category names that needs to
+ be edited in order to add a new debug category.
+ The sole purpose of the second argument to SM_DEBUG_INITIALIZER
+ is to provide an easy way to find out what named debug categories
+ are present in a sendmail binary. You can use:
+<blockquote><pre>
+ident /usr/sbin/sendmail | grep Debug
+</pre></blockquote>
+ or:
+<blockquote><pre>
+what /usr/sbin/sendmail | grep Debug
+</pre></blockquote>
+
+
+<dt>
+<tt> void sm_debug_addsetting(char *pattern, int level) </tt>
+<dd>
+ All debug categories default to activation level 0, which means
+ no activity.
+ This function updates an internal database of debug settings,
+ setting all categories whose name matches the specified glob
+ pattern to the specified activation level. The level argument
+ must be &gt;= 0.
+ <p>
+
+
+<dt>
+<tt> void sm_debug_addsettings(char *settings) </tt>
+<dd>
+ This function is used to process the <tt>-d</tt> command line
+ option of Sendmail 9.x, and of other programs that support the
+ setting of named debug categories. The settings argument is a
+ comma-separated list of settings; each setting is a glob pattern,
+ optionally followed by a '.' and a decimal numeral.
+ <p>
+
+
+<dt>
+<tt> bool sm_debug_active(SM_DEBUG_T *debug, int level) </tt>
+<dd>
+ This macro returns <tt>true</tt> if the activation level of
+ the statically initialized debug structure <tt>debug</tt>
+ is &gt;= the specified level.
+ The test is performed very efficiently: in the most common case,
+ when the result is <tt>false</tt>, only a single comparison
+ operation is performed.
+ <p>
+ This macro performs a function call only if the debug structure has
+ an unknown activation level. All debug structures are in this state
+ at the beginning of program execution, and after a call to
+ <tt>sm_debug_addsetting</tt>.
+ <p>
+
+
+<dt>
+<tt> int sm_debug_level(SM_DEBUG_T *debug) </tt>
+<dd>
+ This macro returns the activation level of the specified debug structure.
+ The comparison
+<blockquote><pre>
+sm_debug_level(debug) &gt;= level
+</pre></blockquote>
+ is slightly less efficient than, but otherwise semantically
+ equivalent to
+<blockquote><pre>
+sm_debug_active(debug, level)
+</pre></blockquote>
+ <p>
+
+
+<dt>
+<tt> bool sm_debug_unknown(SM_DEBUG_T *debug) </tt>
+<dd>
+ This macro returns true if the activation level of the specified
+ debug structure is unknown.
+ Here is an example of how the macro might be used:
+<blockquote><pre>
+if (sm_debug_unknown(&FooDebug))
+{
+ if (sm_debug_active(&FooDebug, 1))
+ {
+ ... perform some expensive data structure initializations
+ ... in order to enable the "foo" debugging mechanism
+ }
+ else
+ {
+ ... disable the "foo" debugging mechanism
+ }
+}
+</pre></blockquote>
+ The purpose of using <tt>sm_debug_unknown</tt> in the above example
+ is to avoid performing the expensive initializations each time through
+ the code. So it's a performance hack.
+ A debug structure is in the "unknown" state at the beginning of
+ program execution, and after a call to <tt>sm_debug_addsetting</tt>.
+ A side effect of calling <tt>sm_debug_active</tt> is that the
+ activation level becomes known.
+ <p>
+
+
+<dt>
+<tt> void sm_dprintf(char *fmt, ...) </tt>
+<dd>
+ This function is used to print a debug message.
+ The standard idiom is
+<blockquote><pre>
+if (sm_debug_active(&BarDebug, 1))
+ sm_dprintf("bar: about to test tensile strength of bar %d\n", i);
+</pre></blockquote>
+ <p>
+
+<dt>
+<tt> void sm_dflush() </tt>
+<dd>
+ Flush the debug output stream.
+ <p>
+
+<dt>
+<tt> void sm_debug_setfile(SM_FILE_T *file) </tt>
+<dd>
+ This function lets you specify where debug output is printed.
+ By default, debug output is written to standard output.
+ <p>
+ We want to allow you to direct debug output to syslog.
+ The current plan is to provide a standard interface for
+ creating an SM_FILE_T object that writes to syslog.
+
+</dl>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/errstring.c b/contrib/sendmail/libsm/errstring.c
new file mode 100644
index 0000000..29aaade
--- /dev/null
+++ b/contrib/sendmail/libsm/errstring.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: errstring.c,v 1.12 2001/10/03 16:09:32 ca Exp $")
+
+#include <errno.h>
+#include <stdio.h> /* sys_errlist, on some platforms */
+
+#include <sm/io.h> /* sm_snprintf */
+#include <sm/string.h>
+#include <sm/errstring.h>
+
+#if NAMED_BIND
+# include <netdb.h>
+#endif
+
+#if LDAPMAP
+# include <lber.h>
+# include <ldap.h> /* for LDAP error codes */
+#endif /* LDAPMAP */
+
+/*
+** Notice: this file is used by libmilter. Please try to avoid
+** using libsm specific functions.
+*/
+
+/*
+** SM_ERRSTRING -- return string description of error code
+**
+** Parameters:
+** errnum -- the error number to translate
+**
+** Returns:
+** A string description of errnum.
+*/
+
+const char *
+sm_errstring(errnum)
+ int errnum;
+{
+ char *ret;
+
+ switch (errnum)
+ {
+ case EPERM:
+ /* SunOS gives "Not owner" -- this is the POSIX message */
+ return "Operation not permitted";
+
+ /*
+ ** Error messages used internally in sendmail.
+ */
+
+ case E_SM_OPENTIMEOUT:
+ return "Timeout on file open";
+
+ case E_SM_NOSLINK:
+ return "Symbolic links not allowed";
+
+ case E_SM_NOHLINK:
+ return "Hard links not allowed";
+
+ case E_SM_REGONLY:
+ return "Regular files only";
+
+ case E_SM_ISEXEC:
+ return "Executable files not allowed";
+
+ case E_SM_WWDIR:
+ return "World writable directory";
+
+ case E_SM_GWDIR:
+ return "Group writable directory";
+
+ case E_SM_FILECHANGE:
+ return "File changed after open";
+
+ case E_SM_WWFILE:
+ return "World writable file";
+
+ case E_SM_GWFILE:
+ return "Group writable file";
+
+ case E_SM_GRFILE:
+ return "Group readable file";
+
+ case E_SM_WRFILE:
+ return "World readable file";
+
+ /*
+ ** DNS error messages.
+ */
+
+#if NAMED_BIND
+ case HOST_NOT_FOUND + E_DNSBASE:
+ return "Name server: host not found";
+
+ case TRY_AGAIN + E_DNSBASE:
+ return "Name server: host name lookup failure";
+
+ case NO_RECOVERY + E_DNSBASE:
+ return "Name server: non-recoverable error";
+
+ case NO_DATA + E_DNSBASE:
+ return "Name server: no data known";
+#endif /* NAMED_BIND */
+
+ /*
+ ** libsmdb error messages.
+ */
+
+ case SMDBE_MALLOC:
+ return "Memory allocation failed";
+
+ case SMDBE_GDBM_IS_BAD:
+ return "GDBM is not supported";
+
+ case SMDBE_UNSUPPORTED:
+ return "Unsupported action";
+
+ case SMDBE_DUPLICATE:
+ return "Key already exists";
+
+ case SMDBE_BAD_OPEN:
+ return "Database open failed";
+
+ case SMDBE_NOT_FOUND:
+ return "Key not found";
+
+ case SMDBE_UNKNOWN_DB_TYPE:
+ return "Unknown database type";
+
+ case SMDBE_UNSUPPORTED_DB_TYPE:
+ return "Support for database type not compiled into this program";
+
+ case SMDBE_INCOMPLETE:
+ return "DB sync did not finish";
+
+ case SMDBE_KEY_EMPTY:
+ return "Key is empty";
+
+ case SMDBE_KEY_EXIST:
+ return "Key already exists";
+
+ case SMDBE_LOCK_DEADLOCK:
+ return "Locker killed to resolve deadlock";
+
+ case SMDBE_LOCK_NOT_GRANTED:
+ return "Lock unavailable";
+
+ case SMDBE_LOCK_NOT_HELD:
+ return "Lock not held by locker";
+
+ case SMDBE_RUN_RECOVERY:
+ return "Database panic, run recovery";
+
+ case SMDBE_IO_ERROR:
+ return "I/O error";
+
+ case SMDBE_READ_ONLY:
+ return "Database opened read-only";
+
+ case SMDBE_DB_NAME_TOO_LONG:
+ return "Name too long";
+
+ case SMDBE_INVALID_PARAMETER:
+ return "Invalid parameter";
+
+ case SMDBE_ONLY_SUPPORTS_ONE_CURSOR:
+ return "Only one cursor allowed";
+
+ case SMDBE_NOT_A_VALID_CURSOR:
+ return "Invalid cursor";
+
+ case SMDBE_OLD_VERSION:
+ return "Berkeley DB file is an old version, recreate it";
+ }
+
+ /*
+ ** LDAP error messages.
+ */
+
+#if LDAPMAP
+ if (errnum >= E_LDAPBASE)
+ return ldap_err2string(errnum - E_LDAPBASE);
+#endif /* LDAPMAP */
+
+ ret = strerror(errnum);
+ if (ret == NULL)
+ {
+ static char buf[30];
+
+ (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
+ return buf;
+ }
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/exc.c b/contrib/sendmail/libsm/exc.c
new file mode 100644
index 0000000..9cc1c6f
--- /dev/null
+++ b/contrib/sendmail/libsm/exc.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: exc.c,v 1.47 2002/01/09 18:51:43 ca Exp $")
+
+/*
+** exception handling
+** For documentation, see exc.html
+*/
+
+#include <ctype.h>
+#include <string.h>
+
+#include <sm/errstring.h>
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+
+const char SmExcMagic[] = "sm_exc";
+const char SmExcTypeMagic[] = "sm_exc_type";
+
+/*
+** SM_ETYPE_PRINTF -- printf for exception types.
+**
+** Parameters:
+** exc -- exception.
+** stream -- file for output.
+**
+** Returns:
+** none.
+*/
+
+/*
+** A simple formatted print function that can be used as the print function
+** by most exception types. It prints the printcontext string, interpreting
+** occurrences of %0 through %9 as references to the argument vector.
+** If exception argument 3 is an int or long, then %3 will print the
+** argument in decimal, and %o3 or %x3 will print it in octal or hex.
+*/
+
+void
+sm_etype_printf(exc, stream)
+ SM_EXC_T *exc;
+ SM_FILE_T *stream;
+{
+ size_t n = strlen(exc->exc_type->etype_argformat);
+ const char *p, *s;
+ char format;
+
+ for (p = exc->exc_type->etype_printcontext; *p != '\0'; ++p)
+ {
+ if (*p != '%')
+ {
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
+ continue;
+ }
+ ++p;
+ if (*p == '\0')
+ {
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
+ break;
+ }
+ if (*p == '%')
+ {
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
+ continue;
+ }
+ format = '\0';
+ if (isalpha(*p))
+ {
+ format = *p++;
+ if (*p == '\0')
+ {
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT,
+ format);
+ break;
+ }
+ }
+ if (isdigit(*p))
+ {
+ size_t i = *p - '0';
+ if (i < n)
+ {
+ switch (exc->exc_type->etype_argformat[i])
+ {
+ case 's':
+ case 'r':
+ s = exc->exc_argv[i].v_str;
+ if (s == NULL)
+ s = "(null)";
+ sm_io_fputs(stream, SM_TIME_DEFAULT, s);
+ continue;
+ case 'i':
+ sm_io_fprintf(stream,
+ SM_TIME_DEFAULT,
+ format == 'o' ? "%o"
+ : format == 'x' ? "%x"
+ : "%d",
+ exc->exc_argv[i].v_int);
+ continue;
+ case 'l':
+ sm_io_fprintf(stream,
+ SM_TIME_DEFAULT,
+ format == 'o' ? "%lo"
+ : format == 'x' ? "%lx"
+ : "%ld",
+ exc->exc_argv[i].v_long);
+ continue;
+ case 'e':
+ sm_exc_write(exc->exc_argv[i].v_exc,
+ stream);
+ continue;
+ }
+ }
+ }
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
+ if (format)
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, format);
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
+ }
+}
+
+/*
+** Standard exception types.
+*/
+
+/*
+** SM_ETYPE_OS_PRINT -- Print OS related exception.
+**
+** Parameters:
+** exc -- exception.
+** stream -- file for output.
+**
+** Returns:
+** none.
+*/
+
+static void
+sm_etype_os_print __P((
+ SM_EXC_T *exc,
+ SM_FILE_T *stream));
+
+static void
+sm_etype_os_print(exc, stream)
+ SM_EXC_T *exc;
+ SM_FILE_T *stream;
+{
+ int err = exc->exc_argv[0].v_int;
+ char *syscall = exc->exc_argv[1].v_str;
+ char *sysargs = exc->exc_argv[2].v_str;
+
+ if (sysargs)
+ sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s: %s failed: %s",
+ sysargs, syscall, sm_errstring(err));
+ else
+ sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall,
+ sm_errstring(err));
+}
+
+/*
+** SmEtypeOs represents the failure of a Unix system call.
+** The three arguments are:
+** int errno (eg, ENOENT)
+** char *syscall (eg, "open")
+** char *sysargs (eg, NULL or "/etc/mail/sendmail.cf")
+*/
+
+const SM_EXC_TYPE_T SmEtypeOs =
+{
+ SmExcTypeMagic,
+ "E:sm.os",
+ "isr",
+ sm_etype_os_print,
+ NULL,
+};
+
+/*
+** SmEtypeErr is a completely generic error which should only be
+** used in applications and test programs. Libraries should use
+** more specific exception codes.
+*/
+
+const SM_EXC_TYPE_T SmEtypeErr =
+{
+ SmExcTypeMagic,
+ "E:sm.err",
+ "r",
+ sm_etype_printf,
+ "%0",
+};
+
+/*
+** SM_EXC_VNEW_X -- Construct a new exception object.
+**
+** Parameters:
+** etype -- type of exception.
+** ap -- varargs.
+**
+** Returns:
+** pointer to exception object.
+*/
+
+/*
+** This is an auxiliary function called by sm_exc_new_x and sm_exc_raisenew_x.
+**
+** If an exception is raised, then to avoid a storage leak, we must:
+** (a) Free all storage we have allocated.
+** (b) Free all exception arguments in the varargs list.
+** Getting this right is tricky.
+**
+** To see why (b) is required, consider the code fragment
+** SM_EXCEPT(exc, "*")
+** sm_exc_raisenew_x(&MyEtype, exc);
+** SM_END_TRY
+** In the normal case, sm_exc_raisenew_x will allocate and raise a new
+** exception E that owns exc. When E is eventually freed, exc is also freed.
+** In the exceptional case, sm_exc_raisenew_x must free exc before raising
+** an out-of-memory exception so that exc is not leaked.
+*/
+
+SM_EXC_T *
+sm_exc_vnew_x(etype, ap)
+ const SM_EXC_TYPE_T *etype;
+ va_list SM_NONVOLATILE ap;
+{
+ /*
+ ** All variables that are modified in the SM_TRY clause and
+ ** referenced in the SM_EXCEPT clause must be declared volatile.
+ */
+
+ /* NOTE: Type of si, i, and argc *must* match */
+ SM_EXC_T * volatile exc = NULL;
+ int volatile si = 0;
+ SM_VAL_T * volatile argv = NULL;
+ int i, argc;
+
+ SM_REQUIRE_ISA(etype, SmExcTypeMagic);
+ argc = strlen(etype->etype_argformat);
+ SM_TRY
+ {
+ /*
+ ** Step 1. Allocate the exception structure.
+ ** On failure, scan the varargs list and free all
+ ** exception arguments.
+ */
+
+ exc = sm_malloc_x(sizeof(SM_EXC_T));
+ exc->sm_magic = SmExcMagic;
+ exc->exc_refcount = 1;
+ exc->exc_type = etype;
+ exc->exc_argv = NULL;
+
+ /*
+ ** Step 2. Allocate the argument vector.
+ ** On failure, free exc, scan the varargs list and free all
+ ** exception arguments. On success, scan the varargs list,
+ ** and copy the arguments into argv.
+ */
+
+ argv = sm_malloc_x(argc * sizeof(SM_VAL_T));
+ exc->exc_argv = argv;
+ for (i = 0; i < argc; ++i)
+ {
+ switch (etype->etype_argformat[i])
+ {
+ case 'i':
+ argv[i].v_int = SM_VA_ARG(ap, int);
+ break;
+ case 'l':
+ argv[i].v_long = SM_VA_ARG(ap, long);
+ break;
+ case 'e':
+ argv[i].v_exc = SM_VA_ARG(ap, SM_EXC_T*);
+ break;
+ case 's':
+ argv[i].v_str = SM_VA_ARG(ap, char*);
+ break;
+ case 'r':
+ SM_REQUIRE(etype->etype_argformat[i+1] == '\0');
+ argv[i].v_str = SM_VA_ARG(ap, char*);
+ break;
+ default:
+ sm_abort("sm_exc_vnew_x: bad argformat '%c'",
+ etype->etype_argformat[i]);
+ }
+ }
+
+ /*
+ ** Step 3. Scan argv, and allocate space for all
+ ** string arguments. si is the number of elements
+ ** of argv that have been processed so far.
+ ** On failure, free exc, argv, all the exception arguments
+ ** and all of the strings that have been copied.
+ */
+
+ for (si = 0; si < argc; ++si)
+ {
+ switch (etype->etype_argformat[si])
+ {
+ case 's':
+ {
+ char *str = argv[si].v_str;
+ if (str != NULL)
+ argv[si].v_str = sm_strdup_x(str);
+ }
+ break;
+ case 'r':
+ {
+ char *fmt = argv[si].v_str;
+ if (fmt != NULL)
+ argv[si].v_str = sm_vstringf_x(fmt, ap);
+ }
+ break;
+ }
+ }
+ }
+ SM_EXCEPT(e, "*")
+ {
+ if (exc == NULL || argv == NULL)
+ {
+ /*
+ ** Failure in step 1 or step 2.
+ ** Scan ap and free all exception arguments.
+ */
+
+ for (i = 0; i < argc; ++i)
+ {
+ switch (etype->etype_argformat[i])
+ {
+ case 'i':
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case 'l':
+ (void) SM_VA_ARG(ap, long);
+ break;
+ case 'e':
+ sm_exc_free(SM_VA_ARG(ap, SM_EXC_T*));
+ break;
+ case 's':
+ case 'r':
+ (void) SM_VA_ARG(ap, char*);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** Failure in step 3. Scan argv and free
+ ** all exception arguments and all string
+ ** arguments that have been duplicated.
+ ** Then free argv.
+ */
+
+ for (i = 0; i < argc; ++i)
+ {
+ switch (etype->etype_argformat[i])
+ {
+ case 'e':
+ sm_exc_free(argv[i].v_exc);
+ break;
+ case 's':
+ case 'r':
+ if (i < si)
+ sm_free(argv[i].v_str);
+ break;
+ }
+ }
+ sm_free(argv);
+ }
+ sm_free(exc);
+ sm_exc_raise_x(e);
+ }
+ SM_END_TRY
+
+ return exc;
+}
+
+/*
+** SM_EXC_NEW_X -- Construct a new exception object.
+**
+** Parameters:
+** etype -- type of exception.
+** ... -- varargs.
+**
+** Returns:
+** pointer to exception object.
+*/
+
+SM_EXC_T *
+#if SM_VA_STD
+sm_exc_new_x(
+ const SM_EXC_TYPE_T *etype,
+ ...)
+#else /* SM_VA_STD */
+sm_exc_new_x(etype, va_alist)
+ const SM_EXC_TYPE_T *etype;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ SM_EXC_T *exc;
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, etype);
+ exc = sm_exc_vnew_x(etype, ap);
+ SM_VA_END(ap);
+ return exc;
+}
+
+/*
+** SM_ADDREF -- Add a reference to an exception object.
+**
+** Parameters:
+** exc -- exception object.
+**
+** Returns:
+** exc itself.
+*/
+
+SM_EXC_T *
+sm_addref(exc)
+ SM_EXC_T *exc;
+{
+ SM_REQUIRE_ISA(exc, SmExcMagic);
+ if (exc->exc_refcount != 0)
+ ++exc->exc_refcount;
+ return exc;
+}
+
+/*
+** SM_EXC_FREE -- Destroy a reference to an exception object.
+**
+** Parameters:
+** exc -- exception object.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_exc_free(exc)
+ SM_EXC_T *exc;
+{
+ if (exc == NULL)
+ return;
+ SM_REQUIRE(exc->sm_magic == SmExcMagic);
+ if (exc->exc_refcount == 0)
+ return;
+ if (--exc->exc_refcount == 0)
+ {
+ int i, c;
+
+ for (i = 0; (c = exc->exc_type->etype_argformat[i]) != '\0';
+ ++i)
+ {
+ switch (c)
+ {
+ case 's':
+ case 'r':
+ sm_free(exc->exc_argv[i].v_str);
+ break;
+ case 'e':
+ sm_exc_free(exc->exc_argv[i].v_exc);
+ break;
+ }
+ }
+ exc->sm_magic = NULL;
+ sm_free(exc->exc_argv);
+ sm_free(exc);
+ }
+}
+
+/*
+** SM_EXC_MATCH -- Match exception category against a glob pattern.
+**
+** Parameters:
+** exc -- exception.
+** pattern -- glob pattern.
+**
+** Returns:
+** true iff match.
+*/
+
+bool
+sm_exc_match(exc, pattern)
+ SM_EXC_T *exc;
+ const char *pattern;
+{
+ if (exc == NULL)
+ return false;
+ SM_REQUIRE(exc->sm_magic == SmExcMagic);
+ return sm_match(exc->exc_type->etype_category, pattern);
+}
+
+/*
+** SM_EXC_WRITE -- Write exception message to a stream (wo trailing newline).
+**
+** Parameters:
+** exc -- exception.
+** stream -- file for output.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_exc_write(exc, stream)
+ SM_EXC_T *exc;
+ SM_FILE_T *stream;
+{
+ SM_REQUIRE_ISA(exc, SmExcMagic);
+ exc->exc_type->etype_print(exc, stream);
+}
+
+/*
+** SM_EXC_PRINT -- Print exception message to a stream (with trailing newline).
+**
+** Parameters:
+** exc -- exception.
+** stream -- file for output.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_exc_print(exc, stream)
+ SM_EXC_T *exc;
+ SM_FILE_T *stream;
+{
+ SM_REQUIRE_ISA(exc, SmExcMagic);
+ exc->exc_type->etype_print(exc, stream);
+ (void) sm_io_putc(stream, SM_TIME_DEFAULT, '\n');
+}
+
+SM_EXC_HANDLER_T *SmExcHandler = NULL;
+static SM_EXC_DEFAULT_HANDLER_T SmExcDefaultHandler = NULL;
+
+/*
+** SM_EXC_NEWTHREAD -- Initialize exception handling for new process/thread.
+**
+** Parameters:
+** h -- default exception handler.
+**
+** Returns:
+** none.
+*/
+
+/*
+** Initialize a new process or a new thread by clearing the
+** exception handler stack and optionally setting a default
+** exception handler function. Call this at the beginning of main,
+** or in a new process after calling fork, or in a new thread.
+**
+** This function is a luxury, not a necessity.
+** If h != NULL then you can get the same effect by
+** wrapping the body of main, or the body of a forked child
+** or a new thread in SM_TRY ... SM_EXCEPT(e,"*") h(e); SM_END_TRY.
+*/
+
+void
+sm_exc_newthread(h)
+ SM_EXC_DEFAULT_HANDLER_T h;
+{
+ SmExcHandler = NULL;
+ SmExcDefaultHandler = h;
+}
+
+/*
+** SM_EXC_RAISE_X -- Raise an exception.
+**
+** Parameters:
+** exc -- exception.
+**
+** Returns:
+** doesn't.
+*/
+
+void
+sm_exc_raise_x(exc)
+ SM_EXC_T *exc;
+{
+ SM_REQUIRE_ISA(exc, SmExcMagic);
+
+ if (SmExcHandler == NULL)
+ {
+ if (SmExcDefaultHandler != NULL)
+ {
+ SM_EXC_DEFAULT_HANDLER_T h;
+
+ /*
+ ** If defined, the default handler is expected
+ ** to terminate the current thread of execution
+ ** using exit() or pthread_exit().
+ ** If it instead returns normally, then we fall
+ ** through to the default case below. If it
+ ** raises an exception, then sm_exc_raise_x is
+ ** re-entered and, because we set SmExcDefaultHandler
+ ** to NULL before invoking h, we will again
+ ** end up in the default case below.
+ */
+
+ h = SmExcDefaultHandler;
+ SmExcDefaultHandler = NULL;
+ (*h)(exc);
+ }
+
+ /*
+ ** No exception handler, so print the error and exit.
+ ** To override this behaviour on a program wide basis,
+ ** call sm_exc_newthread or put an exception handler in main().
+ **
+ ** XXX TODO: map the exception category to an exit code
+ ** XXX from <sysexits.h>.
+ */
+
+ sm_exc_print(exc, smioerr);
+ exit(255);
+ }
+
+ if (SmExcHandler->eh_value == NULL)
+ SmExcHandler->eh_value = exc;
+ else
+ sm_exc_free(exc);
+
+ sm_longjmp_nosig(SmExcHandler->eh_context, 1);
+}
+
+/*
+** SM_EXC_RAISENEW_X -- shorthand for sm_exc_raise_x(sm_exc_new_x(...))
+**
+** Parameters:
+** etype -- type of exception.
+** ap -- varargs.
+**
+** Returns:
+** none.
+*/
+
+void
+#if SM_VA_STD
+sm_exc_raisenew_x(
+ const SM_EXC_TYPE_T *etype,
+ ...)
+#else
+sm_exc_raisenew_x(etype, va_alist)
+ const SM_EXC_TYPE_T *etype;
+ va_dcl
+#endif
+{
+ SM_EXC_T *exc;
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, etype);
+ exc = sm_exc_vnew_x(etype, ap);
+ SM_VA_END(ap);
+ sm_exc_raise_x(exc);
+}
diff --git a/contrib/sendmail/libsm/exc.html b/contrib/sendmail/libsm/exc.html
new file mode 100644
index 0000000..a299036
--- /dev/null
+++ b/contrib/sendmail/libsm/exc.html
@@ -0,0 +1,757 @@
+<html>
+<head>
+ <title>libsm : Exception Handling</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Exception Handling </h1>
+ <br> $Id: exc.html,v 1.12 2001/02/13 21:21:25 gshapiro Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The exception handling package provides the facilities that
+functions in libsm use to report errors.
+Here are the basic concepts:
+
+<ol>
+<li>
+ When a function detects an exceptional condition at the library level,
+ it does not print an error message, or call syslog, or
+ exit the program. Instead, it reports the error back to its
+ caller, and lets the caller decide what to do.
+ This improves modularity, because error handling is separated
+ from error reporting.
+ <p>
+<li>
+ Errors are not represented by a single integer error code,
+ because that you can't represent everything that an error handler
+ might need to know about an error by a single integer.
+ Instead, errors are represented by exception objects.
+ An exception object contains an exception code and an array
+ of zero or more exception arguments.
+ The exception code is a string that specifies what kind of exception
+ this is, and the arguments may be integers, strings or exception objects.
+ <p>
+<li>
+ Errors are not reported using a special return value,
+ because if you religiously check for error returns from every
+ function call that could fail, then most of your code ends up being
+ error handling code. Errors are reported by raising an exception.
+ When an exception is raised, we unwind the call stack
+ until we find an exception handler. If the exception is
+ not handled, then we print the exception on stderr and
+ exit the program.
+</ol>
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/exc.h&gt;
+
+typedef struct sm_exc_type SM_EXC_TYPE_T;
+typedef struct sm_exc SM_EXC_T;
+typedef union sm_val SM_VAL_T;
+
+/*
+** Exception types
+*/
+
+extern const char SmExcTypeMagic[];
+
+struct sm_exc_type
+{
+ const char *sm_magic;
+ const char *etype_category;
+ const char *etype_argformat;
+ void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
+ const char *etype_printcontext;
+};
+
+extern const SM_EXC_TYPE_T SmEtypeOs;
+extern const SM_EXC_TYPE_T SmEtypeErr;
+
+void
+sm_etype_printf(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+/*
+** Exception objects
+*/
+
+extern const char SmExcMagic[];
+
+union sm_val
+{
+ int v_int;
+ long v_long;
+ char *v_str;
+ SM_EXC_T *v_exc;
+};
+
+struct sm_exc
+{
+ const char *sm_magic;
+ size_t exc_refcount;
+ const SM_EXC_TYPE_T *exc_type;
+ SM_VAL_T *exc_argv;
+};
+
+SM_EXC_T *
+sm_exc_new_x(
+ const SM_EXC_TYPE_T *type,
+ ...);
+
+SM_EXC_T *
+sm_exc_addref(
+ SM_EXC_T *exc);
+
+void
+sm_exc_free(
+ SM_EXC_T *exc);
+
+bool
+sm_exc_match(
+ SM_EXC_T *exc,
+ const char *pattern);
+
+void
+sm_exc_print(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+void
+sm_exc_write(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+void
+sm_exc_raise_x(
+ SM_EXC_T *exc);
+
+void
+sm_exc_raisenew_x(
+ const SM_EXC_TYPE_T *type,
+ ...);
+
+/*
+** Ensure that cleanup code is executed,
+** and/or handle an exception.
+*/
+SM_TRY
+ Block of code that may raise an exception.
+SM_FINALLY
+ Cleanup code that may raise an exception.
+ This clause is guaranteed to be executed even if an exception is
+ raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
+ You may have 0 or more SM_FINALLY clauses.
+SM_EXCEPT(exc, pattern)
+ Exception handling code, triggered by an exception
+ whose category matches 'pattern'.
+ You may have 0 or more SM_EXCEPT clauses.
+SM_END_TRY
+</pre>
+
+<h2> Overview </h2>
+
+ An exception is an object which represents an exceptional condition,
+ which might be an error condition like "out of memory", or might be
+ a condition like "end of file".
+<p>
+ Functions in libsm report errors and other unusual conditions by
+ raising an exception, rather than by returning an error code or
+ setting a global variable such as errno. If a libsm function is
+ capable of raising an exception, its name ends in "_x".
+ (We do not raise an exception when a bug is detected in the
+ program; instead, we terminate the program using <tt>sm_abort</tt>.
+ See <a href="assert.html">the assertion package</a>
+ for details.)
+<p>
+ When you are using the libsm exception handling package,
+ you are using a new programming paradigm.
+ You will need to abandon some of the programming idioms
+ you are accustomed to, and switch to new idioms.
+ Here is an overview of some of these idioms.
+<ol>
+<li>
+ When a function is unable to complete its task because
+ of an exceptional condition, it reports this condition
+ by raising an exception.
+ <p>
+ Here is an example of how to construct an exception object
+ and raise an exception.
+ In this example, we convert a Unix system error into an exception.
+<blockquote><pre>
+fd = open(path, O_RDONLY);
+if (fd == -1)
+ sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
+</pre></blockquote>
+
+ Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
+ is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
+<p>
+<li>
+ When you detect an error at the application level,
+ you don't call a function like BSD's <tt>errx</tt>,
+ which prints an error message on stderr and exits the program.
+ Instead, you raise an exception.
+ This causes cleanup code in surrounding exception handlers
+ to be run before the program exits.
+ For example, instead of this:
+<blockquote><pre>
+errx(1, "%s:%d: syntax error", filename, lineno);
+</pre></blockquote>
+
+ use this:
+
+<blockquote><pre>
+sm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
+</pre></blockquote>
+
+ The latter code raises an exception, unwinding the call stack
+ and executing cleanup code.
+ If the exception is not handled, then the exception is printed
+ to stderr and the program exits.
+ The end result is substantially the same as a call to <tt>errx</tt>.
+<p>
+<li>
+ The SM_TRY ... SM_FINALLY ... control structure
+ ensures that cleanup code is executed and resources are released
+ in the presence of exceptions.
+<p>
+ For example, suppose that you have written the following code:
+
+<blockquote><pre>
+rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
+... some code ...
+sm_rpool_free_x(rpool);
+</pre></blockquote>
+
+ If any of the functions called within "... some code ..." have
+ names ending in _x, then it is possible that an exception will be
+ raised, and if that happens, then "rpool" will not be freed.
+ And that's a bug. To fix this bug, change your code so it looks
+ like this:
+
+<blockquote><pre>
+rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
+SM_TRY
+ ... some code that can raise an exception ...
+SM_FINALLY
+ sm_rpool_free_x(rpool);
+SM_END_TRY
+</pre></blockquote>
+
+<li>
+ The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
+ Unhandled exceptions terminate the program.
+ For example, here is a simple exception handler
+ that traps all exceptions, and prints the exceptions:
+
+<blockquote><pre>
+SM_TRY
+ /* code that can raise an exception */
+ ...
+SM_EXCEPT(exc, "*")
+ /* catch all exceptions */
+ sm_exc_print(exc, stderr);
+SM_END_TRY
+</pre></blockquote>
+
+ Exceptions are reference counted. The SM_END_TRY macro contains a
+ call to sm_exc_free, so you don't normally need to worry about freeing
+ an exception after handling it. In the rare case that you want an
+ exception to outlive an exception handler, then you increment its
+ reference count by calling sm_exc_addref.
+<p>
+<li>
+ The second argument of the SM_EXCEPT macro is a glob pattern
+ which specifies the types of exceptions that are to be handled.
+ For example, you might want to handle an end-of-file exception
+ differently from other exceptions.
+ Here's how you do that:
+
+<blockquote><pre>
+SM_TRY
+ /* code that might raise end-of-file, or some other exception */
+ ...
+SM_EXCEPT(exc, "E:sm.eof")
+ /* what to do if end-of-file is encountered */
+ ...
+SM_EXCEPT(exc, "*")
+ /* what to do if some other exception is raised */
+ ...
+SM_END_TRY
+</pre></blockquote>
+</ol>
+
+<h2> Exception Values </h2>
+
+In traditional C code, errors are usually denoted by a single integer,
+such as errno. In practice, errno does not carry enough information
+to describe everything that an error handler might want to know about
+an error. And the scheme is not very extensible: if several different
+packages want to add additional error codes, it is hard to avoid
+collisions.
+
+<p>
+In libsm, an exceptional condition is described
+by an object of type SM_EXC_T.
+An exception object is created by specifying an exception type
+and a list of exception arguments.
+
+<p>
+The exception arguments are an array of zero or more values.
+The values may be a mixture of ints, longs, strings, and exceptions.
+In the SM_EXC_T structure, the argument vector is represented
+by <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
+is a union of the possible argument types.
+The number and types of exception arguments is determined by
+the exception type.
+
+<p>
+An exception type is a statically initialized const object
+of type SM_EXC_TYPE_T, which has the following members:
+
+<dl>
+<dt>
+<tt> const char *sm_magic </tt>
+<dd>
+ A pointer to <tt>SmExcTypeMagic</tt>.
+ <p>
+<dt>
+<tt> const char *etype_category </tt>
+<dd>
+ This is a string of the form
+ <tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
+ <p>
+ The <i>class</i> is used to assign the exception type to
+ one of a number of broad categories of exceptions on which an
+ exception handler might want to discriminate.
+ I suspect that what we want is a hierarchical taxonomy,
+ but I don't have a full design for this yet.
+ For now, I am recommending the following classes:
+ <dl>
+ <dt><tt>"F"</tt>
+ <dd>A fatal error has occurred.
+ This is an error that prevents the application
+ from making any further progress, so the only
+ recourse is to raise an exception, execute cleanup code
+ as the stack is unwound, then exit the application.
+ The out-of-memory exception raised by sm_malloc_x
+ has category "F:sm.heap" because sendmail commits suicide
+ (after logging the error and cleaning up) when it runs out
+ of memory.
+
+ <dt><tt>"E"</tt>
+ <dd>The function could not complete its task because an error occurred.
+ (It might be useful to define subclasses of this category,
+ in which case our taxonony becomes a tree, and 'F' becomes
+ a subclass of 'E'.)
+
+ <dt><tt>"J"</tt>
+ <dd>This exception is being raised in order to effect a
+ non-local jump. No error has occurred; we are just
+ performing the non-local equivalent of a <tt>continue</tt>,
+ <tt>break</tt> or <tt>return</tt>.
+
+ <dt><tt>"S"</tt>
+ <dd>The function was interrupted by a signal.
+ Signals are not errors because they occur asynchronously,
+ and they are semantically unrelated to the function that
+ happens to be executing when the signal arrives.
+ Note that it is extremely dangerous to raise an exception
+ from a signal handler. For example, if you are in the middle
+ of a call to malloc, you might corrupt the heap.
+ </dl>
+ Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
+ for Warning, Debug and Informational:
+ I suspect these categories only make sense in the context of
+ Eric's 1985 exception handling system which allowed you to
+ raise conditions without terminating the calling function.
+ <p>
+ The <i>name</i> uniquely identifies the exception type.
+ I recommend a string of the form
+ <i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
+ <p>
+<dt>
+<tt> const char *etype_argformat </tt>
+<dd>
+ This is an array of single character codes.
+ Each code indicates the type of one of the exception arguments.
+ <tt>sm_exc_new_x</tt> uses this string to decode its variable
+ argument list into an exception argument vector.
+ The following type codes are supported:
+ <dl>
+ <dt><tt>i</tt>
+ <dd>
+ The exception argument has type <tt>int</tt>.
+ <dt><tt>l</tt>
+ <dd>
+ The exception argument has type <tt>long</tt>.
+ <dt><tt>e</tt>
+ <dd>
+ The exception argument has type <tt>SM_EXC_T*</tt>.
+ The value may either be <tt>NULL</tt> or a pointer
+ to an exception. The pointer value is simply copied
+ into the exception argument vector.
+ <dt><tt>s</tt>
+ <dd>
+ The exception argument has type <tt>char*</tt>.
+ The value may either be <tt>NULL</tt> or a pointer
+ to a character string. In the latter case,
+ <tt>sm_exc_new_x</tt> will make a copy of the string.
+ <dt><tt>r</tt>
+ <dd>
+ The exception argument has type <tt>char*</tt>.
+ <tt>sm_exc_new_x</tt> will read a printf-style
+ format string argument followed by a list of printf
+ arguments from its variable argument list, and convert
+ these into a string.
+ This type code can only occur as the last element
+ of <tt>exc_argformat</tt>.
+ </dl>
+ <p>
+<dt>
+<tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ This function prints an exception of the specified type
+ onto an output stream.
+ The final character printed is not a newline.
+</dl>
+
+<h2> Standard Exceptions and Exception Types </h2>
+
+Libsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
+This is a statically initialized const variable, because it seems
+like a bad idea to dynamically allocate an exception object to
+report a low memory condition.
+This exception has category <tt>"F:sm.heap"</tt>.
+If you need to, you can explicitly raise this exception
+with <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.
+
+<p>
+Statically initialized exception values cannot contain any
+run-time parameters, so the normal case is to dynamically allocate
+a new exception object whenever you raise an exception.
+Before you can create an exception, you need an exception type.
+Libsm defines the following standard exception types.
+
+<dl>
+<dt>
+<tt> SmEtypeOs </tt>
+<dd>
+ This represents a generic operating system error.
+ The category is <tt>"E:sm.os"</tt>.
+ The argformat is <tt>"isr"</tt>,
+ where argv[0] is the value of <tt>errno</tt>
+ after a system call has failed,
+ argv[1] is the name of the function (usually a system call) that failed,
+ and argv[2] is either <tt>NULL</tt>
+ or a character string which describes some of the arguments
+ to the failing system call (usually it is just a file name).
+ Here's an example of raising an exception:
+
+<blockquote><pre>
+fd = open(filename, O_RDONLY);
+if (fd == -1)
+ sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
+</pre></blockquote>
+
+ If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
+ then the exception raised by the above code will be printed as
+
+<blockquote><pre>
+/etc/mail/snedmail.cf: open failed: No such file or directory
+</pre></blockquote>
+
+<dt>
+<tt> SmEtypeErr </tt>
+<dd>
+ This represents a generic error.
+ The category is <tt>"E:sm.err"</tt>,
+ and the argformat is <tt>"r"</tt>.
+ You can use it
+ in application contexts where you are raising an exception
+ for the purpose of terminating the program.
+ You know the exception won't be handled,
+ so you don't need to worry about packaging the error for
+ later analysis by an exception handler.
+ All you need to specify is the message string that
+ will be printed to stderr before the program exits.
+ For example,
+
+<blockquote><pre>
+sm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
+</pre></blockquote>
+</dl>
+
+<h2> Custom Exception Types </h2>
+
+If you are writing a library package, and you need to raise
+exceptions that are not standard Unix system errors,
+then you need to define one or more new exception types.
+
+<p>
+Every new exception type needs a print function.
+The standard print function <tt>sm_etype_printf</tt>
+is all you need in the majority of cases.
+It prints the <tt>etype_printcontext</tt> string of the exception type,
+substituting occurrences of %0 through %9 with the corresponding
+exception argument.
+If exception argument 3 is an int or long,
+then %3 will print the argument in decimal,
+and %o3 or %x3 will print it in octal or hex.
+
+<p>
+In the following example, I will assume that your library
+package implements regular expressions, and can raise 5 different exceptions.
+When compiling a regular expression, 3 different syntax errors
+can be reported:
+<ul>
+<li>unbalanced parenthesis
+<li>unbalanced bracket
+<li>missing argument for repetition operator
+</ul>
+Whenever one of these errors is reported, you will also report
+the index of the character within the regex string at which the
+syntax error was detected.
+The fourth exception is raised if a compiled regular expression
+is invalid: this exception has no arguments.
+The fifth exception is raised if the package runs out of memory:
+for this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.
+
+<p>
+The obvious approach is to define 4 separate exception types.
+Here they are:
+
+<blockquote><pre>
+/* print a regular expression syntax error */
+void
+rx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
+{
+ sm_io_fprintf(stream, "rx syntax error at character %d: %s",
+ exc-&gt;exc_argv[0].v_int,
+ exc-&gt;exc_type-&gt;etype_printcontext);
+}
+SM_EXC_TYPE_T RxSyntaxParen = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.paren",
+ "i",
+ rx_esyntax_print,
+ "unbalanced parenthesis"
+};
+SM_EXC_TYPE_T RxSyntaxBracket = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.bracket",
+ "i",
+ rx_esyntax_print,
+ "unbalanced bracket"
+};
+SM_EXC_TYPE_T RxSyntaxMissingArg = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.missingarg",
+ "i",
+ rx_esyntax_print,
+ "missing argument for repetition operator"
+};
+
+SM_EXC_TYPE_T RxRunCorrupt = {
+ SmExcTypeMagic,
+ "E:mylib.rx.run.corrupt",
+ "",
+ sm_etype_printf,
+ "rx runtime error: compiled regular expression is corrupt"
+};
+</pre></blockquote>
+
+<p>
+With the above definitions, you can raise a syntax error reporting
+an unbalanced parenthesis at string offset <tt>i</tt> using:
+<blockquote><pre>
+sm_exc_raisenew_x(&RxSyntaxParen, i);
+</pre></blockquote>
+
+If <tt>i==42</tt> then this exception will be printed as:
+<blockquote><pre>
+rx syntax error at character 42: unbalanced parenthesis
+</pre></blockquote>
+
+An exception handler can provide special handling for regular
+expression syntax errors using this code:
+<blockquote><pre>
+SM_TRY
+ ... code that might raise an exception ...
+SM_EXCEPT(exc, "E:mylib.rx.syntax.*")
+ int i = exc-&gt;exc_argv[0].v_int;
+ ... handle a regular expression syntax error ...
+SM_END_TRY
+</pre></blockquote>
+
+<p>
+External requirements may force you to define an integer code
+for each error reported by your package. Or you may be wrapping
+an existing package that works this way. In this case, it might
+make sense to define a single exception type, patterned after SmEtypeOs,
+and include the integer code as an exception argument.
+
+<p>
+Your package might intercept an exception E generated by a lower
+level package, and then reclassify it as a different expression E'.
+For example, a package for reading a configuration file might
+reclassify one of the regular expression syntax errors from the
+previous example as a configuration file syntax error.
+When you do this, the new exception E' should include the original
+exception E as an exception parameter, and the print function for
+exception E' should print the high level description of the exception
+(eg, "syntax error in configuration file %s at line %d\n"),
+then print the subexception that is stored as an exception parameter.
+
+<h2> Function Reference </h2>
+
+<dl>
+<dt>
+<tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
+<dd>
+ Create a new exception. Raise an exception on heap exhaustion.
+ The new exception has a reference count of 1.
+ <p>
+
+ A list of zero or more exception arguments follows the exception type;
+ these are copied into the new exception object.
+ The number and types of these arguments is determined
+ by <tt>type-&gt;etype_argformat</tt>.
+ <p>
+
+ Note that there is no rpool argument to sm_exc_new_x.
+ Exceptions are allocated directly from the heap.
+ This is because exceptions are normally raised at low levels
+ of abstraction and handled at high levels. Because the low
+ level code typically has no idea of how or at what level the
+ exception will be handled, it also has no idea of which resource
+ pool, if any, should own the exception.
+ <p>
+<dt>
+<tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
+<dd>
+ Increment the reference count of an exception.
+ Return the first argument.
+ <p>
+<dt>
+<tt> void sm_exc_free(SM_EXC_T *exc) </tt>
+<dd>
+ Decrement the reference count of an exception.
+ If it reaches 0, free the exception object.
+ <p>
+<dt>
+<tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
+<dd>
+ Compare the exception's category to the specified glob pattern,
+ return true if they match.
+ <p>
+<dt>
+<tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ Print the exception on the stream
+ as a sequence of one or more newline terminated lines.
+ <p>
+<dt>
+<tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ Write the exception on the stream without a terminating newline.
+ <p>
+<dt>
+<tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
+<dd>
+ Raise the exception. This function does not return to its caller.
+ <p>
+<dt>
+<tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
+<dd>
+ A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
+</dl>
+
+<h2> Macro Reference </h2>
+
+The SM_TRY ... SM_END_TRY control structure
+ensures that cleanup code is executed in the presence of exceptions,
+and permits exceptions to be handled.
+
+<blockquote><pre>
+SM_TRY
+ A block of code that may raise an exception.
+SM_FINALLY
+ Cleanup code that may raise an exception.
+ This code is guaranteed to be executed whether or not
+ an exception was raised by a previous clause.
+ You may have 0 or more SM_FINALLY clauses.
+SM_EXCEPT(e, pat)
+ Exception handling code, which is triggered by an exception
+ whose category matches the glob pattern 'pat'.
+ The exception value is bound to the local variable 'e'.
+ You may have 0 or more SM_EXCEPT clauses.
+SM_END_TRY
+</pre></blockquote>
+
+First, the SM_TRY clause is executed, then each SM_FINALLY clause is
+executed in sequence.
+If one or more of these clauses was terminated by an exception,
+then the first such exception is remembered, and the other exceptions
+are lost.
+
+If no exception was raised, then we are done.
+
+Otherwise, each of the SM_EXCEPT clauses is examined in sequence.
+and the first SM_EXCEPT clause whose pattern argument matches the exception
+(see <tt>sm_exc_match</tt>) is executed.
+If none of the SM_EXCEPT clauses matched the exception, or if there are
+no SM_EXCEPT clauses, then the remembered exception is re-raised.
+
+<p>
+SM_TRY .. SM_END_TRY clauses may be nested arbitrarily.
+
+<p>
+It is illegal to jump out of a SM_TRY or SM_FINALLY clause
+using goto, break, continue, return or longjmp.
+If you do this, you will corrupt the internal exception handling stack.
+You can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
+these are reserved for use by the implementation.
+It is legal to jump out of an SM_EXCEPT clause using goto or return;
+however, in this case, you must take responsibility
+for freeing the exception object.
+
+<p>
+The SM_TRY and SM_FINALLY macros contain calls to setjmp,
+and consequently, they suffer from the limitations imposed on setjmp
+by the C standard.
+Suppose you declare an auto variable <tt>i</tt> outside of a
+SM_TRY ... SM_END_TRY statement, initializing it to 0.
+Then you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
+setting it to 1.
+If you reference <tt>i</tt> in a different SM_FINALLY clause, or in
+an SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
+will be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.
+
+<blockquote><pre>
+int volatile i = 0;
+
+SM_TRY
+ i = 1;
+ ...
+SM_FINALLY
+ /* the following reference to i only works if i is declared volatile */
+ use(i);
+ ...
+SM_EXCEPT(exc, "*")
+ /* the following reference to i only works if i is declared volatile */
+ use(i);
+ ...
+SM_END_TRY
+</pre></blockquote>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/fclose.c b/contrib/sendmail/libsm/fclose.c
new file mode 100644
index 0000000..c1099f8
--- /dev/null
+++ b/contrib/sendmail/libsm/fclose.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fclose.c,v 1.41 2001/09/11 04:04:48 gshapiro Exp $")
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <setjmp.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/conf.h>
+#include <sm/clock.h>
+#include "local.h"
+
+static jmp_buf CloseTimeOut;
+
+/*
+** CLOSEALRM -- handler when timeout activated for sm_io_close()
+**
+** Returns flow of control to where setjmp(CloseTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(CloseTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+closealrm(sig)
+ int sig;
+{
+ longjmp(CloseTimeOut, 1);
+}
+
+/*
+** SM_IO_CLOSE -- close a file handle/pointer
+**
+** Parameters:
+** fp -- file pointer to be closed
+** timeout -- maximum time allowed to perform the close (millisecs)
+**
+** Returns:
+** 0 on success
+** -1 on failure and sets errno
+**
+** Side Effects:
+** file pointer 'fp' will no longer be valid.
+*/
+
+int
+sm_io_close(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ register int SM_NONVOLATILE r;
+ SM_EVENT *evt = NULL;
+
+ if (fp == NULL)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->sm_magic == NULL)
+ {
+ /* not open! */
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ if (fp->f_close == NULL)
+ {
+ /* no close function! */
+ errno = ENODEV;
+ return SM_IO_EOF;
+ }
+ if (fp->f_dup_cnt > 0)
+ {
+ /* decrement file pointer open count */
+ fp->f_dup_cnt--;
+ return 0;
+ }
+
+ /* Okay, this is where we set the timeout. */
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ /* No more duplicates of file pointer. Flush buffer and close */
+ r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0;
+
+ /* sm_flush() has updated to.it_value for the time it's used */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(CloseTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+ evt = sm_seteventm(timeout, closealrm, 0);
+ }
+ if ((*fp->f_close)(fp) < 0)
+ r = SM_IO_EOF;
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ if (fp->f_flags & SMMBF)
+ {
+ sm_free((char *)fp->f_bf.smb_base);
+ fp->f_bf.smb_base = NULL;
+ }
+ if (HASUB(fp))
+ FREEUB(fp);
+ if (HASLB(fp))
+ FREELB(fp);
+ fp->f_flags = 0; /* clear flags */
+ fp->sm_magic = NULL; /* Release this SM_FILE_T for reuse. */
+ fp->f_r = fp->f_w = 0; /* Mess up if reaccessed. */
+ return r;
+}
diff --git a/contrib/sendmail/libsm/feof.c b/contrib/sendmail/libsm/feof.c
new file mode 100644
index 0000000..8d5e0d8
--- /dev/null
+++ b/contrib/sendmail/libsm/feof.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: feof.c,v 1.13 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_EOF -- subroutine version of the macro sm_io_eof.
+**
+** Tests if the file for 'fp' has reached the end.
+**
+** Parameters:
+** fp -- file pointer.
+**
+** Returns:
+** 0 (zero) when the file is not at end
+** non-zero when EOF has been found
+*/
+#undef sm_io_eof
+
+int
+sm_io_eof(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ return sm_eof(fp);
+}
diff --git a/contrib/sendmail/libsm/ferror.c b/contrib/sendmail/libsm/ferror.c
new file mode 100644
index 0000000..9487479
--- /dev/null
+++ b/contrib/sendmail/libsm/ferror.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: ferror.c,v 1.13 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_ERROR -- subroutine version of the macro sm_io_error.
+**
+** Parameters:
+** fp -- file pointer
+**
+** Returns:
+** 0 (zero) when 'fp' is not in an error state
+** non-zero when 'fp' is in an error state
+*/
+
+#undef sm_io_error
+
+int
+sm_io_error(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ return sm_error(fp);
+}
diff --git a/contrib/sendmail/libsm/fflush.c b/contrib/sendmail/libsm/fflush.c
new file mode 100644
index 0000000..83b318e
--- /dev/null
+++ b/contrib/sendmail/libsm/fflush.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fflush.c,v 1.43 2001/09/11 04:04:48 gshapiro Exp $")
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/setjmp.h>
+#include "local.h"
+#include <sm/conf.h>
+
+/*
+** SM_IO_FLUSH -- flush the buffer for a 'fp' to the "file"
+**
+** Flush a single file. We don't allow this function to flush
+** all open files when fp==NULL any longer.
+**
+** Parameters:
+** fp -- the file pointer buffer to flush
+** timeout -- time to complete the flush
+**
+** Results:
+** Failure: SM_IO_EOF and sets errno
+** Success: 0 (zero)
+*/
+
+int
+sm_io_flush(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ int fd;
+ struct timeval to;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if ((fp->f_flags & (SMWR | SMRW)) == 0)
+ {
+ /*
+ ** The file is not opened for writing, so it cannot be flushed
+ ** (writable means SMWR [write] or SMRW [read/write].
+ */
+
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ /* Now do the flush */
+ return sm_flush(fp, (int *) &timeout);
+}
+
+/*
+** SM_FLUSH -- perform the actual flush
+**
+** Assumes that 'fp' has been validated before this function called.
+**
+** Parameters:
+** fp -- file pointer to be flushed
+** timeout -- max time allowed for flush (milliseconds)
+**
+** Results:
+** Success: 0 (zero)
+** Failure: SM_IO_EOF and errno set
+**
+** Side Effects:
+** timeout will get updated with the time remaining (if any)
+*/
+
+int
+sm_flush(fp, timeout)
+ register SM_FILE_T *fp;
+ int *timeout;
+{
+ register unsigned char *p;
+ register int n, t;
+ int fd;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ t = fp->f_flags;
+ if ((t & SMWR) == 0)
+ return 0;
+
+ if (t & SMSTR)
+ {
+ *fp->f_p = '\0';
+ return 0;
+ }
+
+ if ((p = fp->f_bf.smb_base) == NULL)
+ return 0;
+
+ n = fp->f_p - p; /* write this much */
+
+ if ((fd = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1)
+ {
+ /* can't get an fd, likely internal 'fake' fp */
+ errno = 0;
+ fd = -1;
+ }
+
+ /*
+ ** Set these immediately to avoid problems with longjmp and to allow
+ ** exchange buffering (via setvbuf) in user write function.
+ */
+
+ fp->f_p = p;
+ fp->f_w = t & (SMLBF|SMNBF) ? 0 : fp->f_bf.smb_size; /* implies SMFBF */
+
+ for (; n > 0; n -= t, p += t)
+ {
+ errno = 0; /* needed to ensure EOF correctly found */
+
+ /* Call the file type's write function */
+ t = (*fp->f_write)(fp, (char *)p, n);
+ if (t <= 0)
+ {
+ if (t == 0 && errno == 0)
+ break; /* EOF found */
+
+ if (IS_IO_ERROR(fd, t, *timeout))
+ {
+ fp->f_flags |= SMERR;
+
+ /* errno set by fp->f_write */
+ return SM_IO_EOF;
+ }
+ SM_IO_WR_TIMEOUT(fp, fd, *timeout);
+ }
+ }
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/fget.c b/contrib/sendmail/libsm/fget.c
new file mode 100644
index 0000000..611748c
--- /dev/null
+++ b/contrib/sendmail/libsm/fget.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fget.c,v 1.24 2001/09/11 04:04:48 gshapiro Exp $")
+#include <stdlib.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_FGETS -- get a string from a file
+**
+** Read at most n-1 characters from the given file.
+** Stop when a newline has been read, or the count ('n') runs out.
+**
+** Parameters:
+** fp -- the file to read from
+** timeout -- time to complete reading the string in milliseconds
+** buf -- buffer to place read string in
+** n -- size of 'buf'
+**
+** Returns:
+** success: returns value of 'buf'
+** failure: NULL (no characters were read)
+** timeout: NULL and errno set to EAGAIN
+**
+** Side Effects:
+** may move the file pointer
+*/
+
+char *
+sm_io_fgets(fp, timeout, buf, n)
+ register SM_FILE_T *fp;
+ int timeout;
+ char *buf;
+ register int n;
+{
+ register int len;
+ register char *s;
+ register unsigned char *p, *t;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (n <= 0) /* sanity check */
+ return NULL;
+
+ s = buf;
+ n--; /* leave space for NUL */
+ while (n > 0)
+ {
+ /* If the buffer is empty, refill it. */
+ if ((len = fp->f_r) <= 0)
+ {
+
+ /*
+ ** Timeout is only passed if we can't get the data
+ ** from the buffer (which is counted as immediately).
+ */
+
+ if (sm_refill(fp, timeout) != 0)
+ {
+ /* EOF/error: stop with partial or no line */
+ if (s == buf)
+ return NULL;
+ break;
+ }
+ len = fp->f_r;
+ }
+ p = fp->f_p;
+
+ /*
+ ** Scan through at most n bytes of the current buffer,
+ ** looking for '\n'. If found, copy up to and including
+ ** newline, and stop. Otherwise, copy entire chunk
+ ** and loop.
+ */
+
+ if (len > n)
+ len = n;
+ t = (unsigned char *) memchr((void *) p, '\n', len);
+ if (t != NULL)
+ {
+ len = ++t - p;
+ fp->f_r -= len;
+ fp->f_p = t;
+ (void) memcpy((void *) s, (void *) p, len);
+ s[len] = 0;
+ return buf;
+ }
+ fp->f_r -= len;
+ fp->f_p += len;
+ (void) memcpy((void *) s, (void *) p, len);
+ s += len;
+ n -= len;
+ }
+ *s = 0;
+ return buf;
+}
diff --git a/contrib/sendmail/libsm/findfp.c b/contrib/sendmail/libsm/findfp.c
new file mode 100644
index 0000000..a2ec20c
--- /dev/null
+++ b/contrib/sendmail/libsm/findfp.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: findfp.c,v 1.62 2002/01/11 16:33:03 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "glue.h"
+
+bool Sm_IO_DidInit; /* IO system has been initialized? */
+
+const char SmFileMagic[] = "sm_file";
+
+/* An open type to map to fopen()-like behavior */
+SM_FILE_T SmFtStdio_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
+ sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "stdio" };
+
+/* An open type to map to fdopen()-like behavior */
+SM_FILE_T SmFtStdiofd_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
+ sm_stdfdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "stdiofd" };
+
+/* A string file type */
+SM_FILE_T _SmFtString_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
+ sm_strclose, sm_strread, sm_strseek, sm_strwrite,
+ sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "string" };
+
+#if 0
+/* A file type for syslog communications */
+SM_FILE_T SmFtSyslog_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
+ sm_syslogclose, sm_syslogread, sm_syslogseek, sm_syslogwrite,
+ sm_syslogopen, sm_syslogsetinfo, sm_sysloggetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "syslog" };
+#endif /* 0 */
+
+#define NDYNAMIC 10 /* add ten more whenever necessary */
+
+#define smio(flags, file, name) \
+ {SmFileMagic, 0, 0, 0, flags, file, {0}, 0, SmIoF+file, 0, \
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite, \
+ sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER, \
+ SM_TIME_BLOCK, name}
+
+/* sm_magic p r w flags file bf lbfsize cookie ival */
+#define smstd(flags, file, name) \
+ {SmFileMagic, 0, 0, 0, flags, -1, {0}, 0, 0, file, \
+ sm_stdioclose, sm_stdioread, sm_stdioseek, sm_stdiowrite, \
+ sm_stdioopen, sm_stdiosetinfo, sm_stdiogetinfo, SM_TIME_FOREVER,\
+ SM_TIME_BLOCK, name}
+
+/* A file type for interfacing to stdio FILE* streams. */
+SM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio");
+
+ /* the usual - (stdin + stdout + stderr) */
+static SM_FILE_T usual[SM_IO_OPEN_MAX - 3];
+static struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual };
+
+/* List of builtin automagically already open file pointers */
+SM_FILE_T SmIoF[6] =
+{
+ smio(SMRD|SMLBF, SMIOIN_FILENO, "smioin"), /* smioin */
+ smio(SMWR|SMLBF, SMIOOUT_FILENO, "smioout"), /* smioout */
+ smio(SMWR|SMNBF, SMIOERR_FILENO, "smioerr"), /* smioerr */
+ smstd(SMRD|SMNBF, SMIOIN_FILENO, "smiostdin"), /* smiostdin */
+ smstd(SMWR|SMNBF, SMIOOUT_FILENO, "smiostdout"),/* smiostdout */
+ smstd(SMWR|SMNBF, SMIOERR_FILENO, "smiostderr") /* smiostderr */
+};
+
+/* Structure containing list of currently open file pointers */
+struct sm_glue smglue = { &smuglue, 3, SmIoF };
+
+/*
+** SM_MOREGLUE -- adds more space for open file pointers
+**
+** Parameters:
+** n -- number of new spaces for file pointers
+**
+** Returns:
+** Raises an exception if no more memory.
+** Otherwise, returns a pointer to new spaces.
+*/
+
+static struct sm_glue *sm_moreglue_x __P((int));
+static SM_FILE_T empty;
+
+static struct sm_glue *
+sm_moreglue_x(n)
+ register int n;
+{
+ register struct sm_glue *g;
+ register SM_FILE_T *p;
+
+ g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + ALIGNBYTES +
+ n * sizeof(SM_FILE_T));
+ p = (SM_FILE_T *) ALIGN(g + 1);
+ g->gl_next = NULL;
+ g->gl_niobs = n;
+ g->gl_iobs = p;
+ while (--n >= 0)
+ *p++ = empty;
+ return g;
+}
+
+/*
+** SM_FP -- allocate and initialize an SM_FILE structure
+**
+** Parameters:
+** t -- file type requested to be opened.
+** flags -- control flags for file type behavior
+** oldfp -- file pointer to reuse if available (optional)
+**
+** Returns:
+** Raises exception on memory exhaustion.
+** Aborts if type is invalid.
+** Otherwise, returns file pointer for requested file type.
+*/
+
+SM_FILE_T *
+sm_fp(t, flags, oldfp)
+ const SM_FILE_T *t;
+ const int flags;
+ SM_FILE_T *oldfp;
+{
+ register SM_FILE_T *fp;
+ register int n;
+ register struct sm_glue *g;
+
+ SM_REQUIRE(t->f_open && t->f_close && (t->f_read || t->f_write));
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ if (oldfp != NULL)
+ {
+ fp = oldfp;
+ goto found; /* for opening reusing an 'fp' */
+ }
+
+ for (g = &smglue;; g = g->gl_next)
+ {
+ for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++)
+ if (fp->sm_magic == NULL)
+ goto found;
+ if (g->gl_next == NULL)
+ g->gl_next = sm_moreglue_x(NDYNAMIC);
+ }
+found:
+ fp->sm_magic = SmFileMagic; /* 'fp' now valid and in-use */
+ fp->f_p = NULL; /* no current pointer */
+ fp->f_w = 0; /* nothing to write */
+ fp->f_r = 0; /* nothing to read */
+ fp->f_flags = flags;
+ fp->f_file = -1; /* no file */
+ fp->f_bf.smb_base = NULL; /* no buffer */
+ fp->f_bf.smb_size = 0; /* no buffer size with no buffer */
+ fp->f_lbfsize = 0; /* not line buffered */
+ fp->f_flushfp = NULL; /* no associated flush file */
+
+ fp->f_cookie = fp; /* default: *open* overrides cookie setting */
+ fp->f_close = t->f_close; /* assign close function */
+ fp->f_read = t->f_read; /* assign read function */
+ fp->f_seek = t->f_seek; /* assign seek function */
+ fp->f_write = t->f_write; /* assign write function */
+ fp->f_open = t->f_open; /* assign open function */
+ fp->f_setinfo = t->f_setinfo; /* assign setinfo function */
+ fp->f_getinfo = t->f_getinfo; /* assign getinfo function */
+ fp->f_type = t->f_type; /* file type */
+ fp->f_self = fp; /* self reference for future use */
+
+ fp->f_ub.smb_base = NULL; /* no ungetc buffer */
+ fp->f_ub.smb_size = 0; /* no size for no ungetc buffer */
+
+ fp->f_lb.smb_base = NULL; /* no line buffer */
+ fp->f_lb.smb_size = 0; /* no size for no line buffer */
+ if (fp->f_timeout == SM_TIME_DEFAULT)
+ fp->f_timeout = SM_TIME_FOREVER;
+ else
+ fp->f_timeout = t->f_timeout; /* traditional behavior */
+ fp->f_timeoutstate = SM_TIME_BLOCK; /* by default */
+
+ return fp;
+}
+
+/*
+** SM_CLEANUP -- cleanup function when exit called.
+**
+** This function is registered via atexit().
+**
+** Parameters:
+** none
+**
+** Returns:
+** nothing.
+**
+** Side Effects:
+** flushes open files before they are forced closed
+*/
+
+void
+sm_cleanup()
+{
+ int timeout = SM_TIME_DEFAULT;
+
+ (void) sm_fwalk(sm_flush, &timeout); /* `cheating' */
+}
+
+/*
+** SM_INIT -- called whenever sm_io's internal variables must be set up.
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Registers sm_cleanup() using atexit().
+*/
+
+void
+sm_init()
+{
+ if (Sm_IO_DidInit) /* paranoia */
+ return;
+
+ /* more paranoia: initialize pointers in a static variable */
+ empty.f_type = NULL;
+ empty.sm_magic = NULL;
+
+ /* make sure we clean up on exit */
+ atexit(sm_cleanup); /* conservative */
+ Sm_IO_DidInit = true;
+}
+
+/*
+** SM_IO_SETINFO -- change info for an open file type (fp)
+**
+** The generic SM_IO_WHAT_VECTORS is auto supplied for all file types.
+** If the request is to set info other than SM_IO_WHAT_VECTORS then
+** the request is passed on to the file type's specific setinfo vector.
+** WARNING: this is working on an active/open file type.
+**
+** Parameters:
+** fp -- file to make the setting on
+** what -- type of information to set
+** valp -- structure to obtain info from
+**
+** Returns:
+** 0 on success
+** -1 on error and sets errno:
+** - when what != SM_IO_WHAT_VECTORS and setinfo vector
+** not set
+** - when vectored setinfo returns -1
+*/
+
+int
+sm_io_setinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ SM_FILE_T *v = (SM_FILE_T *) valp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ switch (what)
+ {
+ case SM_IO_WHAT_VECTORS:
+
+ /*
+ ** This is the "generic" available for all.
+ ** This allows the function vectors to be replaced
+ ** while the file type is active.
+ */
+
+ fp->f_close = v->f_close;
+ fp->f_read = v->f_read;
+ fp->f_seek = v->f_seek;
+ fp->f_write = v->f_write;
+ fp->f_open = v->f_open;
+ fp->f_setinfo = v->f_setinfo;
+ fp->f_getinfo = v->f_getinfo;
+ sm_free(fp->f_type);
+ fp->f_type = sm_strdup_x(v->f_type);
+ return 0;
+ case SM_IO_WHAT_TIMEOUT:
+ fp->f_timeout = *((int *)valp);
+ return 0;
+ }
+
+ /* Otherwise the vector will check it out */
+ if (fp->f_setinfo == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else
+ return (*fp->f_setinfo)(fp, what, valp);
+}
+
+/*
+** SM_IO_GETINFO -- get information for an active file type (fp)
+**
+** This function supplies for all file types the answers for the
+** three requests SM_IO_WHAT_VECTORS, SM_IO_WHAT_TYPE and
+** SM_IO_WHAT_ISTYPE. Other requests are handled by the getinfo
+** vector if available for the open file type.
+** SM_IO_WHAT_VECTORS returns information for the file pointer vectors.
+** SM_IO_WHAT_TYPE returns the type identifier for the file pointer
+** SM_IO_WHAT_ISTYPE returns >0 if the passed in type matches the
+** file pointer's type.
+** SM_IO_IS_READABLE returns 1 if there is data available for reading,
+** 0 otherwise.
+**
+** Parameters:
+** fp -- file pointer for active file type
+** what -- type of information request
+** valp -- structure to place obtained info into
+**
+** Returns:
+** -1 on error and sets errno:
+** - when valp==NULL and request expects otherwise
+** - when request is not SM_IO_WHAT_VECTORS and not
+** SM_IO_WHAT_TYPE and not SM_IO_WHAT_ISTYPE
+** and getinfo vector is NULL
+** - when getinfo type vector returns -1
+** >=0 on success
+*/
+
+int
+sm_io_getinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ SM_FILE_T *v = (SM_FILE_T *) valp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ switch (what)
+ {
+ case SM_IO_WHAT_VECTORS:
+
+ /* This is the "generic" available for all */
+ v->f_close = fp->f_close;
+ v->f_read = fp->f_read;
+ v->f_seek = fp->f_seek;
+ v->f_write = fp->f_write;
+ v->f_open = fp->f_open;
+ v->f_setinfo = fp->f_setinfo;
+ v->f_getinfo = fp->f_getinfo;
+ v->f_type = fp->f_type;
+ return 0;
+
+ case SM_IO_WHAT_TYPE:
+ if (valp == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ valp = sm_strdup_x(fp->f_type);
+ return 0;
+
+ case SM_IO_WHAT_ISTYPE:
+ if (valp == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return strcmp(fp->f_type, valp) == 0;
+
+ case SM_IO_IS_READABLE:
+
+ /* if there is data in the buffer, it must be readable */
+ if (fp->f_r > 0)
+ return 1;
+
+ /* otherwise query the underlying file */
+ break;
+
+ case SM_IO_WHAT_TIMEOUT:
+ *((int *) valp) = fp->f_timeout;
+ return 0;
+
+ case SM_IO_WHAT_FD:
+ if (fp->f_file > -1)
+ return fp->f_file;
+
+ /* try the file type specific getinfo to see if it knows */
+ break;
+ }
+
+ /* Otherwise the vector will check it out */
+ if (fp->f_getinfo == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return (*fp->f_getinfo)(fp, what, valp);
+}
diff --git a/contrib/sendmail/libsm/flags.c b/contrib/sendmail/libsm/flags.c
new file mode 100644
index 0000000..b3877f1
--- /dev/null
+++ b/contrib/sendmail/libsm/flags.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: flags.c,v 1.20 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sys/types.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <sm/io.h>
+
+/*
+** SM_FLAGS -- translate external (user) flags into internal flags
+**
+** Paramters:
+** flags -- user select flags
+**
+** Returns:
+** Internal flag value matching user selected flags
+*/
+
+int
+sm_flags(flags)
+ register int flags;
+{
+ register int ret;
+
+ switch(flags)
+ {
+ case SM_IO_RDONLY: /* open for reading */
+ ret = SMRD;
+ break;
+
+ case SM_IO_WRONLY: /* open for writing */
+ ret = SMWR;
+ break;
+
+ case SM_IO_APPEND: /* open for appending */
+ ret = SMWR;
+ break;
+
+ case SM_IO_RDWR: /* open for read and write */
+ ret = SMRW;
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/fopen.c b/contrib/sendmail/libsm/fopen.c
new file mode 100644
index 0000000..a2fae9d
--- /dev/null
+++ b/contrib/sendmail/libsm/fopen.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fopen.c,v 1.60 2002/01/07 21:41:35 ca Exp $")
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include <sm/clock.h>
+#include "local.h"
+
+extern int sm_io_fclose __P((SM_FILE_T *));
+
+static jmp_buf OpenTimeOut, ReopenTimeOut;
+
+/*
+** OPENALRM -- handler when timeout activated for sm_io_open()
+**
+** Returns flow of control to where setjmp(OpenTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(OpenTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+openalrm(sig)
+ int sig;
+{
+ longjmp(OpenTimeOut, 1);
+}
+/*
+** REOPENALRM -- handler when timeout activated for sm_io_reopen()
+**
+** Returns flow of control to where setjmp(ReopenTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(ReopenTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+reopenalrm(sig)
+ int sig;
+{
+ longjmp(ReopenTimeOut, 1);
+}
+
+/*
+** SM_IO_OPEN -- open a file of a specific type
+**
+** Parameters:
+** type -- type of file to open
+** timeout -- time to complete the open
+** info -- info describing what is to be opened (type dependant)
+** flags -- user selected flags
+** rpool -- pointer to rpool to be used for this open
+**
+** Returns:
+** Raises exception on heap exhaustion.
+** Aborts if type is invalid.
+** Returns NULL and sets errno
+** - when the type specific open fails
+** - when open vector errors
+** - when flags not set or invalid
+** Success returns a file pointer to the opened file type.
+*/
+
+SM_FILE_T *
+sm_io_open(type, timeout, info, flags, rpool)
+ const SM_FILE_T *type;
+ int SM_NONVOLATILE timeout; /* this is not the file type timeout */
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register SM_FILE_T *fp;
+ int ioflags;
+ SM_EVENT *evt = NULL;
+
+ ioflags = sm_flags(flags);
+
+ if (ioflags == 0)
+ {
+ /* must give some indication/intent */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = SM_TIME_FOREVER;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+
+ fp = sm_fp(type, ioflags, NULL);
+
+ /* Okay, this is where we set the timeout. */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(OpenTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+ evt = sm_seteventm(timeout, openalrm, 0);
+ }
+
+ if ((*fp->f_open)(fp, info, flags, rpool) < 0)
+ {
+ fp->f_flags = 0; /* release */
+ fp->sm_magic = NULL; /* release */
+ return NULL;
+ }
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+
+#if SM_RPOOL
+ if (rpool != NULL)
+ sm_rpool_attach_x(rpool, sm_io_fclose, fp);
+#endif /* SM_RPOOL */
+
+ return fp;
+}
+/*
+** SM_IO_DUP -- duplicate a file pointer
+**
+** Parameters:
+** fp -- file pointer to duplicate
+**
+** Returns:
+** Success - the duplicated file pointer
+** Failure - NULL (was an invalid file pointer or too many open)
+**
+** Increments the duplicate counter (dup_cnt) for the open file pointer.
+** The counter counts the number of duplicates. When the duplicate
+** counter is 0 (zero) then the file pointer is the only one left
+** (no duplicates, it is the only one).
+*/
+
+SM_FILE_T *
+sm_io_dup(fp)
+ SM_FILE_T *fp;
+{
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp->sm_magic != SmFileMagic)
+ {
+ errno = EBADF;
+ return NULL;
+ }
+ if (fp->f_dup_cnt >= INT_MAX - 1)
+ {
+ /* Can't let f_dup_cnt wrap! */
+ errno = EMFILE;
+ return NULL;
+ }
+ fp->f_dup_cnt++;
+ return fp;
+}
+/*
+** SM_IO_REOPEN -- open a new file using the old file pointer
+**
+** Parameters:
+** type -- file type to be opened
+** timeout -- time to complete the reopen
+** info -- infomation about what is to be "re-opened" (type dep.)
+** flags -- user flags to map to internal flags
+** rpool -- rpool file to be associated with
+** fp -- the file pointer to reuse
+**
+** Returns:
+** Raises an exception on heap exhaustion.
+** Aborts if type is invalid.
+** Failure: returns NULL
+** Success: returns "reopened" file pointer
+*/
+
+SM_FILE_T *
+sm_io_reopen(type, timeout, info, flags, rpool, fp)
+ const SM_FILE_T *type;
+ int SM_NONVOLATILE timeout;
+ const void *info;
+ int flags;
+ const void *rpool;
+ SM_FILE_T *fp;
+{
+ int ioflags, ret;
+ SM_FILE_T *fp2;
+ SM_EVENT *evt = NULL;
+
+ if ((ioflags = sm_flags(flags)) == 0)
+ {
+ (void) sm_io_close(fp, timeout);
+ return NULL;
+ }
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = SM_TIME_FOREVER;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return NULL;
+ }
+ /* Okay, this is where we set the timeout. */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(ReopenTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+
+ evt = sm_seteventm(timeout, reopenalrm, 0);
+ }
+
+ /*
+ ** There are actually programs that depend on being able to "reopen"
+ ** descriptors that weren't originally open. Keep this from breaking.
+ ** Remember whether the stream was open to begin with, and which file
+ ** descriptor (if any) was associated with it. If it was attached to
+ ** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin)
+ ** should work. This is unnecessary if it was not a Unix file.
+ */
+
+ if (fp != NULL)
+ {
+ if (fp->sm_magic != SmFileMagic)
+ fp->f_flags = SMFEOF; /* hold on to it */
+ else
+ {
+ /* flush the stream; ANSI doesn't require this. */
+ (void) sm_io_flush(fp, SM_TIME_FOREVER);
+ (void) sm_io_close(fp, SM_TIME_FOREVER);
+ }
+ }
+
+ fp2 = sm_fp(type, ioflags, fp);
+ ret = (*fp2->f_open)(fp2, info, flags, rpool);
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+
+ if (ret < 0)
+ {
+ fp2->f_flags = 0; /* release */
+ fp2->sm_magic = NULL; /* release */
+ return NULL;
+ }
+
+ /*
+ ** We're not preserving this logic (below) for sm_io because it is now
+ ** abstracted at least one "layer" away. By closing and reopening
+ ** the 1st fd used should be the just released one (when Unix
+ ** behavior followed). Old comment::
+ ** If reopening something that was open before on a real file, try
+ ** to maintain the descriptor. Various C library routines (perror)
+ ** assume stderr is always fd STDERR_FILENO, even if being reopen'd.
+ */
+
+#if SM_RPOOL
+ if (rpool != NULL)
+ sm_rpool_attach_x(rpool, sm_io_close, fp2);
+#endif /* SM_RPOOL */
+
+ return fp2;
+}
+/*
+** SM_IO_AUTOFLUSH -- link another file to this for auto-flushing
+**
+** When a read occurs on fp, fp2 will be flushed iff there is no
+** data waiting on fp.
+**
+** Parameters:
+** fp -- the file opened for reading.
+** fp2 -- the file opened for writing.
+**
+** Returns:
+** The old flush file pointer.
+*/
+
+SM_FILE_T *
+sm_io_autoflush(fp, fp2)
+ SM_FILE_T *fp;
+ SM_FILE_T *fp2;
+{
+ SM_FILE_T *savefp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp2 != NULL)
+ SM_REQUIRE_ISA(fp2, SmFileMagic);
+
+ savefp = fp->f_flushfp;
+ fp->f_flushfp = fp2;
+ return savefp;
+}
+/*
+** SM_IO_AUTOMODE -- link another file to this for auto-moding
+**
+** When the mode (blocking or non-blocking) changes for fp1 then
+** update fp2's mode at the same time. This is to be used when
+** a system dup() has generated a second file descriptor for
+** another sm_io_open() by file descriptor. The modes have been
+** linked in the system and this formalizes it for sm_io internally.
+**
+** Parameters:
+** fp1 -- the first file
+** fp2 -- the second file
+**
+** Returns:
+** nothing
+*/
+
+void
+sm_io_automode(fp1, fp2)
+ SM_FILE_T *fp1;
+ SM_FILE_T *fp2;
+{
+ SM_REQUIRE_ISA(fp1, SmFileMagic);
+ SM_REQUIRE_ISA(fp2, SmFileMagic);
+
+ fp1->f_modefp = fp2;
+ fp2->f_modefp = fp1;
+}
diff --git a/contrib/sendmail/libsm/fpos.c b/contrib/sendmail/libsm/fpos.c
new file mode 100644
index 0000000..a8083fd
--- /dev/null
+++ b/contrib/sendmail/libsm/fpos.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fpos.c,v 1.37 2001/09/11 04:04:48 gshapiro Exp $")
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/clock.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+static jmp_buf TellTimeOut;
+
+/*
+** TELLALRM -- handler when timeout activated for sm_io_tell()
+**
+** Returns flow of control to where setjmp(TellTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(TellTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+tellalrm(sig)
+ int sig;
+{
+ longjmp(TellTimeOut, 1);
+}
+
+/*
+** SM_IO_TELL -- position the file pointer
+**
+** Paramters:
+** fp -- the file pointer to get repositioned
+** timeout -- time to complete the tell (milliseconds)
+**
+** Returns:
+** Success -- the repositioned location.
+** Failure -- -1 (minus 1) and sets errno
+*/
+
+long
+sm_io_tell(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ register off_t pos;
+ SM_EVENT *evt = NULL;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp->f_seek == NULL)
+ {
+ errno = ESPIPE; /* historic practice */
+ return -1L;
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return -1L;
+ }
+
+ /*
+ ** Find offset of underlying I/O object, then adjust byte position
+ ** may adjust seek offset on append stream
+ */
+
+ (void) sm_flush(fp, (int *) &timeout);
+
+ /* This is where we start the timeout */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(TellTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return -1L;
+ }
+
+ evt = sm_seteventm(timeout, tellalrm, 0);
+ }
+
+ if (fp->f_flags & SMOFF)
+ pos = fp->f_lseekoff;
+ else
+ {
+ /* XXX only set the timeout here? */
+ pos = (*fp->f_seek)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (pos == -1L)
+ goto clean;
+ }
+ if (fp->f_flags & SMRD)
+ {
+ /*
+ ** Reading. Any unread characters (including
+ ** those from ungetc) cause the position to be
+ ** smaller than that in the underlying object.
+ */
+
+ pos -= fp->f_r;
+ if (HASUB(fp))
+ pos -= fp->f_ur;
+ }
+ else if (fp->f_flags & SMWR && fp->f_p != NULL)
+ {
+ /*
+ ** Writing. Any buffered characters cause the
+ ** position to be greater than that in the
+ ** underlying object.
+ */
+
+ pos += fp->f_p - fp->f_bf.smb_base;
+ }
+
+clean:
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ return pos;
+}
diff --git a/contrib/sendmail/libsm/fprintf.c b/contrib/sendmail/libsm/fprintf.c
new file mode 100644
index 0000000..7193872
--- /dev/null
+++ b/contrib/sendmail/libsm/fprintf.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fprintf.c,v 1.17 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_FPRINTF -- format and print a string to a file pointer
+**
+** Parameters:
+** fp -- file pointer to be printed to
+** timeout -- time to complete print
+** fmt -- markup format for the string to be printed
+** ... -- additional information for 'fmt'
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns the number of characters o/p
+*/
+
+int
+#if SM_VA_STD
+sm_io_fprintf(SM_FILE_T *fp, int timeout, const char *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_fprintf(fp, timeout, fmt, va_alist)
+ SM_FILE_T *fp;
+ int timeout;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ SM_VA_START(ap, fmt);
+ ret = sm_io_vfprintf(fp, timeout, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/fpurge.c b/contrib/sendmail/libsm/fpurge.c
new file mode 100644
index 0000000..4e6fd5a
--- /dev/null
+++ b/contrib/sendmail/libsm/fpurge.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fpurge.c,v 1.20 2001/09/11 04:04:48 gshapiro Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_PURGE -- purge/empty the buffer without committing buffer content
+**
+** Parameters:
+** fp -- file pointer to purge
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_purge(fp)
+ register SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (!fp->f_flags)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_p = fp->f_bf.smb_base;
+ fp->f_r = 0;
+
+ /* implies SMFBF */
+ fp->f_w = fp->f_flags & (SMLBF|SMNBF) ? 0 : fp->f_bf.smb_size;
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/fput.c b/contrib/sendmail/libsm/fput.c
new file mode 100644
index 0000000..3c5e11c
--- /dev/null
+++ b/contrib/sendmail/libsm/fput.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fput.c,v 1.20 2001/09/11 04:04:48 gshapiro Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_FPUTS -- add a string to the buffer for the file pointer
+**
+** Parameters:
+** fp -- the file pointer for the buffer to be written to
+** timeout -- time to complete the put-string
+** s -- string to be placed in the buffer
+**
+** Returns:
+** Failure: returns SM_IO_EOF
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_fputs(fp, timeout, s)
+ SM_FILE_T *fp;
+ int timeout;
+ const char *s;
+{
+ struct sm_uio uio;
+ struct sm_iov iov;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ iov.iov_base = (void *) s;
+ iov.iov_len = uio.uio_resid = strlen(s);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ return sm_fvwrite(fp, timeout, &uio);
+}
diff --git a/contrib/sendmail/libsm/fread.c b/contrib/sendmail/libsm/fread.c
new file mode 100644
index 0000000..1e651fd
--- /dev/null
+++ b/contrib/sendmail/libsm/fread.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fread.c,v 1.28 2001/09/11 04:04:48 gshapiro Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_READ -- read data from the file pointer
+**
+** Parameters:
+** fp -- file pointer to read from
+** timeout -- time to complete the read
+** buf -- location to place read data
+** size -- size of each chunk of data
+**
+** Returns:
+** Failure: returns 0 (zero) _and_ sets errno
+** Success: returns the number of whole chunks read.
+**
+** A read returning 0 (zero) is only an indication of error when errno
+** has been set.
+*/
+
+size_t
+sm_io_read(fp, timeout, buf, size)
+ SM_FILE_T *fp;
+ int timeout;
+ void *buf;
+ size_t size;
+{
+ register size_t resid = size;
+ register char *p;
+ register int r;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->f_read == NULL)
+ {
+ errno = ENODEV;
+ return 0;
+ }
+
+ /*
+ ** The ANSI standard requires a return value of 0 for a count
+ ** or a size of 0. Peculiarily, it imposes no such requirements
+ ** on fwrite; it only requires read to be broken.
+ */
+
+ if (resid == 0)
+ return 0;
+ if (fp->f_r < 0)
+ fp->f_r = 0;
+ p = buf;
+ while ((int) resid > (r = fp->f_r))
+ {
+ (void) memcpy((void *) p, (void *) fp->f_p, (size_t) r);
+ fp->f_p += r;
+ /* fp->f_r = 0 ... done in sm_refill */
+ p += r;
+ resid -= r;
+ if ((fp->f_flags & SMNOW) != 0 && r > 0)
+ {
+ /*
+ ** Take whatever we have available. Spend no more time
+ ** trying to get all that has been requested.
+ ** This is needed on some file types (such as
+ ** SASL) that would jam when given extra, untimely
+ ** reads.
+ */
+
+ fp->f_r -= r;
+ return size - resid;
+ }
+ if (sm_refill(fp, timeout) != 0)
+ {
+ /* no more input: return partial result */
+ return size - resid;
+ }
+ }
+ (void) memcpy((void *) p, (void *) fp->f_p, resid);
+ fp->f_r -= resid;
+ fp->f_p += resid;
+ return size;
+}
diff --git a/contrib/sendmail/libsm/fscanf.c b/contrib/sendmail/libsm/fscanf.c
new file mode 100644
index 0000000..5e1fcfd
--- /dev/null
+++ b/contrib/sendmail/libsm/fscanf.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fscanf.c,v 1.17 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/varargs.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_IO_FSCANF -- convert input data to translated format
+**
+** Parameters:
+** fp -- the file pointer to obtain the data from
+** timeout -- time to complete scan
+** fmt -- the format to translate the data to
+** ... -- memory locations to place the formated data
+**
+** Returns:
+** Failure: returns SM_IO_EOF
+** Success: returns the number of data units translated
+*/
+
+int
+#if SM_VA_STD
+sm_io_fscanf(SM_FILE_T *fp, int timeout, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_fscanf(fp, timeout, fmt, va_alist)
+ SM_FILE_T *fp;
+ int timeout;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ SM_VA_START(ap, fmt);
+ ret = sm_vfscanf(fp, timeout, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/fseek.c b/contrib/sendmail/libsm/fseek.c
new file mode 100644
index 0000000..6985e0d
--- /dev/null
+++ b/contrib/sendmail/libsm/fseek.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fseek.c,v 1.45 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/signal.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/clock.h>
+#include "local.h"
+
+#define POS_ERR (-(off_t)1)
+
+static jmp_buf SeekTimeOut;
+
+/*
+** SEEKALRM -- handler when timeout activated for sm_io_seek()
+**
+** Returns flow of control to where setjmp(SeekTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(SeekTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+seekalrm(sig)
+ int sig;
+{
+ longjmp(SeekTimeOut, 1);
+}
+
+/*
+** SM_IO_SEEK -- position the file pointer
+**
+** Parameters:
+** fp -- the file pointer to be seek'd
+** timeout -- time to complete seek (milliseconds)
+** offset -- seek offset based on 'whence'
+** whence -- indicates where seek is relative from.
+** One of SM_IO_SEEK_{CUR,SET,END}.
+** Returns:
+** Failure: returns -1 (minus 1) and sets errno
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_seek(fp, timeout, offset, whence)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+ long SM_NONVOLATILE offset;
+ int SM_NONVOLATILE whence;
+{
+ bool havepos;
+ off_t target, curoff;
+ size_t n;
+ struct stat st;
+ int ret;
+ SM_EVENT *evt = NULL;
+ register off_t (*seekfn) __P((SM_FILE_T *, off_t, int));
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ /* Have to be able to seek. */
+ if ((seekfn = fp->f_seek) == NULL)
+ {
+ errno = ESPIPE; /* historic practice */
+ return -1;
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return -1;
+ }
+
+#define SM_SET_ALARM() \
+ if (timeout != SM_TIME_FOREVER) \
+ { \
+ if (setjmp(SeekTimeOut) != 0) \
+ { \
+ errno = EAGAIN; \
+ return -1; \
+ } \
+ evt = sm_seteventm(timeout, seekalrm, 0); \
+ }
+
+ /*
+ ** Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence'
+ ** argument. After this, whence is either SM_IO_SEEK_SET or
+ ** SM_IO_SEEK_END.
+ */
+
+ switch (whence)
+ {
+ case SM_IO_SEEK_CUR:
+
+ /*
+ ** In order to seek relative to the current stream offset,
+ ** we have to first find the current stream offset a la
+ ** ftell (see ftell for details).
+ */
+
+ /* may adjust seek offset on append stream */
+ sm_flush(fp, (int *) &timeout);
+ SM_SET_ALARM();
+ if (fp->f_flags & SMOFF)
+ curoff = fp->f_lseekoff;
+ else
+ {
+ curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (curoff == -1L)
+ {
+ ret = -1;
+ goto clean;
+ }
+ }
+ if (fp->f_flags & SMRD)
+ {
+ curoff -= fp->f_r;
+ if (HASUB(fp))
+ curoff -= fp->f_ur;
+ }
+ else if (fp->f_flags & SMWR && fp->f_p != NULL)
+ curoff += fp->f_p - fp->f_bf.smb_base;
+
+ offset += curoff;
+ whence = SM_IO_SEEK_SET;
+ havepos = true;
+ break;
+
+ case SM_IO_SEEK_SET:
+ case SM_IO_SEEK_END:
+ SM_SET_ALARM();
+ curoff = 0; /* XXX just to keep gcc quiet */
+ havepos = false;
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ ** Can only optimise if:
+ ** reading (and not reading-and-writing);
+ ** not unbuffered; and
+ ** this is a `regular' Unix file (and hence seekfn==sm_stdseek).
+ ** We must check SMNBF first, because it is possible to have SMNBF
+ ** and SMSOPT both set.
+ */
+
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+ if (fp->f_flags & (SMWR | SMRW | SMNBF | SMNPT))
+ goto dumb;
+ if ((fp->f_flags & SMOPT) == 0)
+ {
+ if (seekfn != sm_stdseek ||
+ fp->f_file < 0 || fstat(fp->f_file, &st) ||
+ (st.st_mode & S_IFMT) != S_IFREG)
+ {
+ fp->f_flags |= SMNPT;
+ goto dumb;
+ }
+ fp->f_blksize = st.st_blksize;
+ fp->f_flags |= SMOPT;
+ }
+
+ /*
+ ** We are reading; we can try to optimise.
+ ** Figure out where we are going and where we are now.
+ */
+
+ if (whence == SM_IO_SEEK_SET)
+ target = offset;
+ else
+ {
+ if (fstat(fp->f_file, &st))
+ goto dumb;
+ target = st.st_size + offset;
+ }
+
+ if (!havepos)
+ {
+ if (fp->f_flags & SMOFF)
+ curoff = fp->f_lseekoff;
+ else
+ {
+ curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (curoff == POS_ERR)
+ goto dumb;
+ }
+ curoff -= fp->f_r;
+ if (HASUB(fp))
+ curoff -= fp->f_ur;
+ }
+
+ /*
+ ** Compute the number of bytes in the input buffer (pretending
+ ** that any ungetc() input has been discarded). Adjust current
+ ** offset backwards by this count so that it represents the
+ ** file offset for the first byte in the current input buffer.
+ */
+
+ if (HASUB(fp))
+ {
+ curoff += fp->f_r; /* kill off ungetc */
+ n = fp->f_up - fp->f_bf.smb_base;
+ curoff -= n;
+ n += fp->f_ur;
+ }
+ else
+ {
+ n = fp->f_p - fp->f_bf.smb_base;
+ curoff -= n;
+ n += fp->f_r;
+ }
+
+ /*
+ ** If the target offset is within the current buffer,
+ ** simply adjust the pointers, clear SMFEOF, undo ungetc(),
+ ** and return. (If the buffer was modified, we have to
+ ** skip this; see getln in fget.c.)
+ */
+
+ if (target >= curoff && target < curoff + (off_t) n)
+ {
+ register int o = target - curoff;
+
+ fp->f_p = fp->f_bf.smb_base + o;
+ fp->f_r = n - o;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~SMFEOF;
+ ret = 0;
+ goto clean;
+ }
+
+ /*
+ ** The place we want to get to is not within the current buffer,
+ ** but we can still be kind to the kernel copyout mechanism.
+ ** By aligning the file offset to a block boundary, we can let
+ ** the kernel use the VM hardware to map pages instead of
+ ** copying bytes laboriously. Using a block boundary also
+ ** ensures that we only read one block, rather than two.
+ */
+
+ curoff = target & ~(fp->f_blksize - 1);
+ if ((*seekfn)(fp, curoff, SM_IO_SEEK_SET) == POS_ERR)
+ goto dumb;
+ fp->f_r = 0;
+ fp->f_p = fp->f_bf.smb_base;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~SMFEOF;
+ n = target - curoff;
+ if (n)
+ {
+ /* Note: SM_TIME_FOREVER since fn timeout already set */
+ if (sm_refill(fp, SM_TIME_FOREVER) || fp->f_r < (int) n)
+ goto dumb;
+ fp->f_p += n;
+ fp->f_r -= n;
+ }
+
+ ret = 0;
+clean:
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ return ret;
+dumb:
+ /*
+ ** We get here if we cannot optimise the seek ... just
+ ** do it. Allow the seek function to change fp->f_bf.smb_base.
+ */
+
+ /* Note: SM_TIME_FOREVER since fn timeout already set */
+ ret = SM_TIME_FOREVER;
+ if (sm_flush(fp, &ret) != 0 ||
+ (*seekfn)(fp, (off_t) offset, whence) == POS_ERR)
+ {
+ ret = -1;
+ goto clean;
+ }
+
+ /* success: clear SMFEOF indicator and discard ungetc() data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_p = fp->f_bf.smb_base;
+ fp->f_r = 0;
+ fp->f_flags &= ~SMFEOF;
+ ret = 0;
+ goto clean;
+}
diff --git a/contrib/sendmail/libsm/fvwrite.c b/contrib/sendmail/libsm/fvwrite.c
new file mode 100644
index 0000000..a692781
--- /dev/null
+++ b/contrib/sendmail/libsm/fvwrite.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/setjmp.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_FVWRITE -- write memory regions and buffer for file pointer
+**
+** Parameters:
+** fp -- the file pointer to write to
+** timeout -- time length for function to return by
+** uio -- the memory regions to write
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0 (zero)
+**
+** This routine is large and unsightly, but most of the ugliness due
+** to the different kinds of output buffering handled here.
+*/
+
+#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
+#define GETIOV(extra_work) \
+ while (len == 0) \
+ { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+
+int
+sm_fvwrite(fp, timeout, uio)
+ register SM_FILE_T *fp;
+ int timeout;
+ register struct sm_uio *uio;
+{
+ register size_t len;
+ register char *p;
+ register struct sm_iov *iov;
+ register int w, s;
+ char *nl;
+ int nlknown, nldist;
+ int fd;
+ struct timeval to;
+
+ if (uio->uio_resid == 0)
+ return 0;
+
+ /* make sure we can write */
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+ if (fp->f_flags & SMNBF)
+ {
+ /* Unbuffered: write up to BUFSIZ bytes at a time. */
+ do
+ {
+ GETIOV(;);
+ errno = 0; /* needed to ensure EOF correctly found */
+ w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ else
+ {
+ p += w;
+ len -= w;
+ }
+ } while ((uio->uio_resid -= w) != 0);
+ }
+ else if ((fp->f_flags & SMLBF) == 0)
+ {
+ /*
+ ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
+ ** buffered: fill partially full buffer, if any,
+ ** and then flush. If there is no partial buffer, write
+ ** one bf._size byte chunk directly (without copying).
+ **
+ ** String output is a special case: write as many bytes
+ ** as fit, but pretend we wrote everything. This makes
+ ** snprintf() return the number of bytes needed, rather
+ ** than the number used, and avoids its write function
+ ** (so that the write function can be invalid).
+ */
+
+ do
+ {
+ GETIOV(;);
+ if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
+ || ((fp->f_flags & SMNOW) != 0))
+ && (size_t) fp->f_w < len)
+ {
+ size_t blen = fp->f_p - fp->f_bf.smb_base;
+ unsigned char *tbase;
+ int tsize;
+
+ /* Allocate space exponentially. */
+ tsize = fp->f_bf.smb_size;
+ do
+ {
+ tsize = (tsize << 1) + 1;
+ } while ((size_t) tsize < blen + len);
+ tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base,
+ tsize + 1);
+ if (tbase == NULL)
+ {
+ errno = ENOMEM;
+ goto err; /* errno set */
+ }
+ fp->f_w += tsize - fp->f_bf.smb_size;
+ fp->f_bf.smb_base = tbase;
+ fp->f_bf.smb_size = tsize;
+ fp->f_p = tbase + blen;
+ }
+ w = fp->f_w;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_flags & SMSTR)
+ {
+ if (len < (size_t) w)
+ w = len;
+ COPY(w); /* copy SM_MIN(fp->f_w,len), */
+ fp->f_w -= w;
+ fp->f_p += w;
+ w = len; /* but pretend copied all */
+ }
+ else if (fp->f_p > fp->f_bf.smb_base
+ && len > (size_t) w)
+ {
+ /* fill and flush */
+ COPY(w);
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (len >= (size_t) (w = fp->f_bf.smb_size))
+ {
+ /* write directly */
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ /* fill and done */
+ w = len;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+
+ if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else
+ {
+ /*
+ ** Line buffered: like fully buffered, but we
+ ** must check for newlines. Compute the distance
+ ** to the first newline (including the newline),
+ ** or `infinity' if there is none, then pretend
+ ** that the amount to write is SM_MIN(len,nldist).
+ */
+
+ nlknown = 0;
+ nldist = 0; /* XXX just to keep gcc happy */
+ do
+ {
+ GETIOV(nlknown = 0);
+ if (!nlknown)
+ {
+ nl = memchr((void *)p, '\n', len);
+ nldist = nl != NULL ? nl + 1 - p : len + 1;
+ nlknown = 1;
+ }
+ s = SM_MIN(len, ((size_t) nldist));
+ w = fp->f_w + fp->f_bf.smb_size;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_p > fp->f_bf.smb_base && s > w)
+ {
+ COPY(w);
+ /* fp->f_w -= w; */
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (s >= (w = fp->f_bf.smb_size))
+ {
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ w = s;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ if ((nldist -= w) == 0)
+ {
+ /* copied the newline: flush and forget */
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ nlknown = 0;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ }
+
+ return 0;
+
+err:
+ /* errno set before goto places us here */
+ fp->f_flags |= SMERR;
+ return SM_IO_EOF;
+}
diff --git a/contrib/sendmail/libsm/fvwrite.h b/contrib/sendmail/libsm/fvwrite.h
new file mode 100644
index 0000000..a1344c0
--- /dev/null
+++ b/contrib/sendmail/libsm/fvwrite.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: fvwrite.h,v 1.7 2001/03/02 00:18:19 ca Exp $
+ */
+
+/* I/O descriptors for sm_fvwrite() */
+struct sm_iov
+{
+ void *iov_base;
+ size_t iov_len;
+};
+struct sm_uio
+{
+ struct sm_iov *uio_iov;
+ int uio_iovcnt;
+ int uio_resid;
+};
+
+extern int sm_fvwrite __P((SM_FILE_T *, int, struct sm_uio *));
diff --git a/contrib/sendmail/libsm/fwalk.c b/contrib/sendmail/libsm/fwalk.c
new file mode 100644
index 0000000..b878c1a
--- /dev/null
+++ b/contrib/sendmail/libsm/fwalk.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fwalk.c,v 1.21 2001/09/11 04:04:48 gshapiro Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+#include "glue.h"
+
+/*
+** SM_FWALK -- apply a function to all found-open file pointers
+**
+** Parameters:
+** function -- a function vector to be applied
+** timeout -- time to complete actions (milliseconds)
+**
+** Returns:
+** The (binary) OR'd result of each function call
+*/
+
+int
+sm_fwalk(function, timeout)
+ int (*function) __P((SM_FILE_T *, int *));
+ int *timeout;
+{
+ register SM_FILE_T *fp;
+ register int n, ret;
+ register struct sm_glue *g;
+ int fptimeout;
+
+ ret = 0;
+ for (g = &smglue; g != NULL; g = g->gl_next)
+ {
+ for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++)
+ {
+ if (fp->f_flags != 0)
+ {
+ if (*timeout == SM_TIME_DEFAULT)
+ fptimeout = fp->f_timeout;
+ else
+ fptimeout = *timeout;
+ if (fptimeout == SM_TIME_IMMEDIATE)
+ continue; /* skip it */
+ ret |= (*function)(fp, &fptimeout);
+ }
+ }
+ }
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/fwrite.c b/contrib/sendmail/libsm/fwrite.c
new file mode 100644
index 0000000..372f75d
--- /dev/null
+++ b/contrib/sendmail/libsm/fwrite.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: fwrite.c,v 1.24 2001/09/11 04:04:48 gshapiro Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_WRITE -- write to a file pointer
+**
+** Parameters:
+** fp -- file pointer writing to
+** timeout -- time to complete the write
+** buf -- location of data to be written
+** size -- number of bytes to be written
+**
+** Result:
+** Failure: returns 0 _and_ sets errno
+** Success: returns >=0 with errno unchanged, where the
+** number returned is the number of bytes written.
+*/
+
+size_t
+sm_io_write(fp, timeout, buf, size)
+ SM_FILE_T *fp;
+ int timeout;
+ const void *buf;
+ size_t size;
+{
+ struct sm_uio uio;
+ struct sm_iov iov;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->f_write == NULL)
+ {
+ errno = ENODEV;
+ return 0;
+ }
+
+ iov.iov_base = (void *) buf;
+ uio.uio_resid = iov.iov_len = size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+
+ /* The usual case is success (sm_fvwrite returns 0) */
+ if (sm_fvwrite(fp, timeout, &uio) == 0)
+ return size;
+
+ /* else return number of bytes actually written */
+ return size - uio.uio_resid;
+}
diff --git a/contrib/sendmail/libsm/gen.html b/contrib/sendmail/libsm/gen.html
new file mode 100644
index 0000000..cf642ae
--- /dev/null
+++ b/contrib/sendmail/libsm/gen.html
@@ -0,0 +1,43 @@
+<html>
+<head>
+ <title>libsm : General Definitions</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : General Definitions </h1>
+ <br> $Id: gen.html,v 1.5 2000/12/08 21:41:42 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The header file <tt>&lt;sm/gen.h&gt;</tt>
+contains general definitions that are used by every other
+header file in <b>libsm</b>.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/gen.h&gt;
+
+#define NULL ((void*)0)
+
+typedef int bool;
+#define false 0
+#define true 1
+
+#define SM_MAX(a, b) ((a) &gt; (b) ? (a) : (b))
+#define SM_MIN(a, b) ((a) &lt; (b) ? (a) : (b))
+
+/*
+** The following types can be accessed and updated atomically.
+** This is relevant in the context of signal handlers and threads.
+*/
+typedef <i>some signed integral type</i> SM_ATOMIC_INT_T;
+typedef <i>some unsigned integral type</i> SM_ATOMIC_UINT_T;
+</pre>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/get.c b/contrib/sendmail/libsm/get.c
new file mode 100644
index 0000000..74549fe
--- /dev/null
+++ b/contrib/sendmail/libsm/get.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: get.c,v 1.18 2001/09/11 04:04:48 gshapiro Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_GETC -- get a character from a file
+**
+** Parameters:
+** fp -- the file to get the character from
+** timeout -- time to complete getc
+**
+** Returns:
+** Success: the value of the character read.
+** Failure: SM_IO_EOF
+**
+** This is a function version of the macro (in <sm/io.h>).
+** It is guarded with locks (which are currently not functional)
+** for multi-threaded programs.
+*/
+
+#undef sm_io_getc
+
+int
+sm_io_getc(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ return sm_getc(fp, timeout);
+}
diff --git a/contrib/sendmail/libsm/glue.h b/contrib/sendmail/libsm/glue.h
new file mode 100644
index 0000000..db8c101
--- /dev/null
+++ b/contrib/sendmail/libsm/glue.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: glue.h,v 1.6 2001/01/22 23:09:49 ca Exp $
+ */
+
+/*
+** The first few FILEs are statically allocated; others are dynamically
+** allocated and linked in via this glue structure.
+*/
+
+extern struct sm_glue
+{
+ struct sm_glue *gl_next;
+ int gl_niobs;
+ SM_FILE_T *gl_iobs;
+} smglue;
diff --git a/contrib/sendmail/libsm/heap.c b/contrib/sendmail/libsm/heap.c
new file mode 100644
index 0000000..50bb631
--- /dev/null
+++ b/contrib/sendmail/libsm/heap.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: heap.c,v 1.50 2001/09/11 04:04:48 gshapiro Exp $")
+
+/*
+** debugging memory allocation package
+** See heap.html for documentation.
+*/
+
+#include <string.h>
+
+#include <sm/assert.h>
+#include <sm/debug.h>
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/signal.h>
+#include <sm/xtrap.h>
+
+/* undef all macro versions of the "functions" so they can be specified here */
+#undef sm_malloc
+#undef sm_malloc_x
+#undef sm_malloc_tagged
+#undef sm_malloc_tagged_x
+#undef sm_free
+#undef sm_free_tagged
+#undef sm_realloc
+#if SM_HEAP_CHECK
+# undef sm_heap_register
+# undef sm_heap_checkptr
+# undef sm_heap_report
+#endif /* SM_HEAP_CHECK */
+
+#if SM_HEAP_CHECK
+SM_DEBUG_T SmHeapCheck = SM_DEBUG_INITIALIZER("sm_check_heap",
+ "@(#)$Debug: sm_check_heap - check sm_malloc, sm_realloc, sm_free calls $");
+# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
+#endif /* SM_HEAP_CHECK */
+
+const SM_EXC_TYPE_T SmHeapOutOfMemoryType =
+{
+ SmExcTypeMagic,
+ "F:sm.heap",
+ "",
+ sm_etype_printf,
+ "out of memory",
+};
+
+SM_EXC_T SmHeapOutOfMemory = SM_EXC_INITIALIZER(&SmHeapOutOfMemoryType, NULL);
+
+
+/*
+** The behaviour of malloc with size==0 is platform dependent (it
+** says so in the C standard): it can return NULL or non-NULL. We
+** don't want sm_malloc_x(0) to raise an exception on some platforms
+** but not others, so this case requires special handling. We've got
+** two choices: "size = 1" or "return NULL". We use the former in the
+** following.
+** If we had something like autoconf we could figure out the
+** behaviour of the platform and either use this hack or just
+** use size.
+*/
+
+#define MALLOC_SIZE(size) ((size) == 0 ? 1 : (size))
+
+/*
+** SM_MALLOC_X -- wrapper around malloc(), raises an exception on error.
+**
+** Parameters:
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to memory region.
+**
+** Note:
+** sm_malloc_x only gets called from source files in which heap
+** debugging is disabled at compile time. Otherwise, a call to
+** sm_malloc_x is macro expanded to a call to sm_malloc_tagged_x.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_malloc_x(size)
+ size_t size;
+{
+ void *ptr;
+
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return ptr;
+}
+
+#if !SM_HEAP_CHECK
+
+/*
+** SM_MALLOC -- wrapper around malloc()
+**
+** Parameters:
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to memory region.
+*/
+
+void *
+sm_malloc(size)
+ size_t size;
+{
+ void *ptr;
+
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return ptr;
+}
+
+/*
+** SM_REALLOC -- wrapper for realloc()
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area, NULL on failure.
+*/
+
+void *
+sm_realloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return newptr;
+}
+
+/*
+** SM_REALLOC_X -- wrapper for realloc()
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_realloc_x(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return newptr;
+}
+/*
+** SM_FREE -- wrapper around free()
+**
+** Parameters:
+** ptr -- pointer to memory region.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_free(ptr)
+ void *ptr;
+{
+ if (ptr == NULL)
+ return;
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ return;
+}
+
+#else /* !SM_HEAP_CHECK */
+
+/*
+** Each allocated block is assigned a "group number".
+** By default, all blocks are assigned to group #1.
+** By convention, group #0 is for memory that is never freed.
+** You can use group numbers any way you want, in order to help make
+** sense of sm_heap_report output.
+*/
+
+int SmHeapGroup = 1;
+int SmHeapMaxGroup = 1;
+
+/*
+** Total number of bytes allocated.
+** This is only maintained if the sm_check_heap debug category is active.
+*/
+
+size_t SmHeapTotal = 0;
+
+/*
+** High water mark: the most that SmHeapTotal has ever been.
+*/
+
+size_t SmHeapMaxTotal = 0;
+
+/*
+** Maximum number of bytes that may be allocated at any one time.
+** 0 means no limit.
+** This is only honoured if sm_check_heap is active.
+*/
+
+SM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit",
+ "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
+
+/*
+** This is the data structure that keeps track of all currently
+** allocated blocks of memory known to the heap package.
+*/
+
+typedef struct sm_heap_item SM_HEAP_ITEM_T;
+struct sm_heap_item
+{
+ void *hi_ptr;
+ size_t hi_size;
+ char *hi_tag;
+ int hi_num;
+ int hi_group;
+ SM_HEAP_ITEM_T *hi_next;
+};
+
+#define SM_HEAP_TABLE_SIZE 256
+static SM_HEAP_ITEM_T *SmHeapTable[SM_HEAP_TABLE_SIZE];
+
+/*
+** This is a randomly generated table
+** which contains exactly one occurrence
+** of each of the numbers between 0 and 255.
+** It is used by ptrhash.
+*/
+
+static unsigned char hashtab[SM_HEAP_TABLE_SIZE] =
+{
+ 161, 71, 77,187, 15,229, 9,176,221,119,239, 21, 85,138,203, 86,
+ 102, 65, 80,199,235, 32,140, 96,224, 78,126,127,144, 0, 11,179,
+ 64, 30,120, 23,225,226, 33, 50,205,167,130,240,174, 99,206, 73,
+ 231,210,189,162, 48, 93,246, 54,213,141,135, 39, 41,192,236,193,
+ 157, 88, 95,104,188, 63,133,177,234,110,158,214,238,131,233, 91,
+ 125, 82, 94, 79, 66, 92,151, 45,252, 98, 26,183, 7,191,171,106,
+ 145,154,251,100,113, 5, 74, 62, 76,124, 14,217,200, 75,115,190,
+ 103, 28,198,196,169,219, 37,118,150, 18,152,175, 49,136, 6,142,
+ 89, 19,243,254, 47,137, 24,166,180, 10, 40,186,202, 46,184, 67,
+ 148,108,181, 81, 25,241, 13,139, 58, 38, 84,253,201, 12,116, 17,
+ 195, 22,112, 69,255, 43,147,222,111, 56,194,216,149,244, 42,173,
+ 232,220,249,105,207, 51,197,242, 72,211,208, 59,122,230,237,170,
+ 165, 44, 68,123,129,245,143,101, 8,209,215,247,185, 57,218, 53,
+ 114,121, 3,128, 4,204,212,146, 2,155, 83,250, 87, 29, 31,159,
+ 60, 27,107,156,227,182, 1, 61, 36,160,109, 97, 90, 20,168,132,
+ 223,248, 70,164, 55,172, 34, 52,163,117, 35,153,134, 16,178,228
+};
+
+/*
+** PTRHASH -- hash a pointer value
+**
+** Parameters:
+** p -- pointer.
+**
+** Returns:
+** hash value.
+**
+** ptrhash hashes a pointer value to a uniformly distributed random
+** number between 0 and 255.
+**
+** This hash algorithm is based on Peter K. Pearson,
+** "Fast Hashing of Variable-Length Text Strings",
+** in Communications of the ACM, June 1990, vol 33 no 6.
+*/
+
+static int
+ptrhash(p)
+ void *p;
+{
+ int h;
+
+ if (sizeof(void*) == 4 && sizeof(unsigned long) == 4)
+ {
+ unsigned long n = (unsigned long)p;
+
+ h = hashtab[n & 0xFF];
+ h = hashtab[h ^ ((n >> 8) & 0xFF)];
+ h = hashtab[h ^ ((n >> 16) & 0xFF)];
+ h = hashtab[h ^ ((n >> 24) & 0xFF)];
+ }
+# if 0
+ else if (sizeof(void*) == 8 && sizeof(unsigned long) == 8)
+ {
+ unsigned long n = (unsigned long)p;
+
+ h = hashtab[n & 0xFF];
+ h = hashtab[h ^ ((n >> 8) & 0xFF)];
+ h = hashtab[h ^ ((n >> 16) & 0xFF)];
+ h = hashtab[h ^ ((n >> 24) & 0xFF)];
+ h = hashtab[h ^ ((n >> 32) & 0xFF)];
+ h = hashtab[h ^ ((n >> 40) & 0xFF)];
+ h = hashtab[h ^ ((n >> 48) & 0xFF)];
+ h = hashtab[h ^ ((n >> 56) & 0xFF)];
+ }
+# endif /* 0 */
+ else
+ {
+ unsigned char *cp = (unsigned char *)&p;
+ int i;
+
+ h = 0;
+ for (i = 0; i < sizeof(void*); ++i)
+ h = hashtab[h ^ cp[i]];
+ }
+ return h;
+}
+
+/*
+** SM_MALLOC_TAGGED -- wrapper around malloc(), debugging version.
+**
+** Parameters:
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to memory region.
+*/
+
+void *
+sm_malloc_tagged(size, tag, num, group)
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ void *ptr;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return ptr;
+ }
+
+ if (sm_xtrap_check())
+ return NULL;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
+ return NULL;
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ ptr = NULL;
+ }
+ SmHeapTotal += size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ return ptr;
+}
+
+/*
+** SM_MALLOC_TAGGED_X -- wrapper around malloc(), debugging version.
+**
+** Parameters:
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to memory region.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_malloc_tagged_x(size, tag, num, group)
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ void *ptr;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return ptr;
+ }
+
+ sm_xtrap_raise_x(&SmHeapOutOfMemory);
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
+ {
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ }
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ ptr = NULL;
+ }
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ SmHeapTotal += size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ return ptr;
+}
+
+/*
+** SM_HEAP_REGISTER -- register a pointer into the heap for debugging.
+**
+** Parameters:
+** ptr -- pointer to register.
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** true iff successfully registered (not yet in table).
+*/
+
+bool
+sm_heap_register(ptr, size, tag, num, group)
+ void *ptr;
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ int i;
+ SM_HEAP_ITEM_T *hi;
+
+ if (!HEAP_CHECK)
+ return true;
+ SM_REQUIRE(ptr != NULL);
+ i = ptrhash(ptr);
+# if SM_CHECK_REQUIRE
+
+ /*
+ ** We require that ptr is not already in SmHeapTable.
+ */
+
+ for (hi = SmHeapTable[i]; hi != NULL; hi = hi->hi_next)
+ {
+ if (hi->hi_ptr == ptr)
+ sm_abort("sm_heap_register: ptr %p is already registered (%s:%d)",
+ ptr, hi->hi_tag, hi->hi_num);
+ }
+# endif /* SM_CHECK_REQUIRE */
+ ENTER_CRITICAL();
+ hi = (SM_HEAP_ITEM_T *) malloc(sizeof(SM_HEAP_ITEM_T));
+ LEAVE_CRITICAL();
+ if (hi == NULL)
+ return false;
+ hi->hi_ptr = ptr;
+ hi->hi_size = size;
+ hi->hi_tag = tag;
+ hi->hi_num = num;
+ hi->hi_group = group;
+ hi->hi_next = SmHeapTable[i];
+ SmHeapTable[i] = hi;
+ return true;
+}
+/*
+** SM_REALLOC -- wrapper for realloc(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area, NULL on failure.
+*/
+
+void *
+sm_realloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+ SM_HEAP_ITEM_T *hi, **hp;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return newptr;
+ }
+
+ if (ptr == NULL)
+ return sm_malloc_tagged(size, "realloc", 0, SmHeapGroup);
+
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ if (sm_xtrap_check())
+ return NULL;
+ hi = *hp;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit)
+ < SmHeapTotal - hi->hi_size + size)
+ {
+ return NULL;
+ }
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ return NULL;
+ SmHeapTotal = SmHeapTotal - hi->hi_size + size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ *hp = hi->hi_next;
+ hi->hi_ptr = newptr;
+ hi->hi_size = size;
+ hp = &SmHeapTable[ptrhash(newptr)];
+ hi->hi_next = *hp;
+ *hp = hi;
+ return newptr;
+ }
+ }
+ sm_abort("sm_realloc: bad argument (%p)", ptr);
+ /* NOTREACHED */
+ return NULL; /* keep Irix compiler happy */
+}
+
+/*
+** SM_REALLOC_X -- wrapper for realloc(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_realloc_x(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+ SM_HEAP_ITEM_T *hi, **hp;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return newptr;
+ }
+
+ if (ptr == NULL)
+ return sm_malloc_tagged_x(size, "realloc", 0, SmHeapGroup);
+
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ sm_xtrap_raise_x(&SmHeapOutOfMemory);
+ hi = *hp;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit)
+ < SmHeapTotal - hi->hi_size + size)
+ {
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ }
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ SmHeapTotal = SmHeapTotal - hi->hi_size + size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ *hp = hi->hi_next;
+ hi->hi_ptr = newptr;
+ hi->hi_size = size;
+ hp = &SmHeapTable[ptrhash(newptr)];
+ hi->hi_next = *hp;
+ *hp = hi;
+ return newptr;
+ }
+ }
+ sm_abort("sm_realloc_x: bad argument (%p)", ptr);
+ /* NOTREACHED */
+ return NULL; /* keep Irix compiler happy */
+}
+
+/*
+** SM_FREE_TAGGED -- wrapper around free(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to memory region.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_free_tagged(ptr, tag, num)
+ void *ptr;
+ char *tag;
+ int num;
+{
+ SM_HEAP_ITEM_T **hp;
+
+ if (ptr == NULL)
+ return;
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ return;
+ }
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ SM_HEAP_ITEM_T *hi = *hp;
+
+ *hp = hi->hi_next;
+
+ /*
+ ** Fill the block with zeros before freeing.
+ ** This is intended to catch problems with
+ ** dangling pointers. The block is filled with
+ ** zeros, not with some non-zero value, because
+ ** it is common practice in some C code to store
+ ** a zero in a structure member before freeing the
+ ** structure, as a defense against dangling pointers.
+ */
+
+ (void) memset(ptr, 0, hi->hi_size);
+ SmHeapTotal -= hi->hi_size;
+ ENTER_CRITICAL();
+ free(ptr);
+ free(hi);
+ LEAVE_CRITICAL();
+ return;
+ }
+ }
+ sm_abort("sm_free: bad argument (%p) (%s:%d)", ptr, tag, num);
+}
+
+/*
+** SM_HEAP_CHECKPTR_TAGGED -- check whether ptr is a valid argument to sm_free
+**
+** Parameters:
+** ptr -- pointer to memory region.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** aborts if check fails.
+*/
+
+void
+sm_heap_checkptr_tagged(ptr, tag, num)
+ void *ptr;
+ char *tag;
+ int num;
+{
+ SM_HEAP_ITEM_T *hp;
+
+ if (!HEAP_CHECK)
+ return;
+ if (ptr == NULL)
+ return;
+ for (hp = SmHeapTable[ptrhash(ptr)]; hp != NULL; hp = hp->hi_next)
+ {
+ if (hp->hi_ptr == ptr)
+ return;
+ }
+ sm_abort("sm_heap_checkptr(%p): bad ptr (%s:%d)", ptr, tag, num);
+}
+
+/*
+** SM_HEAP_REPORT -- output "map" of used heap.
+**
+** Parameters:
+** stream -- the file pointer to write to.
+** verbosity -- how much info?
+**
+** Returns:
+** none.
+*/
+
+void
+sm_heap_report(stream, verbosity)
+ SM_FILE_T *stream;
+ int verbosity;
+{
+ int i;
+ unsigned long group0total, group1total, otherstotal, grandtotal;
+
+ if (!HEAP_CHECK || verbosity <= 0)
+ return;
+ group0total = group1total = otherstotal = grandtotal = 0;
+ for (i = 0; i < sizeof(SmHeapTable) / sizeof(SmHeapTable[0]); ++i)
+ {
+ SM_HEAP_ITEM_T *hi = SmHeapTable[i];
+
+ while (hi != NULL)
+ {
+ if (verbosity > 2
+ || (verbosity > 1 && hi->hi_group != 0))
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "%4d %*lx %7lu bytes",
+ hi->hi_group,
+ (int) sizeof(void *) * 2,
+ (long)hi->hi_ptr,
+ (unsigned long)hi->hi_size);
+ if (hi->hi_tag != NULL)
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ " %s",
+ hi->hi_tag);
+ if (hi->hi_num)
+ {
+ sm_io_fprintf(stream,
+ SM_TIME_DEFAULT,
+ ":%d",
+ hi->hi_num);
+ }
+ }
+ sm_io_fprintf(stream, SM_TIME_DEFAULT, "\n");
+ }
+ switch (hi->hi_group)
+ {
+ case 0:
+ group0total += hi->hi_size;
+ break;
+ case 1:
+ group1total += hi->hi_size;
+ break;
+ default:
+ otherstotal += hi->hi_size;
+ break;
+ }
+ grandtotal += hi->hi_size;
+ hi = hi->hi_next;
+ }
+ }
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "heap max=%lu, total=%lu, ",
+ (unsigned long) SmHeapMaxTotal, grandtotal);
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "group 0=%lu, group 1=%lu, others=%lu\n",
+ group0total, group1total, otherstotal);
+ if (grandtotal != SmHeapTotal)
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "BUG => SmHeapTotal: got %lu, expected %lu\n",
+ (unsigned long) SmHeapTotal, grandtotal);
+ }
+}
+#endif /* !SM_HEAP_CHECK */
diff --git a/contrib/sendmail/libsm/heap.html b/contrib/sendmail/libsm/heap.html
new file mode 100644
index 0000000..bc32b01
--- /dev/null
+++ b/contrib/sendmail/libsm/heap.html
@@ -0,0 +1,424 @@
+<html>
+<head>
+ <title>libsm : Memory Allocation</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Memory Allocation </h1>
+ <br> $Id: heap.html,v 1.9 2000/12/08 21:41:42 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The heap package provides a layer of abstraction on top of
+<tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt>
+that provides optional error checking and memory leak detection,
+and which optionally raises an exception when an allocation request
+cannot be satisfied.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/heap.h&gt;
+
+/*
+** Wrappers for malloc, realloc, free
+*/
+void *sm_malloc(size_t size);
+void *sm_realloc(void *ptr, size_t size);
+void sm_free(void *ptr);
+
+/*
+** Wrappers for malloc, realloc that raise an exception instead of
+** returning NULL on heap exhaustion.
+*/
+void *sm_malloc_x(size_t size);
+void *sm_realloc_x(void *ptr, size_t size);
+
+/*
+** Print a list of currently allocated blocks,
+** used to diagnose memory leaks.
+*/
+void sm_heap_report(FILE *stream, int verbosity);
+
+/*
+** Low level interfaces.
+*/
+int sm_heap_group();
+int sm_heap_setgroup(int g);
+int sm_heap_newgroup();
+void *sm_malloc_tagged(size_t size, char *file, int line, int group);
+void *sm_malloc_tagged_x(size_t size, char *file, int line, int group);
+bool sm_heap_register(void *ptr, size_t size, char *file, int line);
+</pre>
+
+<h2> How to allocate and free memory </h2>
+
+ <tt>sm_malloc</tt>, <tt>sm_realloc</tt> and <tt>sm_free</tt>
+ are portable plug in replacements
+ for <tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt> that provide
+ error checking and memory leak detection.
+ <tt>sm_malloc_x</tt> and <tt>sm_realloc_x</tt>
+ are variants of
+ <tt>sm_malloc</tt> and <tt>sm_realloc</tt>
+ that raise an exception on error.
+ To use the package effectively,
+ all calls to <tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt>
+ should be replaced by calls
+ to the corresponding <tt>sm_</tt>* routines.
+
+<dl>
+<dt>
+<tt> void *sm_malloc(size_t size) </tt>
+<dd>
+ This function is a plug-in replacement for <tt>malloc</tt>.
+ It allocates <tt>size</tt> bytes of memory on the heap
+ and returns a pointer to it,
+ or it returns <tt>NULL</tt> on failure.
+ <p>
+
+ The C standard says that <tt>malloc(0)</tt> may return
+ either <tt>NULL</tt> or a non-<tt>NULL</tt> value.
+ To ensure consistent behaviour on all platforms,
+ <tt>sm_malloc(0)</tt> is equivalent to <tt>sm_malloc(1)</tt>.
+ <p>
+
+ In addition, if heap checking is enabled, then <tt>sm_malloc</tt>
+ maintains a hash table describing all currently allocated
+ memory blocks. This table is used for argument validity
+ checking in <tt>sm_realloc</tt> and <tt>sm_free</tt>,
+ and it can be printed using <tt>sm_heap_report</tt>
+ as an aid to finding memory leaks.
+ <p>
+
+<dt>
+<tt> void *sm_malloc_x(size_t size) </tt>
+<dd>
+ This function is just like <tt>sm_malloc</tt>
+ except that it raises the <tt>SmHeapOutOfMemory</tt> exception
+ instead of returning <tt>NULL</tt> on error.
+ <p>
+
+<dt>
+<tt> void *sm_realloc(void *ptr, size_t size) </tt>
+<dd>
+ This function is a plug-in replacement for <tt>realloc</tt>.
+ If <tt>ptr</tt> is null then this call is equivalent
+ to <tt>sm_malloc(size)</tt>.
+ Otherwise, the size of the object pointed to by <tt>ptr</tt>
+ is changed to <tt>size</tt> bytes, and a pointer to the
+ (possibly moved) object is returned.
+ If the space cannot be allocated, then the object pointed to
+ by <tt>ptr</tt> is unchanged and <tt>NULL</tt> is returned.
+ <p>
+
+ If <tt>size</tt> is 0 then we pretend that <tt>size</tt> is 1.
+ This may be a mistake.
+ <p>
+
+ If ptr is not NULL and heap checking is enabled,
+ then ptr is required to be a value that was
+ previously returned by sm_malloc or sm_realloc, and which
+ has not yet been freed by sm_free. If this condition is not
+ met, then the program is aborted using sm_abort.
+ <p>
+
+<dt>
+<tt> void *sm_realloc_x(void *ptr, size_t size) </tt>
+<dd>
+ This function is just like <tt>sm_realloc</tt>
+ except that it raises the SmHeapOutOfMemory exception
+ instead of returning <tt>NULL</tt> on error.
+ <p>
+
+<dt>
+<tt> void sm_free(void *ptr) </tt>
+<dd>
+ This function is a plug-in replacement for free.
+ If heap checking is disabled, then this function is equivalent
+ to a call to free. Otherwise, the following additional semantics
+ apply.
+ <p>
+
+ If ptr is NULL, this function has no effect.
+ <p>
+
+ Otherwise, ptr is required to be a value that was
+ previously returned by sm_malloc or sm_realloc, and which
+ has not yet been freed by sm_free. If this condition is not
+ met, then the program is aborted using sm_abort.
+ <p>
+
+ Otherwise, if there is no error, then the block pointed to by ptr
+ will be set to all zeros before free() is called. This is intended
+ to assist in detecting the use of dangling pointers.
+</dl>
+
+<h2> How to control tag information </h2>
+
+When heap checking is enabled,
+the heap package maintains a hash table which associates the
+following values with each currently allocated block:
+
+<dl>
+<dt>
+<tt> size_t size </tt>
+<dd>
+ The size of the block.
+<dt>
+<tt> char *tag </tt>
+<dd>
+ By default, this is the name of the source file from which
+ the block was allocated, but you can specify an arbitrary
+ string pointer, or <tt>NULL</tt>.
+<dt>
+<tt> int num </tt>
+<dd>
+ By default, this is the line number from which the block was
+ allocated.
+<dt>
+<tt> int group </tt>
+<dd>
+ By convention, group==0 indicates that the block is permanently
+ allocated and will never be freed. The meanings of other group
+ numbers are defined by the application developer.
+ Unless you take special action, all blocks allocated by
+ <tt>sm_malloc</tt> and <tt>sm_malloc_x</tt> will be assigned
+ to group 1.
+</dl>
+
+These tag values are printed by <tt>sm_heap_report</tt>,
+and are used to help analyze memory allocation behaviour
+and to find memory leaks.
+The following functions give you precise control over the
+tag values associated with each allocated block.
+
+<dl>
+<dt>
+<tt> void *sm_malloc_tagged(size_t size, int tag, int num, int group) </tt>
+<dd>
+ Just like <tt>sm_malloc</tt>, except you directly specify
+ all of the tag values.
+ If heap checking is disabled at compile time, then a call
+ to <tt>sm_malloc_tagged</tt> is macro expanded to
+ a call to <tt>malloc</tt>.
+ <p>
+
+ Note that the expression <tt>sm_malloc(size)</tt> is macro expanded to
+
+<blockquote><pre>
+sm_malloc_tagged(size, __FILE__, __LINE__, sm_heap_group())
+</pre></blockquote>
+
+<dt>
+<tt> void *sm_malloc_tagged_x(size_t size, int tag, int num, int group) </tt>
+<dd>
+ A variant of <tt>sm_malloc_tagged</tt>
+ that raises an exception on error.
+ A call to <tt>sm_malloc_x</tt> is macro expanded
+ to a call to <tt>sm_malloc_tagged_x</tt>.
+ <p>
+
+<dt>
+<tt> int sm_heap_group() </tt>
+<dd>
+ The heap package maintains a thread-local variable containing
+ the current group number.
+ This is the group that <tt>sm_malloc</tt> and <tt>sm_malloc_x</tt>
+ will assign a newly allocated block to.
+ The initial value of this variable is 1.
+ The current value of this variable is returned by
+ <tt>sm_heap_group()</tt>.
+ <p>
+
+<dt>
+<tt> int sm_heap_setgroup(int g) </tt>
+<dd>
+ Set the current group to the specified value.
+</dl>
+
+Here are two examples of how you might use these interfaces.
+
+<ol>
+<li>
+One way to detect memory leaks is to turn on heap checking
+and call <tt>sm_heap_report(stdout,2)</tt>
+when the program exits.
+This prints a list of all allocated blocks that do not belong to group 0.
+(Blocks in group 0 are assumed to be permanently allocated,
+and so their existence at program exit does not indicate a leak.)
+If you want to allocate a block and assign it to group 0,
+you have two choices:
+
+<blockquote><pre>
+int g = sm_heap_group();
+sm_heap_setgroup(0);
+p = sm_malloc_x(size);
+sm_heap_setgroup(g);
+</pre></blockquote>
+
+or
+
+<blockquote><pre>
+p = sm_malloc_tagged_x(size, __FILE__, __LINE__, 0);
+</pre></blockquote>
+
+<li>
+Suppose you have a utility function foo_alloc which allocates
+and initializes a 'foo' object. When sm_heap_report is called,
+all unfreed 'foo' objects will be reported to have the same
+source code file name and line number.
+That might make it difficult to determine where a memory leak is.
+<p>
+
+Here is how you can arrange for more precise reporting for
+unfreed foo objects:
+
+<blockquote><pre>
+#include &lt;sm/heap.h&gt;
+
+#if SM_HEAP_CHECK
+# define foo_alloc_x() foo_alloc_tagged_x(__FILE__,__LINE)
+ FOO *foo_alloc_tagged_x(char *, int);
+#else
+ FOO *foo_alloc_x(void);
+# define foo_alloc_tagged_x(file,line) foo_alloc_x()
+#endif
+
+...
+
+#if SM_HEAP_CHECK
+FOO *
+foo_alloc_tagged_x(char *file, int line)
+#else
+FOO *
+foo_alloc_x(void)
+#endif
+{
+ FOO *p;
+
+ p = sm_malloc_tagged_x(sizeof(FOO), file, line, sm_heap_group());
+ ...
+ return p;
+}
+</pre></blockquote>
+</ol>
+
+<h2> How to dump the block list </h2>
+
+To perform memory leak detection, you need to arrange for your
+program to call sm_heap_report at appropriate times.
+
+<dl>
+<dt>
+<tt> void sm_heap_report(FILE *stream, int verbosity) </tt>
+<dd>
+ If heap checking is disabled, this function does nothing.
+ If verbosity &lt;= 0, this function does nothing.
+ <p>
+
+ If verbosity &gt;= 1, then sm_heap_report prints a single line
+ to stream giving the total number of bytes currently allocated.
+ If you call sm_heap_report each time the program has reached a
+ "ground state", and the reported amount of heap storage is
+ monotonically increasing, that indicates a leak.
+ <p>
+
+ If verbosity &gt;= 2, then sm_heap_report additionally prints one line
+ for each block of memory currently allocated, providing that
+ the group != 0.
+ (Such blocks are assumed to be permanently allocated storage, and
+ are not reported to cut down the level of noise.)
+ <p>
+
+ If verbosity &gt;= 3, then sm_heap_report prints one line for each
+ allocated block, regardless of the group.
+</dl>
+
+<h2> How to enable heap checking </h2>
+
+The overhead of using the package can be made as small as you want.
+You have three options:
+
+<ol>
+<li>
+ If you compile your software with -DSM_HEAP_CHECK=0 then
+ sm_malloc, sm_realloc and sm_free will be redefined
+ as macros that call malloc, realloc, and free. In this case,
+ there is zero overhead.
+<li>
+ If you do not define -DSM_HEAP_CHECK=0, and you do not explicitly
+ turn on heap checking at run time, then your program will run
+ without error checking and memory leak detection, and the additional
+ cost of calling sm_malloc, sm_realloc and sm_free is a
+ function call and test. That overhead is sufficiently low that
+ the checking code can be left compiled in a production environment.
+<li>
+ If you do not define -DSM_HEAP_CHECK=0, and you explicitly turn on
+ heap checking at run time, then the additional cost of calling
+ sm_malloc, sm_realloc and sm_free is a hash table lookup.
+</ol>
+
+ Here's how to modify your application to use the heap package.
+ First, change all calls to malloc, realloc and free to sm_malloc,
+ sm_realloc and sm_free.
+ Make sure that there is a -d command line option that
+ uses the libsm debug package to enable named debug options.
+ Add the following code to your program just before it calls exit,
+ or register an atexit handler function containing the following code:
+
+<blockquote><pre>
+#if SM_HEAP_CHECK
+ /* dump the heap, if we are checking for memory leaks */
+ if (sm_debug_active(&SmHeapCheck, 2))
+ sm_heap_report(stdout, sm_debug_level(&SmHeapCheck) - 1);
+#endif
+</pre></blockquote>
+
+ To turn on heap checking, use the command line option "-dsm_check_heap.1".
+ This will cause a table of all currently allocated blocks to be
+ maintained. The table is used by sm_realloc and sm_free to perform
+ validity checking on the first argument.
+
+ <p>
+ The command line option "-dsm_check_heap.2" will cause your application
+ to invoke sm_heap_report with verbosity=1 just before exit.
+ That will print a single line reporting total storage allocation.
+
+ <p>
+ The command line option "-dsm_check_heap.3" will cause your application
+ to invoke sm_heap_report with verbosity=2 just before exit.
+ This will print a list of all leaked blocks.
+
+ <p>
+ The command line option "-dsm_check_heap.4" will cause your application
+ to invoke sm_heap_report with verbosity=3 just before exit.
+ This will print a list of all allocated blocks.
+
+<h2> Using sm_heap_register </h2>
+
+ Suppose you call a library routine foo that allocates a block of storage
+ for you using malloc, and expects you to free the block later using
+ free. Because the storage was not allocated using sm_malloc, you
+ will normally get an abort if you try to pass the pointer to
+ sm_free. The way to fix this problem is to 'register' the pointer
+ returned by foo with the heap package, by calling sm_heap_register:
+
+<blockquote><pre>
+bool sm_heap_register(ptr, size, file, line, group)
+</pre></blockquote>
+
+ The 'ptr' argument is the pointer returned by foo. The 'size' argument
+ can be smaller than the actual size of the allocated block, but it must
+ not be larger. The file and line arguments indicate at which line of
+ source code the block was allocated, and is printed by sm_heap_report.
+ For group, you probably want to pass sm_heap_group().
+ <p>
+ This function returns <tt>true</tt> on success,
+ or <tt>false</tt> if it failed due to heap exhaustion.
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/index.html b/contrib/sendmail/libsm/index.html
new file mode 100644
index 0000000..f2eec16
--- /dev/null
+++ b/contrib/sendmail/libsm/index.html
@@ -0,0 +1,174 @@
+<html>
+<head>
+ <title>libsm Overview</title>
+</head>
+<body>
+
+<center>
+ <h1> libsm Overview </h1>
+ <br> $Id: index.html,v 1.14 2001/02/13 21:21:25 gshapiro Exp $
+</center>
+
+<h2> Introduction </h2>
+
+Libsm is a library of generally useful C abstractions.
+Libsm stands alone; it depends on no other sendmail libraries,
+and the only sendmail header files it depends on are its own,
+which reside in <tt>../include/sm</tt>.
+
+<h2> Contents </h2>
+
+Here is the current set of packages:
+<blockquote>
+ <a href="gen.html"> gen: general definitions </a><br>
+ <a href="debug.html"> debug: debugging and tracing </a><br>
+ <a href="assert.html"> assert: assertion handling and aborts </a><br>
+ <a href="heap.html"> heap: memory allocation </a><br>
+ <a href="exc.html"> exc: exception handling </a><br>
+ <a href="rpool.html"> rpool: resource pools </a><br>
+ <a href="cdefs.html"> cdefs: C language portability macros </a><br>
+ <a href="io.html"> io: buffered i/o </a><br>
+</blockquote>
+
+<h2> Naming Conventions </h2>
+
+ Some of the symbols defined by libsm
+ come from widely used defacto or dejure standards.
+ Examples include <tt>size_t</tt> (from the C 89 standard),
+ <tt>bool</tt> (from the C 99 standard),
+ <tt>strerror</tt> (from Posix),
+ and <tt>__P</tt> (from BSD and Linux).
+ In these cases, we use the standard name rather than
+ inventing a new name.
+ We import the name from the appropriate header file when possible,
+ or define it ourselves when necessary.
+ When you are using one of these abstractions, you must include
+ the appropriate libsm header file.
+ For example, when you are using <tt>strerror</tt>, you must
+ include <tt>&lt;sm/string.h&gt;</tt> instead of <tt>&lt;string.h&gt;</tt>.
+
+ <p>
+ When we aren't implementing a standard interface,
+ we use a naming convention that attempts to maximize portability
+ across platforms, and minimize conflicts with other libraries.
+ Except for a few seemingly benign exceptions,
+ all names begin with <tt>SM_</tt>, <tt>Sm</tt> or <tt>sm_</tt>.
+
+ <p>
+ The ISO C, Posix and Unix standards forbid applications
+ from using names beginning with <tt>__</tt> or <tt>_[A-Z]</tt>,
+ and place restrictions on what sorts of names can begin
+ with <tt>_[a-z]</tt>. Such names are reserved for the compiler and
+ the standard libraries.
+ For this reason, we avoid defining any names that begin
+ with <tt>_</tt>.
+ For example, all libsm header file idempotency macros have the form
+ <tt>SM_FOO_H</tt> (no leading <tt>_</tt>).
+
+ <p>
+ Type names begin with <tt>SM_</tt> and end with <tt>_T</tt>.
+ Note that the Posix standard reserves all identifiers ending
+ with <tt>_t</tt>.
+
+ <p>
+ All functions that are capable of raising an exception
+ have names ending in <tt>_x</tt>, and developers are
+ encouraged to use this convention when writing new code.
+ This naming convention may seem unnecessary at first,
+ but it becomes extremely useful during maintenance,
+ when you are attempting to reason about the correctness
+ of a block of code,
+ and when you are trying to track down exception-related bugs
+ in existing code.
+
+<h2> Coding Conventions </h2>
+
+The official style for function prototypes in libsm header files is
+
+<blockquote><pre>
+extern int
+foo __P((
+ int _firstarg,
+ int _secondarg));
+</pre></blockquote>
+
+The <tt>extern</tt> is useless, but required for stylistic reasons.
+The parameter names are optional; if present they are lowercase
+and begin with _ to avoid namespace conflicts.
+Each parameter is written on its own line to avoid very long lines.
+
+<p>
+For each structure <tt>struct sm_foo</tt> defined by libsm,
+there is a typedef:
+
+<blockquote><pre>
+typedef struct sm_foo SM_FOO_T;
+</pre></blockquote>
+
+and there is a global variable which is defined as follows:
+
+<blockquote><pre>
+const char SmFooMagic[] = "sm_foo";
+</pre></blockquote>
+
+The first member of each structure defined by libsm is
+
+<blockquote><pre>
+const char *sm_magic;
+</pre></blockquote>
+
+For all instances of <tt>struct sm_foo</tt>,
+<tt>sm_magic</tt> contains <tt>SmFooMagic</tt>,
+which points to a unique character string naming the type.
+It is used for debugging and run time type checking.
+
+<p>
+Each function with a parameter declared <tt>SM_FOO_T *foo</tt>
+contains the following assertion:
+
+<blockquote><pre>
+SM_REQUIRE_ISA(foo, SmFooMagic);
+</pre></blockquote>
+
+which is equivalent to
+
+<blockquote><pre>
+SM_REQUIRE(foo != NULL && foo-&gt;sm_magic == SmFooMagic);
+</pre></blockquote>
+
+When an object of type <tt>SM_FOO_T</tt> is deallocated,
+the member <tt>sm_magic</tt> is set to <tt>NULL</tt>.
+That will cause the above assertion to fail if a dangling pointer is used.
+
+<h2> Additional Design Goals </h2>
+
+Here are some of my design goals:
+<ul>
+ <p>
+<li>The sm library is self contained; it does not depend on any other
+ sendmail libraries or header files.
+ <p>
+<li>The sm library must be compatible with shared libraries,
+ even on platforms with weird implementation restrictions.
+ I assume that a shared library can export global variables;
+ the debug package relies on this assumption.
+ I do not assume that if an application redefines a function defined
+ in a shared library, the shared library will use the version of the
+ function defined in the application in preference to the version
+ that it defines.
+ For this reason, I provide interfaces for registering handler functions
+ in cases where an application might need to override standard behaviour.
+ <p>
+<li>The sm library must be compatible with threads.
+ The debug package presents a small problem: I don't want
+ sm_debug_active to acquire and release a lock.
+ So I assume that
+ there exists an integral type <tt>SM_ATOMIC_INT_T</tt>
+ (see <a href="gen.html"><tt>&lt;sm/gen.h&gt;</tt></a>)
+ that can be accessed and updated atomically.
+ I assume that locking must be used to guard updates and accesses to
+ any other type, and I have designed the interfaces accordingly.
+</ul>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/io.html b/contrib/sendmail/libsm/io.html
new file mode 100644
index 0000000..5bb7c32
--- /dev/null
+++ b/contrib/sendmail/libsm/io.html
@@ -0,0 +1,745 @@
+<html>
+<head>
+<title>libsm sm_io general overview</title>
+</head>
+<body>
+<a href="index.html">Back to libsm overview</a>
+<center>
+<h1>libsm sm_io general overview</h1>
+<br> $Id: io.html,v 1.3 2001/03/17 03:22:50 gshapiro Exp $
+</center>
+<h2> Introduction </h2>
+<p>
+The <i>sm_io</i> portion of the <i>libsm</i> library is similar to
+the <i>stdio</i> library. It is derived from the Chris Torek version
+of the <i>stdio</i> library (BSD). There are some key differences
+described below between <i>sm_io</i> and <i>stdio</i> but many
+similarities will be noticed.
+</p>
+<p>
+A key difference between <i>stdio</i> and <i>sm_io</i> is that the
+functional code that does the open, close, read, write, etc. on a file
+can be different for different files. For example, with <i>stdio</i>
+the functional code (read, write) is either the default supplied in the
+library or a "programmer specified" set of functions set via
+<i>sm_io_open()</i>. Whichever set of functions are specified <b>all</b>
+open's, read's, write's, etc use the same set of functions. In contrast, with
+<i>sm_io</i> a different set of functions can be specified with each
+active file for read's, write's, etc. These different function sets
+are identified as <b>file types</b> (see <tt>sm_io_open()</tt>). Each function
+set can handle the actions directly, pass the action request to
+another function set or do some work before passing it on to another function
+set. The setting of a function set for a file type can be done for
+a file type at any time (even after the type is open).
+</p>
+<p>
+A second difference is the use of <a href="rpool.html"><b>rpools</b></a>.
+An <b>rpool</b> is specified with the opening of a file
+(<tt>sm_io_open()</tt>).
+This allows of a file to be associated with an rpool so that when the
+rpool is released the open file will be closed; the <tt>sm_io_open()</tt>
+registers that <tt>sm_io_close()</tt> should be called when the rpool is
+released.
+</p>
+<p>
+A third difference is that the I/O functions take a <i>timeout</i>
+argument. This allows the setting of a maximum amount of time allowable
+for the I/O to be completed. This means the calling program does not need
+to setup it's own timeout mechanism. NOTE: SIGALRM's should not be
+active in the calling program when an I/O function with a <i>timeout</i>
+is used.
+</p>
+<p>
+When converting source code from <i>stdio</i> to <i>sm_io</i> be
+very careful to NOTE: the arguments to functions have been rationalized.
+That is, unlike <i>stdio</i>, all <i>sm_io</i> functions that
+take a file pointer (SM_FILE_T *) argument have the file pointer
+as the first argument. Also not all functions with <i>stdio</i> have
+an identical matching <i>sm_io</i> API: the API list has been thinned
+since a number of <i>stdio</i> API's overlapped in functionality.
+Remember many functions also have a <i>timeout</i> argument added.
+</p>
+<p>
+When a file is going to be opened, the file type is included with
+<tt>sm_io_open()</tt>.
+A file type is either one automatically included with the <i>sm_io</i>
+library or one created by the program at runtime.
+File types can be either buffered or unbuffered. When buffered the buffering
+is either the builtin <i>sm_io</i> buffering or as done by the file type.
+File types can be disk files, strings, TCP/IP connections or whatever
+your imagination can come up with that can be read and/or written to.
+</p>
+<p>
+Information about a particular file type or pointer can be obtained or set with
+the <i>sm_io</i> "info" functions.
+The <tt>sm_io_setinfo()</tt> and <tt>sm_io_getinfo()</tt> functions work on
+an active file pointer.
+</p>
+<h2>Include files</h2>
+<p>
+There is one main include file for use with sm_io: <i>io.h</i>. Since the
+use of <b>rpools</b> is specified with <tt>sm_io_open()</tt> an
+<b>rpool</b> may
+be created and thus <i>rpool.h</i> may need to be included as well
+(before io.h).
+</p>
+<pre>
+#include &lt;rpool.h&gt;
+#include &lt;io.h&gt;
+</pre>
+
+<h2>Functions/API's</h2>
+<p>
+Below is a list of the functions for <i>sm_io</i> listed in
+alphabetical order. Currently these functions return error codes
+and set errno when appropriate. These (may?/will?) change to
+raising exceptions later.
+</p>
+<pre>
+<a href="#sm_io_autoflush">SM_FILE_T *sm_io_autoflush(SM_FILE_T *fp, SM_FILE_T *)</a>
+
+<a href="#sm_io_automode">void sm_io_automode(SM_FILE_T *fp, SM_FILE_T *)</a>
+
+<a href="#defaultapi">void sm_io_clearerr(SM_FILE_T *fp)</a>
+
+<a href="#sm_io_close">int sm_io_close(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_dup(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_eof(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_error(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">char * sm_io_fgets(SM_FILE_T *fp, int timeout, char *buf, int n)</a>
+
+<a href="#defaultapi">int sm_io_flush(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#sm_io_fopen">int sm_io_fopen(char *pathname, int flags [, MODE_T mode])</a>
+
+<a href="#defaultapi">int sm_io_fprintf(SM_FILE_T *fp, int timeout, const char *fmt, ...)</a>
+
+<a href="#defaultapi">int sm_io_fputs(s, int, SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_fscanf(SM_FILE_T *fp, int timeout, char const *fmt, ...) </a>
+
+<a href="#defaultapi">int sm_io_getc(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#sm_io_getinfo">void sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)</a>
+
+<a href="#sm_io_open">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>
+
+<a href="#defaultapi">int sm_io_purge(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_putc(SM_FILE_T *fp, int timeout, int c)</a>
+
+<a href="#defaultapi">size_t sm_io_read(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>
+
+<a href="#sm_io_reopen">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>
+
+<a href="#defaultapi">void sm_io_rewind(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_seek(SM_FILE_T *fp, off_t offset, int timeout, int whence)</a>
+
+<a href="#sm_io_setinfo">void sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)</a>
+
+<a href="#defaultapi">int sm_io_setvbuf(SM_FILE_T *fp, int timeout, char *buf, int mode, size_t size)</a>
+
+<a href="#defaultapi">int sm_io_sscanf(const char *str, char const *fmt, ...)</a>
+
+<a href="#defaultapi">long sm_io_tell(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_ungetc(SM_FILE_T *fp, int timeout, int c)</a>
+
+<a href="#defaultapi">size_t sm_io_write(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>
+
+<a href="#defaultapi">int sm_snprintf(char *str, size_t n, char const *fmt, ...)</a>
+
+</pre>
+<a name="timeouts">
+<h2>Timeouts</h2>
+<p>
+For many of the functions a <i>timeout</i> argument is given. This limits
+the amount of time allowed for the function to complete. There are three
+pre-defined values:
+<menu>
+<li>
+SM_TIME_DEFAULT - timeout using the default setting for this file type
+</li>
+<li>
+SM_TIME_FOREVER - timeout will take forever; blocks until task completed
+</li>
+<li>
+SM_TIME_IMMEDIATE - timeout (virtually) now
+</li>
+</menu>
+</p>
+<p>
+A function caller can also specify a positive integer value in milliseconds.
+A function will return with <i>errno</i> set to EINVAL if a bad value
+is given for <i>timeout</i>.
+When a function times out the function returns in error with <i>errno</i>
+set to <b>EAGAIN</b>. In the future this may change to an exception being
+thrown.
+</p>
+<h2>Function Descriptions</h2>
+<dl>
+<!-- SM_IO_FOPEN -->
+<p></p>
+<dt><tt><a name="sm_io_fopen">
+SM_FILE_T *
+<br>
+sm_io_fopen(char *pathname, int flags)
+<br>
+SM_FILE_T *
+<br>
+sm_io_fopen(char *pathname, int flags, MODE_T mode)
+</a></tt></dt>
+<dd>
+Open the file named by <tt>pathname</tt>, and associate a stream with it.
+The arguments are the same as for the <tt>open(2)</tt> system call.
+<br>
+If memory could not be allocated, an exception is raised.
+If successful, an <tt>SM_FILE_T</tt> pointer is returned.
+Otherwise, <tt>NULL</tt> is returned and <tt>errno</tt> is set.
+<!-- SM_IO_OPEN -->
+<p></p>
+<dt><tt><a name="sm_io_open">
+SM_FILE_T *
+<br>
+sm_io_open(const SM_FILE_T *type, int timeout, const void *info, int flags, void *rpool)
+</a></tt></dt>
+<dd>
+Opens a file by <i>type</i> directed by <i>info</i>. <i>Type</i> is a filled-in
+SM_FILE_T structure from the following builtin list
+(<a href="#builtins"><b>descriptions below</b></a>)
+or one specified by the program.
+<menu>
+<li>
+SmFtString
+</li>
+<li>
+SmFtStdio
+</li>
+<li>
+SmFtStdiofd
+</li>
+<li>
+smioin <b>*</b>
+</li>
+<li>
+smioout <b>*</b>
+</li>
+<li>
+smioerr <b>*</b>
+</li>
+<li>
+smiostdin <b>*</b>
+</li>
+<li>
+smiostdout <b>*</b>
+</li>
+<li>
+smiostderr <b>*</b>
+</li>
+<li>
+SmFtSyslog
+</li>
+</menu>
+<br>
+The above list of file types are already appropriately filled in. Those marked
+with a "<b>*</b>" are already open and may be used directly and immediately.
+For program specified types, to set the <i>type</i> argument easily and with minimal error the macro
+<b>SM_IO_SET_TYPE</b> should be used. The SM_FILE_T structure is fairly
+large, but only a small portion of it need to be initialized for a new
+type.
+See also <a href="#writefunctions">"Writing Functions for a File Type"</a>.
+<menu>
+<pre>
+SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
+</pre>
+</menu>
+<br>
+<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
+section.
+<br>
+<i>Info</i> is information that describes for the file type what is
+to be opened and any associated information.
+For a disk file this would be a file path; with a TCP
+connection this could be an a structure containing an IP address and port.
+<br><i>Flags</i> is a
+set of sm_io flags that describes how the file is to be interacted with:
+<menu>
+<li>
+SM_IO_RDWR - read and write
+</li>
+<li>
+SM_IO_RDONLY - read only
+</li>
+<li>
+SM_IO_WRONLY - write only
+</li>
+<li>
+SM_IO_APPEND - allow write to EOF only
+</li>
+<li>
+SM_IO_APPENDRW - allow read-write from EOF only
+</li>
+<li>
+SM_IO_RDWRTR - read and write with truncation of file first
+</li>
+</menu>
+<i>Rpool</i> is the address of the rpool that this open is to be associated
+with. When the rpool is released then the close function for this
+file type will be automatically called to close the file for cleanup.
+If NULL is specified for <i>rpool</i> then the close function is not
+associated (attached) to an rpool.
+<br>
+On cannot allocate memory, an exception is raised.
+If the <i>type</i> is invalid, <tt>sm_io_open</tt> will abort the process.
+On success an SM_FILE_T * pointer is returned.
+On failure the NULL pointer is returned and errno is set.
+</dd>
+<!-- SM_IO_SETINFO -->
+<p></p>
+<dt><tt><a name="sm_io_setinfo">
+int
+<br>
+sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)
+</a></tt></dt>
+<dd>
+For the open file <i>sfp</i> set the indicated information (<i>what</i>)
+to the new value <i>(valp</i>).
+This will make the change for this SM_FILE_T only. The file
+type that <i>sfp</i> originally belonged to will still be
+configured the same way (this is to prevent side-effect
+to other open's of the same file type, particularly with threads).
+The value of <i>what</i> will be file-type dependant since this function
+is one of the per file type setable functions.
+One value for <i>what</i> that is valid for all file types is
+SM_WHAT_VECTORS. This sets the currently open file with a new function
+vector set for open, close, etc. The new values are taken from <i>valp</i>
+a SM_FILE_T filled in by the used via the macro SM_IO_SET_TYPE
+(see and <a href="#writefunctions">
+"Writing Functions for a File Type"</a> for more information).
+<br>
+On success 0 (zero) is returned. On failure -1 is returned and errno is set.
+</dd>
+<!-- SM_IO_GETINFO -->
+<p></p>
+<dt><tt><a name="sm_io_getinfo">
+int
+<br>
+sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)
+</a></tt></dt>
+<dd>
+For the open file <i>sfp</i> get the indicated information (<i>what</i>)
+and place the result in <i>(valp</i>).
+This will obtain information for SM_FILE_T only and may be different than
+the information for the file type it was originally opened as.
+The value of <i>what</i> will be file type dependant since this function
+is one of the per file type setable functions.
+One value for <i>what</i> that is valid for all file types is
+SM_WHAT_VECTORS. This gets from the currently open file a copy of
+the function vectors and stores them in <i>valp</i> a SM_FILE_T
+(see <a href="#writefunctions">
+"Writing Functions for a File Type"</a> for more information).
+<br>
+On success 0 (zero) is returned. On failure -1 is returned and errno is set.
+</dd>
+<!-- SM_IO_AUTOFLUSH -->
+<p></p>
+<dt><tt><a name="sm_io_autoflush">
+void
+<br>
+sm_io_autoflush(SM_FILE_T *fp1, *SM_FILE_T fp2)
+</a></tt></dt>
+<dd>
+Associate a read of <i>fp1</i> with a data flush for <i>fp2</i>. If a read
+of <i>fp1</i> discovers that there is no data available to be read, then
+<i>fp2</i> will have it's data buffer flushed for writable data. It is
+assumed that <i>fp1</i> is open for reading and <i>fp2</i> is open
+for writing.
+<br>
+On return the old file pointer associated with <i>fp1</i> for flushing
+is returned. A return of NULL is no an error; this merely indicates no
+previous association.
+</dd>
+<!-- SM_IO_AUTOMODE -->
+<p></p>
+<dt><tt><a name="sm_io_automode">
+void
+<br>
+sm_io_automode(SM_FILE_T *fp1, *SM_FILE_T fp2)
+<dt><tt><a name="sm_io_automode">
+</a></tt></dt>
+<dd>
+Associate the two file pointers for blocking/non-blocking mode changes.
+In the handling of timeouts <i>sm_io</i> may need to switch the mode of
+a file between blocking and non-blocking. If the underlying file descriptor
+has been duplicated with <tt>dup(2)</tt> and these descriptors are used
+by <i>sm_io</i> (for example with an SmFtStdiofd file type), then this API
+should be called to associate them. Otherwise odd behavior (i.e. errors)
+may result that is not consistently reproducable nor easily identifiable.
+</dd>
+<!-- SM_IO_CLOSE -->
+<p></p>
+<dt><tt><a name="sm_io_close">
+int
+<br>
+sm_io_close(SM_FILE_T *sfp, int timeout)
+</a></tt></dt>
+<dd>
+Release all resources (file handles, memory, etc.) associated with
+the open SM_FILE_T <i>sfp</i>. If buffering is active then the
+buffer is flushed before any resources are released.
+<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
+section.
+The first resources released after buffer flushing will be the
+buffer itself. Then the <b>close</b> function specified in the
+file type at open will be called. It is the responsibility
+of the <b>close</b> function to release any file type
+specific resources allocated and to call <tt>sm_io_close()</tt>
+for the next file type layer(s) that the current file type uses (if any).
+<br>
+On success 0 (zero) is returned. On failure SM_IO_EOF is returned and
+errno is set.
+</dd>
+</dl>
+<h2>
+<a name="builtins">Description of Builtin File Types</a>
+</h2>
+<p>
+There are several builtin file types as mentioned in <tt>sm_io_open()</tt>.
+More file types may be added later.
+</p>
+<dl>
+<p></p>
+<dt><tt>SmFtString</tt></dt>
+<dd>
+Operates on a character string. <i>SmFtString</i> is a file type only.
+The string starts at the location 0 (zero)
+and ends at the last character. A read will obtain the requested
+number of characters if available; else as many as possible. A read
+will not terminate the read characters with a NULL ('\0'). A write
+will place the number of requested characters at the current location.
+To append to a string either the pointer must currently be at the end
+of the string or a seek done to position the pointer. The file type
+handles the space needed for the string. Thus space needed for the
+string will be grown automagically without the user worrying about
+space management.
+</dd>
+<dt><tt>SmFtStdio</tt></dt>
+<dd>
+A predefined SM_FILE_T structure with function vectors pointing to
+functions that result in the file-type behaving as the system stdio
+normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
+is the path of the file to be opened. Note that this file type
+does not interact with the system's stdio. Thus a program mixing system
+stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
+and output.
+</dd>
+<dt><tt>SmFtStdiofd</tt></dt>
+<dd>
+A predefined SM_FILE_T structure with function vectors pointing to
+functions that result in the file-type behaving as the system stdio
+normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
+is a file descriptor (the value returned by open(2)). Note that this file type
+does not interact with the system's stdio. Thus a program mixing system
+stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
+and output.
+</dd>
+<dt><tt>smioin</tt></dt>
+<dt><tt>smioout</tt></dt>
+<dt><tt>smioerr</tt></dt>
+<dd>
+The three types <i>smioin</i>, <i>smioout</i> and <i>smioerr</i> are grouped
+together. These three types
+perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
+and <i>stderr</i>. These types are both the names and the file pointers.
+They are already open when a program starts (unless the parent explictly
+closed file descriptors 0, 1 and 2).
+Thus <tt>sm_io_open()</tt> should never be called for these types:
+the named file pointers should be used directly.
+<i>Smioin</i> and <i>smioout</i> are buffered
+by default. <i>Smioerr</i> is not buffered by default. Calls to <b>stdio</b>
+are safe to make when using these three<b>sm_io</b> file pointers.
+There is no interaction between <b>sm_io</b> and <b>stdio</b>. Hence,
+due to buffering, the sequence of input and output data from both <b>sm_io</b>
+and <b>stdio</b> at the same time may appear unordered. For
+coordination between <b>sm_io</b> and <b>stdio</b> use the three
+file pointers below (<i>smiostdin, smiostdout, smiostderr</i>).
+</dd>
+<dt><tt>smiostdin</tt></dt>
+<dt><tt>smiostdout</tt></dt>
+<dt><tt>smiostderr</tt></dt>
+<dd>
+The three types <i>smiostdin</i>, <i>smioostdut</i> and <i>smiostderr</i>
+are grouped together. These three types
+perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
+and <i>stderr</i>. These types are both the names and file pointers.
+They are already open when a program starts (unless the parent explictly
+close file descriptors 0, 1 and 2).
+Thus <tt>sm_io_open()</tt> should
+never be called: the named file pointers should be used directly.
+Calls to <b>stdio</b> are safe to make when using these three<b>sm_io</b>
+file pointers though no code is shared between the two libaries.
+However, the input and output between <i>sm_io</i> and <i>stdio</i> is
+coordinated for these three file pointers: <i>smiostdin</i>,
+<i>smiostdout</i> and <i>smiostderr</i> are layered on-top-of
+the system's <i>stdio</i>.
+<i>Smiostdin</i>, <i>smiostdout</i>
+and <i>Smiostderr</i> are not buffered by default.
+Hence, due to buffering in <i>stdio</i> only, the sequence of input and
+output data from both <b>sm_io</b> and <b>stdio</b> at the same time will
+appear ordered. If <i>sm_io</i> buffering is turned on then the
+input and output can appear unordered or lost.
+</dd>
+<dt><tt>SmFtSyslog</tt></dt>
+<dd>
+This opens the channel to the system log. Reads are not allowed. Writes
+cannot be undone once they have left the <i>sm_io</i> buffer.
+The man pages for <tt>syslog(3)</tt> should be read for information
+on syslog.
+</dd>
+</dl>
+<p></p>
+<hr>
+<p></p>
+<h2>
+<a name="writefunctions">
+Writing Functions for a File Type
+</a>
+</h2>
+<p>
+When writing functions to create a file type a function needs to
+be created for each function vector in the SM_FILE_T structure
+that will be passed to <tt>sm_io_open()</tt> or <tt>sm_io_setinfo()</tt>.
+Otherwise the setting will be rejected and <i>errno</i> set to EINVAL.
+Each function should accept and handle the number and types of arguments as
+described in the portion of the SM_FILE_T structure shown below:
+</p>
+<pre>
+ int (*open) __P((SM_FILE_T *fp, const void *, int flags,
+ const void *rpool));
+ int (*close) __P((SM_FILE_T *fp));
+ int (*read) __P((SM_FILE_T *fp, char *buf, size_t size));
+ int (*write) __P((SM_FILE_T *fp, const char *buf, size_t size));
+ off_t (*seek) __P((SM_FILE_T *fp, off_t offset, int whence));
+ int (*getinfo) __P((SM_FILE_T *fp, int what, void *valp));
+ int (*setinfo) __P((SM_FILE_T *fp, int what, void *valp));
+</pre>
+<p>
+The macro SM_IO_SET_TYPE should be used to initialized an SM_FILE_T as a file
+type for an <tt>sm_io_open()</tt>:
+<menu>
+<pre>
+SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
+</pre>
+<br>
+where:
+<menu>
+<li>
+type - is the SM_FILE_T being filled-in
+</li>
+<li>
+name - a human readable character string for human identification purposes
+</li>
+<li>
+open - the vector to the open function
+</li>
+<li>
+close - the vector to the close function
+</li>
+<li>
+read - the vector to the read function
+</li>
+<li>
+write - the vector to the write function
+</li>
+<li>
+seek - the vector to the seek function
+</li>
+<li>
+set - the vector to the set function
+</li>
+<li>
+get - the vector to the get function
+</li>
+<li>
+timeout - the default to be used for a timeout when SM_TIME_DEFAULT specified
+</li>
+</menu>
+</menu>
+You should avoid trying to change or use the other structure members of the
+SM_FILE_T. The file pointer content (internal structure members) of an active
+file should only be set and observed with the "info" functions.
+The two exceptions to the above statement are the structure members
+<i>cookie</i> and <i>ival</i>. <i>Cookie</i> is of type <tt>void *</tt>
+while <i>ival</i> is of type <tt>int</tt>. These two structure members exist
+specificly for your created file type to use. The <i>sm_io</i> functions
+will not change or set these two structure members; only specific file type
+will change or set these variables.
+</p>
+<p>
+For maintaining information privately about status for a file type the
+information should be encapsulated in a <i>cookie</i>. A <i>cookie</i>
+is an opaque type that contains information that is only known to
+the file type layer itself. The <i>sm_io</i> package will know
+nothing about the contents of the <i>cookie</i>; <i>sm_io</i> only
+maintains the location of the <i>cookie</i> so that it may be passed
+to the functions of a file type. It is up to the file type to
+determine what to do with the <i>cookie</i>. It is the responsibility
+of the file type's open to create the cookie and point the SM_FILE_T's
+<i>cookie</i> at the address of the cookie.
+It is the responsibility of close to clean up
+any resources that the cookie and instance of the file type have used.
+</p>
+<p>
+For the <i>cookie</i> to be passed to all members of a function type
+cleanly the location of the cookie must assigned during
+the call to open. The file type functions should not attempt to
+maintain the <i>cookie</i> internally since the file type may have
+serveral instances (file pointers).
+</p>
+<p>
+The SM_FILE_T's member <i>ival</i> may be used in a manner similar to
+<i>cookie</i>. It is not to be used for maintaining the file's offset
+or access status (other members do that). It is intended as a "light"
+reference.
+</p>
+<p>
+The file type vector functions are called by the <tt>sm_io_*()</tt>
+functions after <i>sm_io</i> processing has occurred. The <i>sm_io</i>
+processing validates SM_FILE_T's and may then handle the call entirely
+itself or pass the request to the file type vector functions.
+</p>
+<p>
+All of the "int" functions should return -1 (minus one) on failure
+and 0 (zero) or greater on success. <i>Errno</i> should be set to
+provide diagnostic information to the caller if it has not already
+been set by another function the file type function used.
+</p>
+<p>
+Examples are a wonderful manner of clarifying details. Below is an example
+of an open function.
+</p>
+<p>
+This shows the setup.
+<menu>
+<pre>
+SM_FILE_T *fp;
+SM_FILE_T SM_IO_SET_TYPE(vector, "my_type", myopen, myclose, myread, mywrite,
+ myseek, myget, myset, SM_TIME_FOREVER);
+
+fp = sm_io_open(&vector, 1000, "data", SM_IO_RDONLY, NULL);
+
+if (fp == NULL)
+ return(-1);
+</pre>
+The above code open's a file of type "my_type". The <i>info</i> is set
+to a string "data". "data" may be the name of a file or have some special
+meaning to the file type. For sake of the example, we will have it be
+the name of a file in the home directory of the user running the program.
+Now the only file type function that is dependent on this information
+will be the open function.
+<br>
+We have also specified read-only access (SM_IO_RDONLY) and that no <i>rpool</i>
+will be used. The <i>timeout</i> has been set to 1000 milliseconds which
+directs that the file and all associated setup should be done within
+1000 milliseconds or return that the function erred (with errno==EAGAIN).
+<pre>
+int myopen(fp, info, flags, rpools)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ void *rpool;
+{
+ /*
+ ** now we could do the open raw (i.e with read(2)), but we will
+ ** use file layering instead. We will use the <i>stdio</i> file
+ ** type (different than the system's stdio).
+ */
+ struct passwd *pw;
+ char path[PATH_MAX];
+
+ pw = getpwuid(getuid());
+ sm_io_snprintf(path, PATH_MAX, "%s/%s", pw->pw_dir, info);
+
+ /*
+ ** Okay. Now the path pass-in has been prefixed with the
+ ** user's HOME directory. We'll call the regular stdio (SmFtStdio)
+ ** now to handle the rest of the open.
+ */
+ fp->cookie = sm_io_open(SmFtStdio, path, flags, rpools);
+ if (fp->cookie == NULL)
+ return(-1) /* errno set by sm_io_open call */
+ else
+ return(0);
+}
+</pre>
+Later on when a write is performed the function <tt>mywrite</tt> will
+be invoked. To match the above <tt>myopen</tt>, <tt>mywrite</tt> could
+be written as:
+<pre>
+int mywrite(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t size;
+{
+ /*
+ ** As an example, we can change, modify, refuse, filter, etc.
+ ** the content being passed through before we ask the SmFtStdio
+ ** to do the actual write.
+ ** This example is very simple and contrived, but this keeps it
+ ** clear.
+ */
+ if (size == 0)
+ return(0); /* why waste the cycles? */
+ if (*buf == 'X')
+ *buf = 'Y';
+
+ /*
+ ** Note that the file pointer passed to the next level is the
+ ** one that was stored in the cookie during the open.
+ */
+ return(sm_io_write(fp->cookie, buf, size));
+}
+</pre>
+As a thought-exercise for the fair reader: how would you modify the
+above two functions to make a "tee". That is the program will call
+<tt>sm_io_open</tt> or <tt>sm_io_write</tt> and two or more files will
+be opened and written to. (Hint: create a cookie to hold two or more
+file pointers).
+</menu>
+</p>
+<p></p>
+<hr>
+<br>
+<hr>
+<p></p>
+<center>
+<h1>
+<a name="defaultapi">
+libsm sm_io default API definition
+</a>
+</h1>
+</center>
+<h2> Introduction </h2>
+<p>
+A number of <i>sm_io</i> API's perform similar to their <i>stdio</i>
+counterparts (same name as when the "sm_io_" is removed).
+One difference between <i>sm_io</i> and <i>stdio</i> functions is that
+if a "file pointer" (FILE/SM_FILE_T)
+is one of the arguments for the function, then it is now the first
+argument. <i>Sm_io</i> is standardized so that when a file pointer is
+one of the arguments to function then it will always be the first
+arguement. Many of the <i>sm_io</i> function take a <i>timeout</i>
+argument (see <a href="#timeouts"><b>Timeouts</b></a>).
+</p>
+<p>
+The API you have selected is one of these. Please consult the
+appropriate <i>stdio</i> man page for now.
+</p>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c
new file mode 100644
index 0000000..a431511
--- /dev/null
+++ b/contrib/sendmail/libsm/ldap.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")
+
+#if LDAPMAP
+# include <sys/types.h>
+# include <errno.h>
+# include <setjmp.h>
+# include <stdlib.h>
+# include <unistd.h>
+
+# include <sm/bitops.h>
+# include <sm/clock.h>
+# include <sm/conf.h>
+# include <sm/debug.h>
+# include <sm/errstring.h>
+# include <sm/ldap.h>
+# include <sm/string.h>
+# include <sm/sysexits.h>
+
+SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
+ "@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
+
+static void ldaptimeout __P((int));
+
+/*
+** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
+**
+** Parameters:
+** lmap -- pointer to SM_LDAP_STRUCT to clear
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_clear(lmap)
+ SM_LDAP_STRUCT *lmap;
+{
+ if (lmap == NULL)
+ return;
+
+ lmap->ldap_host = NULL;
+ lmap->ldap_port = LDAP_PORT;
+ lmap->ldap_deref = LDAP_DEREF_NEVER;
+ lmap->ldap_timelimit = LDAP_NO_LIMIT;
+ lmap->ldap_sizelimit = LDAP_NO_LIMIT;
+# ifdef LDAP_REFERRALS
+ lmap->ldap_options = LDAP_OPT_REFERRALS;
+# else /* LDAP_REFERRALS */
+ lmap->ldap_options = 0;
+# endif /* LDAP_REFERRALS */
+ lmap->ldap_attrsep = '\0';
+ lmap->ldap_binddn = NULL;
+ lmap->ldap_secret = NULL;
+ lmap->ldap_method = LDAP_AUTH_SIMPLE;
+ lmap->ldap_base = NULL;
+ lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
+ lmap->ldap_attrsonly = LDAPMAP_FALSE;
+ lmap->ldap_timeout.tv_sec = 0;
+ lmap->ldap_timeout.tv_usec = 0;
+ lmap->ldap_ld = NULL;
+ lmap->ldap_filter = NULL;
+ lmap->ldap_attr[0] = NULL;
+#if _FFR_LDAP_RECURSION
+ lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL;
+ lmap->ldap_attr_final[0] = NULL;
+#endif /* _FFR_LDAP_RECURSION */
+ lmap->ldap_res = NULL;
+ lmap->ldap_next = NULL;
+ lmap->ldap_pid = 0;
+}
+
+/*
+** SM_LDAP_START -- actually connect to an LDAP server
+**
+** Parameters:
+** name -- name of map for debug output.
+** lmap -- the LDAP map being opened.
+**
+** Returns:
+** true if connection is successful, false otherwise.
+**
+** Side Effects:
+** Populates lmap->ldap_ld.
+*/
+
+static jmp_buf LDAPTimeout;
+
+#define SM_LDAP_SETTIMEOUT(to) \
+do \
+{ \
+ if (to != 0) \
+ { \
+ if (setjmp(LDAPTimeout) != 0) \
+ { \
+ errno = ETIMEDOUT; \
+ return false; \
+ } \
+ ev = sm_setevent(to, ldaptimeout, 0); \
+ } \
+} while (0)
+
+#define SM_LDAP_CLEARTIMEOUT() \
+do \
+{ \
+ if (ev != NULL) \
+ sm_clrevent(ev); \
+} while (0)
+
+bool
+sm_ldap_start(name, lmap)
+ char *name;
+ SM_LDAP_STRUCT *lmap;
+{
+ int bind_result;
+ int save_errno;
+ SM_EVENT *ev = NULL;
+ LDAP *ld;
+
+ if (sm_debug_active(&SmLDAPTrace, 2))
+ sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
+
+ if (sm_debug_active(&SmLDAPTrace, 9))
+ sm_dprintf("ldapmap_start(%s, %d)\n",
+ lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
+ lmap->ldap_port);
+
+# if USE_LDAP_INIT
+ ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
+ save_errno = errno;
+# else /* USE_LDAP_INIT */
+ /*
+ ** If using ldap_open(), the actual connection to the server
+ ** happens now so we need the timeout here. For ldap_init(),
+ ** the connection happens at bind time.
+ */
+
+ SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
+ ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
+ save_errno = errno;
+
+ /* clear the event if it has not sprung */
+ SM_LDAP_CLEARTIMEOUT();
+# endif /* USE_LDAP_INIT */
+
+ errno = save_errno;
+ if (ld == NULL)
+ return false;
+
+ sm_ldap_setopts(ld, lmap);
+
+# if USE_LDAP_INIT
+ /*
+ ** If using ldap_init(), the actual connection to the server
+ ** happens at ldap_bind_s() so we need the timeout here.
+ */
+
+ SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
+# endif /* USE_LDAP_INIT */
+
+# ifdef LDAP_AUTH_KRBV4
+ if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
+ lmap->ldap_secret != NULL)
+ {
+ /*
+ ** Need to put ticket in environment here instead of
+ ** during parseargs as there may be different tickets
+ ** for different LDAP connections.
+ */
+
+ (void) putenv(lmap->ldap_secret);
+ }
+# endif /* LDAP_AUTH_KRBV4 */
+
+ bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
+ lmap->ldap_secret, lmap->ldap_method);
+
+# if USE_LDAP_INIT
+ /* clear the event if it has not sprung */
+ SM_LDAP_CLEARTIMEOUT();
+# endif /* USE_LDAP_INIT */
+
+ if (bind_result != LDAP_SUCCESS)
+ {
+ errno = bind_result + E_LDAPBASE;
+ return false;
+ }
+
+ /* Save PID to make sure only this PID closes the LDAP connection */
+ lmap->ldap_pid = getpid();
+ lmap->ldap_ld = ld;
+ return true;
+}
+
+/* ARGSUSED */
+static void
+ldaptimeout(unused)
+ int unused;
+{
+ /*
+ ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+ ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+ ** DOING.
+ */
+
+ errno = ETIMEDOUT;
+ longjmp(LDAPTimeout, 1);
+}
+
+/*
+** SM_LDAP_SEARCH -- iniate LDAP search
+**
+** Initiate an LDAP search, return the msgid.
+** The calling function must collect the results.
+**
+** Parameters:
+** lmap -- LDAP map information
+** key -- key to substitute in LDAP filter
+**
+** Returns:
+** -1 on failure, msgid on success
+**
+*/
+
+int
+sm_ldap_search(lmap, key)
+ SM_LDAP_STRUCT *lmap;
+ char *key;
+{
+ int msgid;
+ char *fp, *p, *q;
+ char filter[LDAPMAP_MAX_FILTER + 1];
+
+ /* substitute key into filter, perhaps multiple times */
+ memset(filter, '\0', sizeof filter);
+ fp = filter;
+ p = lmap->ldap_filter;
+ while ((q = strchr(p, '%')) != NULL)
+ {
+ if (q[1] == 's')
+ {
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s%s", (int) (q - p), p, key);
+ fp += strlen(fp);
+ p = q + 2;
+ }
+ else if (q[1] == '0')
+ {
+ char *k = key;
+
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s", (int) (q - p), p);
+ fp += strlen(fp);
+ p = q + 2;
+
+ /* Properly escape LDAP special characters */
+ while (SPACELEFT(filter, fp) > 0 &&
+ *k != '\0')
+ {
+ if (*k == '*' || *k == '(' ||
+ *k == ')' || *k == '\\')
+ {
+ (void) sm_strlcat(fp,
+ (*k == '*' ? "\\2A" :
+ (*k == '(' ? "\\28" :
+ (*k == ')' ? "\\29" :
+ (*k == '\\' ? "\\5C" :
+ "\00")))),
+ SPACELEFT(filter, fp));
+ fp += strlen(fp);
+ k++;
+ }
+ else
+ *fp++ = *k++;
+ }
+ }
+ else
+ {
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s", (int) (q - p + 1), p);
+ p = q + (q[1] == '%' ? 2 : 1);
+ fp += strlen(fp);
+ }
+ }
+ (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
+ if (sm_debug_active(&SmLDAPTrace, 20))
+ sm_dprintf("ldap search filter=%s\n", filter);
+
+ lmap->ldap_res = NULL;
+ msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
+ filter,
+ (lmap->ldap_attr[0] == NULL ? NULL :
+ lmap->ldap_attr),
+ lmap->ldap_attrsonly);
+ return msgid;
+}
+
+# if _FFR_LDAP_RECURSION
+/*
+** SM_LDAP_RESULTS -- return results from an LDAP lookup in result
+**
+** Parameters:
+** lmap -- pointer to SM_LDAP_STRUCT in use
+** msgid -- msgid returned by sm_ldap_search()
+** flags -- flags for the lookup
+** delim -- delimiter for result concatenation
+** rpool -- memory pool for storage
+** result -- return string
+** recurse -- recursion list
+**
+** Returns:
+** status (sysexit)
+*/
+
+# define LDAPMAP_ERROR_CLEANUP() \
+{ \
+ if (lmap->ldap_res != NULL) \
+ { \
+ ldap_msgfree(lmap->ldap_res); \
+ lmap->ldap_res = NULL; \
+ } \
+ (void) ldap_abandon(lmap->ldap_ld, msgid); \
+}
+
+static int
+ldapmap_add_recurse(top, item, type, rpool)
+ SM_LDAP_RECURSE_LIST **top;
+ char *item;
+ int type;
+ SM_RPOOL_T *rpool;
+{
+ SM_LDAP_RECURSE_LIST *p;
+ SM_LDAP_RECURSE_LIST *last;
+
+ last = NULL;
+ for (p = *top; p != NULL; p = p->lr_next)
+ {
+ if (strcasecmp(item, p->lr_search) == 0 &&
+ type == p->lr_type)
+ {
+ /* already on list */
+ return 1;
+ }
+ last = p;
+ }
+
+ /* not on list, add it */
+ p = sm_rpool_malloc_x(rpool, sizeof *p);
+ p->lr_search = sm_rpool_strdup_x(rpool, item);
+ p->lr_type = type;
+ p->lr_next = NULL;
+ if (last == NULL)
+ *top = p;
+ else
+ last->lr_next = p;
+ return 0;
+}
+
+int
+sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
+ SM_LDAP_STRUCT *lmap;
+ int msgid;
+ int flags;
+ char delim;
+ SM_RPOOL_T *rpool;
+ char **result;
+ SM_LDAP_RECURSE_LIST *recurse;
+{
+ bool toplevel;
+ int i;
+ int entries = 0;
+ int statp;
+ int vsize;
+ int ret;
+ int save_errno;
+ char *p;
+
+ /* Are we the top top level of the search? */
+ toplevel = (recurse == NULL);
+
+ /* Get results */
+ statp = EX_NOTFOUND;
+ while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
+ (lmap->ldap_timeout.tv_sec == 0 ? NULL :
+ &(lmap->ldap_timeout)),
+ &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
+ {
+ LDAPMessage *entry;
+
+ if (bitset(SM_LDAP_SINGLEMATCH, flags))
+ {
+ entries += ldap_count_entries(lmap->ldap_ld,
+ lmap->ldap_res);
+ if (entries > 1)
+ {
+ LDAPMAP_ERROR_CLEANUP();
+ errno = ENOENT;
+ return EX_NOTFOUND;
+ }
+ }
+
+ /* If we don't want multiple values and we have one, break */
+ if (delim == '\0' && *result != NULL)
+ break;
+
+ /* Cycle through all entries */
+ for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
+ entry != NULL;
+ entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
+ {
+ BerElement *ber;
+ char *attr;
+ char **vals = NULL;
+ char *dn;
+
+ /*
+ ** If matching only and found an entry,
+ ** no need to spin through attributes
+ */
+
+ if (statp == EX_OK &&
+ bitset(SM_LDAP_MATCHONLY, flags))
+ continue;
+
+ /* record completed DN's to prevent loops */
+ dn = ldap_get_dn(lmap->ldap_ld, entry);
+ if (dn == NULL)
+ {
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ save_errno += E_LDAPBASE;
+ LDAPMAP_ERROR_CLEANUP();
+ errno = save_errno;
+ return EX_OSERR;
+ }
+
+ switch (ldapmap_add_recurse(&recurse, dn,
+ LDAPMAP_ATTR_NORMAL,
+ rpool))
+ {
+ case -1:
+ /* error adding */
+ ldap_memfree(dn);
+ LDAPMAP_ERROR_CLEANUP();
+ errno = ENOMEM;
+ return EX_OSERR;
+
+ case 1:
+ /* already on list, skip it */
+ ldap_memfree(dn);
+ continue;
+ }
+ ldap_memfree(dn);
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
+ &ber);
+ attr != NULL;
+ attr = ldap_next_attribute(lmap->ldap_ld, entry,
+ ber))
+ {
+ char *tmp, *vp_tmp;
+ int type;
+
+ for (i = 0; lmap->ldap_attr[i] != NULL; i++)
+ {
+ if (sm_strcasecmp(lmap->ldap_attr[i],
+ attr) == 0)
+ {
+ type = lmap->ldap_attr_type[i];
+ break;
+ }
+ }
+ if (lmap->ldap_attr[i] == NULL)
+ {
+ /* attribute not requested */
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ LDAPMAP_ERROR_CLEANUP();
+ errno = EFAULT;
+ return EX_SOFTWARE;
+ }
+
+ if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
+ {
+ vals = ldap_get_values(lmap->ldap_ld,
+ entry,
+ attr);
+ if (vals == NULL)
+ {
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno == LDAP_SUCCESS)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+
+ /* Must be an error */
+ save_errno += E_LDAPBASE;
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ LDAPMAP_ERROR_CLEANUP();
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+ }
+
+ statp = EX_OK;
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ /*
+ ** If matching only,
+ ** no need to spin through entries
+ */
+
+ if (bitset(SM_LDAP_MATCHONLY, flags))
+ {
+ if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
+ ldap_value_free(vals);
+
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+
+ /*
+ ** If we don't want multiple values,
+ ** return first found.
+ */
+
+ if (delim == '\0')
+ {
+ if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
+ {
+ *result = sm_rpool_strdup_x(rpool,
+ attr);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ break;
+ }
+
+ if (vals[0] == NULL)
+ {
+ ldap_value_free(vals);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+
+ vsize = strlen(vals[0]) + 1;
+ if (lmap->ldap_attrsep != '\0')
+ vsize += strlen(attr) + 1;
+ *result = sm_rpool_malloc_x(rpool,
+ vsize);
+ if (lmap->ldap_attrsep != '\0')
+ sm_snprintf(*result, vsize,
+ "%s%c%s",
+ attr,
+ lmap->ldap_attrsep,
+ vals[0]);
+ else
+ sm_strlcpy(*result, vals[0],
+ vsize);
+ ldap_value_free(vals);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ break;
+ }
+
+ /* attributes only */
+ if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
+ {
+ if (*result == NULL)
+ *result = sm_rpool_strdup_x(rpool,
+ attr);
+ else
+ {
+ vsize = strlen(*result) +
+ strlen(attr) + 2;
+ tmp = sm_rpool_malloc_x(rpool,
+ vsize);
+ (void) sm_snprintf(tmp,
+ vsize, "%s%c%s",
+ *result, delim,
+ attr);
+ *result = tmp;
+ }
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+
+ /*
+ ** If there is more than one,
+ ** munge then into a map_coldelim
+ ** separated string
+ */
+
+ vsize = 0;
+ for (i = 0; vals[i] != NULL; i++)
+ {
+ if (type == LDAPMAP_ATTR_DN ||
+ type == LDAPMAP_ATTR_FILTER ||
+ type == LDAPMAP_ATTR_URL)
+ {
+ if (ldapmap_add_recurse(&recurse,
+ vals[i],
+ type) < 0)
+ {
+ LDAPMAP_ERROR_CLEANUP();
+ errno = ENOMEM;
+ return EX_OSERR;
+ }
+ }
+ if (type != LDAPMAP_ATTR_NORMAL)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+ vsize += strlen(vals[i]) + 1;
+ if (lmap->ldap_attrsep != '\0')
+ vsize += strlen(attr) + 1;
+ }
+ vp_tmp = sm_rpool_malloc_x(rpool, vsize);
+ *vp_tmp = '\0';
+
+ p = vp_tmp;
+ for (i = 0; vals[i] != NULL; i++)
+ {
+ if (lmap->ldap_attrsep != '\0')
+ {
+ p += sm_strlcpy(p, attr,
+ vsize - (p - vp_tmp));
+ *p++ = lmap->ldap_attrsep;
+ }
+ p += sm_strlcpy(p, vals[i],
+ vsize - (p - vp_tmp));
+ if (p >= vp_tmp + vsize)
+ {
+ /* Internal error: buffer too small for LDAP values */
+ LDAPMAP_ERROR_CLEANUP();
+ errno = ENOMEM;
+ return EX_OSERR;
+ }
+ if (vals[i + 1] != NULL)
+ *p++ = delim;
+ }
+
+ ldap_value_free(vals);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ if (*result == NULL)
+ {
+ *result = vp_tmp;
+ continue;
+ }
+ vsize = strlen(*result) + strlen(vp_tmp) + 2;
+ tmp = sm_rpool_malloc_x(rpool, vsize);
+ (void) sm_snprintf(tmp, vsize, "%s%c%s",
+ *result, delim, vp_tmp);
+ *result = tmp;
+ }
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+
+ /*
+ ** We check save_errno != LDAP_DECODING_ERROR since
+ ** OpenLDAP 1.X has a very ugly *undocumented*
+ ** hack of returning this error code from
+ ** ldap_next_attribute() if the library freed the
+ ** ber attribute. See:
+ ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
+ */
+
+ if (save_errno != LDAP_SUCCESS &&
+ save_errno != LDAP_DECODING_ERROR)
+ {
+ /* Must be an error */
+ save_errno += E_LDAPBASE;
+ LDAPMAP_ERROR_CLEANUP();
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+
+ /* We don't want multiple values and we have one */
+ if (delim == '\0' && *result != NULL)
+ break;
+ }
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno != LDAP_SUCCESS &&
+ save_errno != LDAP_DECODING_ERROR)
+ {
+ /* Must be an error */
+ save_errno += E_LDAPBASE;
+ LDAPMAP_ERROR_CLEANUP();
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+ ldap_msgfree(lmap->ldap_res);
+ lmap->ldap_res = NULL;
+ }
+
+ if (ret == 0)
+ save_errno = ETIMEDOUT;
+ else
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno != LDAP_SUCCESS)
+ {
+ statp = EX_TEMPFAIL;
+ if (ret != 0)
+ {
+ switch (save_errno)
+ {
+#ifdef LDAP_SERVER_DOWN
+ case LDAP_SERVER_DOWN:
+#endif /* LDAP_SERVER_DOWN */
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
+ /* server disappeared, try reopen on next search */
+ statp = EX_RESTART;
+ break;
+ }
+ save_errno += E_LDAPBASE;
+ }
+ LDAPMAP_ERROR_CLEANUP();
+ errno = save_errno;
+ return statp;
+ }
+
+ if (lmap->ldap_res != NULL)
+ {
+ ldap_msgfree(lmap->ldap_res);
+ lmap->ldap_res = NULL;
+ }
+
+ if (toplevel)
+ {
+ SM_LDAP_RECURSE_LIST *rl;
+
+ /*
+ ** Spin through the built-up recurse list at the top
+ ** of the recursion. Since new items are added at the
+ ** end of the shared list, we actually only ever get
+ ** one level of recursion before things pop back to the
+ ** top. Any items added to the list during that recursion
+ ** will be expanded by the top level.
+ */
+
+ for (rl = recurse; rl != NULL; rl = rl->lr_next)
+ {
+ int sid;
+ int status;
+
+ if (rl->lr_type == LDAPMAP_ATTR_NORMAL)
+ {
+ /* already expanded */
+ continue;
+ }
+ else if (rl->lr_type == LDAPMAP_ATTR_DN)
+ {
+ /* do DN search */
+ sid = ldap_search(lmap->ldap_ld,
+ rl->lr_search,
+ lmap->ldap_scope,
+ "(objectClass=*)",
+ lmap->ldap_attr_final,
+ lmap->ldap_attrsonly);
+ }
+ else if (rl->lr_type == LDAPMAP_ATTR_FILTER)
+ {
+ /* do new search */
+ sid = ldap_search(lmap->ldap_ld,
+ lmap->ldap_base,
+ lmap->ldap_scope,
+ rl->lr_search,
+ lmap->ldap_attr_final,
+ lmap->ldap_attrsonly);
+ }
+ else if (rl->lr_type == LDAPMAP_ATTR_URL)
+ {
+ /* do new URL search */
+ sid = ldap_url_search(lmap->ldap_ld,
+ rl->lr_search,
+ lmap->ldap_attrsonly);
+ }
+ else
+ {
+ /* unknown or illegal attribute type */
+ errno = EFAULT;
+ return EX_SOFTWARE;
+ }
+
+ /* Collect results */
+ if (sid == -1)
+ {
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ statp = EX_TEMPFAIL;
+ switch (save_errno)
+ {
+#ifdef LDAP_SERVER_DOWN
+ case LDAP_SERVER_DOWN:
+#endif /* LDAP_SERVER_DOWN */
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
+ /* server disappeared, try reopen on next search */
+ statp = EX_RESTART;
+ break;
+ }
+ errno = save_errno + E_LDAPBASE;
+ return statp;
+ }
+
+ status = sm_ldap_results(lmap, sid, flags, delim,
+ rpool, result, recurse);
+ save_errno = errno;
+ if (status != EX_OK && status != EX_NOTFOUND)
+ {
+ errno = save_errno;
+ return status;
+ }
+
+ /* Mark as done */
+ rl->lr_type = LDAPMAP_ATTR_NORMAL;
+ }
+ }
+ return statp;
+}
+#endif /* _FFR_LDAP_RECURSION */
+
+/*
+** SM_LDAP_CLOSE -- close LDAP connection
+**
+** Parameters:
+** lmap -- LDAP map information
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_close(lmap)
+ SM_LDAP_STRUCT *lmap;
+{
+ if (lmap->ldap_ld == NULL)
+ return;
+
+ if (lmap->ldap_pid == getpid())
+ ldap_unbind(lmap->ldap_ld);
+ lmap->ldap_ld = NULL;
+ lmap->ldap_pid = 0;
+}
+
+/*
+** SM_LDAP_SETOPTS -- set LDAP options
+**
+** Parameters:
+** ld -- LDAP session handle
+** lmap -- LDAP map information
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_setopts(ld, lmap)
+ LDAP *ld;
+ SM_LDAP_STRUCT *lmap;
+{
+# if USE_LDAP_SET_OPTION
+ ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
+ if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
+ ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
+ else
+ ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
+ ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
+# else /* USE_LDAP_SET_OPTION */
+ /* From here on in we can use ldap internal timelimits */
+ ld->ld_deref = lmap->ldap_deref;
+ ld->ld_options = lmap->ldap_options;
+ ld->ld_sizelimit = lmap->ldap_sizelimit;
+ ld->ld_timelimit = lmap->ldap_timelimit;
+# endif /* USE_LDAP_SET_OPTION */
+}
+
+/*
+** SM_LDAP_GETERRNO -- get ldap errno value
+**
+** Parameters:
+** ld -- LDAP session handle
+**
+** Returns:
+** LDAP errno.
+**
+*/
+
+int
+sm_ldap_geterrno(ld)
+ LDAP *ld;
+{
+ int err = LDAP_SUCCESS;
+
+# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
+ (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
+# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
+# ifdef LDAP_OPT_SIZELIMIT
+ err = ldap_get_lderrno(ld, NULL, NULL);
+# else /* LDAP_OPT_SIZELIMIT */
+ err = ld->ld_errno;
+
+ /*
+ ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see above)
+ */
+
+ ld->ld_errno = LDAP_SUCCESS;
+# endif /* LDAP_OPT_SIZELIMIT */
+# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
+ return err;
+}
+# endif /* LDAPMAP */
diff --git a/contrib/sendmail/libsm/local.h b/contrib/sendmail/libsm/local.h
new file mode 100644
index 0000000..f97859e
--- /dev/null
+++ b/contrib/sendmail/libsm/local.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * $Id: local.h,v 1.48 2001/05/14 20:42:29 gshapiro Exp $
+ */
+
+/*
+** Information local to this implementation of stdio,
+** in particular, macros and private variables.
+*/
+
+#include <sys/time.h>
+#if !SM_CONF_MEMCHR
+# include <memory.h>
+#endif /* !SM_CONF_MEMCHR */
+#include <sm/heap.h>
+
+int sm_flush __P((SM_FILE_T *, int *));
+SM_FILE_T *smfp __P((void));
+int sm_refill __P((SM_FILE_T *, int));
+void sm_init __P((void));
+void sm_cleanup __P((void));
+void sm_makebuf __P((SM_FILE_T *));
+int sm_whatbuf __P((SM_FILE_T *, size_t *, int *));
+int sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *));
+int sm_wsetup __P((SM_FILE_T *));
+int sm_flags __P((int));
+SM_FILE_T *sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *));
+int sm_vprintf __P((int, char const *, va_list));
+int sm_vfscanf __P((SM_FILE_T *, int, char const *, va_list));
+
+/* std io functions */
+ssize_t sm_stdread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_stdwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_stdseek __P((SM_FILE_T *, off_t, int));
+int sm_stdclose __P((SM_FILE_T *));
+int sm_stdopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdsetinfo __P((SM_FILE_T *, int , void *));
+int sm_stdgetinfo __P((SM_FILE_T *, int , void *));
+
+/* stdio io functions */
+ssize_t sm_stdioread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_stdiowrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_stdioseek __P((SM_FILE_T *, off_t, int));
+int sm_stdioclose __P((SM_FILE_T *));
+int sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdiosetinfo __P((SM_FILE_T *, int , void *));
+int sm_stdiogetinfo __P((SM_FILE_T *, int , void *));
+
+/* string io functions */
+ssize_t sm_strread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_strwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_strseek __P((SM_FILE_T *, off_t, int));
+int sm_strclose __P((SM_FILE_T *));
+int sm_stropen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_strsetinfo __P((SM_FILE_T *, int , void *));
+int sm_strgetinfo __P((SM_FILE_T *, int , void *));
+
+/* syslog io functions */
+ssize_t sm_syslogread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_syslogwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_syslogseek __P((SM_FILE_T *, off_t, int));
+int sm_syslogclose __P((SM_FILE_T *));
+int sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_syslogsetinfo __P((SM_FILE_T *, int , void *));
+int sm_sysloggetinfo __P((SM_FILE_T *, int , void *));
+
+/* should be defined in sys/time.h */
+#ifndef timersub
+# define timersub(tvp, uvp, vvp) \
+ do \
+ { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) \
+ { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* !timersub */
+
+#ifndef timeradd
+# define timeradd(tvp, uvp, vvp) \
+ do \
+ { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) \
+ { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif /* !timeradd */
+
+#ifndef timercmp
+# define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#endif /* !timercmp */
+
+extern bool Sm_IO_DidInit;
+
+/* Return true iff the given SM_FILE_T cannot be written now. */
+#define cantwrite(fp) \
+ ((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \
+ sm_wsetup(fp))
+
+/*
+** Test whether the given stdio file has an active ungetc buffer;
+** release such a buffer, without restoring ordinary unread data.
+*/
+
+#define HASUB(fp) ((fp)->f_ub.smb_base != NULL)
+#define FREEUB(fp) \
+{ \
+ if ((fp)->f_ub.smb_base != (fp)->f_ubuf) \
+ sm_free((char *)(fp)->f_ub.smb_base); \
+ (fp)->f_ub.smb_base = NULL; \
+}
+
+/* Test for an fgetln() buffer. */
+#define HASLB(fp) ((fp)->f_lb.smb_base != NULL)
+#define FREELB(fp) \
+{ \
+ sm_free((char *)(fp)->f_lb.smb_base); \
+ (fp)->f_lb.smb_base = NULL; \
+}
+
+struct sm_io_obj
+{
+ int file;
+};
+
+extern const char SmFileMagic[];
+
+#ifndef ALIGNBYTES
+# define ALIGNBYTES (sizeof(long) - 1)
+# define ALIGN(p) (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
+#endif /* ALIGNBYTES */
+
+#define sm_io_flockfile(fp) ((void) 0)
+#define sm_io_funlockfile(fp) ((void) 0)
+
+#ifndef FDSET_CAST
+# define FDSET_CAST /* empty cast for fd_set arg to select */
+#endif
+
+/*
+** SM_CONVERT_TIME -- convert the API timeout flag for select() usage.
+**
+** This takes a 'fp' (a file type pointer) and obtains the "raw"
+** file descriptor (fd) if possible. The 'fd' is needed to possibly
+** switch the mode of the file (blocking/non-blocking) to match
+** the type of timeout. If timeout is SM_TIME_FOREVER then the
+** timeout using select won't be needed and the file is best placed
+** in blocking mode. If there is to be a finite timeout then the file
+** is best placed in non-blocking mode. Then, if not enough can be
+** written, select() can be used to test when something can be written
+** yet still timeout if the wait is too long.
+** If the mode is already in the correct state we don't change it.
+** Iff (yes "iff") the 'fd' is "-1" in value then the mode change
+** will not happen. This situation arises when a late-binding-to-disk
+** file type is in use. An example of this is the sendmail buffered
+** file type (in sendmail/bf.c).
+**
+** Parameters
+** fp -- the file pointer the timeout is for
+** fd -- to become the file descriptor value from 'fp'
+** val -- the timeout value to be converted
+** time -- a struct timeval holding the converted value
+**
+** Returns
+** nothing, this is flow-through code
+**
+** Side Effects:
+** May or may not change the mode of a currently open file.
+** The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK
+** (meaning block). This is done to best match the type of
+** timeout and for (possible) use with select().
+*/
+
+# define SM_CONVERT_TIME(fp, fd, val, time) { \
+ if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \
+ { \
+ /* can't get an fd, likely internal 'fake' fp */ \
+ errno = 0; \
+ } \
+ if ((val) == SM_TIME_DEFAULT) \
+ (val) = (fp)->f_timeout; \
+ if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \
+ { \
+ (time)->tv_sec = 0; \
+ (time)->tv_usec = 0; \
+ } \
+ else \
+ { \
+ (time)->tv_sec = (val) / 1000; \
+ (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 10; \
+ } \
+ if ((val) == SM_TIME_FOREVER) \
+ { \
+ if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \
+ { \
+ int ret; \
+ ret = fcntl((fd), F_GETFL, 0); \
+ if (ret == -1 || fcntl((fd), F_SETFL, \
+ ret & ~O_NONBLOCK) == -1) \
+ { \
+ /* errno should be set */ \
+ return SM_IO_EOF; \
+ } \
+ (fp)->f_timeoutstate = SM_TIME_BLOCK; \
+ if ((fp)->f_modefp != NULL) \
+ (fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \
+ } \
+ } \
+ else { \
+ if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \
+ { \
+ int ret; \
+ ret = fcntl((fd), F_GETFL, 0); \
+ if (ret == -1 || fcntl((fd), F_SETFL, \
+ ret | O_NONBLOCK) == -1) \
+ { \
+ /* errno should be set */ \
+ return SM_IO_EOF; \
+ } \
+ (fp)->f_timeoutstate = SM_TIME_NONBLOCK; \
+ if ((fp)->f_modefp != NULL) \
+ (fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \
+ } \
+ } \
+}
+
+/*
+** SM_IO_WR_TIMEOUT -- setup the timeout for the write
+**
+** This #define uses a select() to wait for the 'fd' to become writable.
+** The select() can be active for up to 'to' time. The select may not
+** use all of the the 'to' time. Hence, the amount of "wall-clock" time is
+** measured to decide how much to subtract from 'to' to update it. On some
+** BSD-based/like systems the timeout for a select is updated for the
+** amount of time used. On many/most systems this does not happen. Therefore
+** the updating of 'to' must be done ourselves; a copy of 'to' is passed
+** since a BSD-like system will have updated it and we don't want to
+** double the time used!
+** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
+** sendmail buffered file type in sendmail/bf.c; see fvwrite.c).
+**
+** Parameters
+** fd -- a file descriptor for doing select() with
+** timeout -- the original user set value.
+**
+** Returns
+** nothing, this is flow through code
+**
+** Side Effects:
+** adjusts 'timeout' for time used
+*/
+
+#define SM_IO_WR_TIMEOUT(fp, fd, to) { \
+ struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
+ struct timeval sm_io_to; \
+ int sm_io_to_sel; \
+ fd_set sm_io_to_mask, sm_io_x_mask; \
+ errno = 0; \
+ if ((to) == SM_TIME_DEFAULT) \
+ (to) = (fp)->f_timeout; \
+ if ((to) == SM_TIME_IMMEDIATE) \
+ { \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ else if ((to) == SM_TIME_FOREVER) \
+ { \
+ errno = EINVAL; \
+ return SM_IO_EOF; \
+ } \
+ else \
+ { \
+ sm_io_to.tv_sec = (to) / 1000; \
+ sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 10; \
+ } \
+ FD_ZERO(&sm_io_to_mask); \
+ FD_SET((fd), &sm_io_to_mask); \
+ FD_ZERO(&sm_io_x_mask); \
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+ sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, &sm_io_x_mask, \
+ &sm_io_to); \
+ if (sm_io_to_sel < 0) \
+ { \
+ /* something went wrong, errno set */ \
+ return SM_IO_EOF; \
+ } \
+ else if (sm_io_to_sel == 0) \
+ { \
+ /* timeout */ \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ /* else loop again */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+ timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
+ timersub(&sm_io_to, &sm_io_to_diff, &sm_io_to); \
+ (to) -= (sm_io_to.tv_sec * 1000); \
+ (to) -= (sm_io_to.tv_usec / 10); \
+ if ((to) < 0) \
+ (to) = 0; \
+}
+
+/*
+** If there is no 'fd' just error (we can't timeout). If the timeout
+** is SM_TIME_FOREVER then there is no need to do a timeout with
+** select since this will be a real error. If the error is not
+** EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error.
+** Specify the condition here as macro so it can be used in several places.
+*/
+
+#define IS_IO_ERROR(fd, ret, to) \
+ ((fd) < 0 || \
+ ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || \
+ (to) == SM_TIME_FOREVER)
+
diff --git a/contrib/sendmail/libsm/makebuf.c b/contrib/sendmail/libsm/makebuf.c
new file mode 100644
index 0000000..044de8c
--- /dev/null
+++ b/contrib/sendmail/libsm/makebuf.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: makebuf.c,v 1.26 2001/10/31 16:04:08 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_MAKEBUF -- make a buffer for the file
+**
+** Parameters:
+** fp -- the file to be buffered
+**
+** Returns:
+** nothing
+**
+** Allocate a file buffer, or switch to unbuffered I/O.
+** By default tty devices default to line buffered.
+*/
+
+void
+sm_makebuf(fp)
+ register SM_FILE_T *fp;
+{
+ register void *p;
+ register int flags;
+ size_t size;
+ int couldbetty;
+
+ if (fp->f_flags & SMNBF)
+ {
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return;
+ }
+ flags = sm_whatbuf(fp, &size, &couldbetty);
+ if ((p = sm_malloc(size)) == NULL)
+ {
+ fp->f_flags |= SMNBF;
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return;
+ }
+ if (!Sm_IO_DidInit)
+ sm_init();
+ flags |= SMMBF;
+ fp->f_bf.smb_base = fp->f_p = p;
+ fp->f_bf.smb_size = size;
+ if (couldbetty && isatty(fp->f_file))
+ flags |= SMLBF;
+ fp->f_flags |= flags;
+}
+
+/*
+** SM_WHATBUF -- determine proper buffer for a file (internal)
+**
+** Plus it fills in 'bufsize' for recommended buffer size and
+** fills in flag to indicate if 'fp' could be a tty (nothing
+** to do with "betty" :-) ).
+**
+** Parameters:
+** fp -- file pointer to be buffered
+** bufsize -- new buffer size (a return)
+** couldbetty -- could be a tty (returns)
+**
+** Returns:
+** Success:
+** on error:
+** SMNPT -- not seek opimized
+** SMOPT -- seek opimized
+*/
+
+int
+sm_whatbuf(fp, bufsize, couldbetty)
+ register SM_FILE_T *fp;
+ size_t *bufsize;
+ int *couldbetty;
+{
+ struct stat st;
+
+ if (fp->f_file < 0 || fstat(fp->f_file, &st) < 0)
+ {
+ *couldbetty = 0;
+ *bufsize = SM_IO_BUFSIZ;
+ return SMNPT;
+ }
+
+ /* could be a tty iff it is a character device */
+ *couldbetty = S_ISCHR(st.st_mode);
+ if (st.st_blksize == 0)
+ {
+ *bufsize = SM_IO_BUFSIZ;
+ return SMNPT;
+ }
+
+#if SM_IO_MAX_BUF_FILE > 0
+ if (S_ISREG(st.st_mode) && st.st_blksize > SM_IO_MAX_BUF_FILE)
+ st.st_blksize = SM_IO_MAX_BUF_FILE;
+#endif /* SM_IO_MAX_BUF_FILE > 0 */
+
+#if SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0
+ if (!S_ISREG(st.st_mode))
+ {
+# if SM_IO_MAX_BUF > 0
+ if (st.st_blksize > SM_IO_MAX_BUF)
+ st.st_blksize = SM_IO_MAX_BUF;
+# if SM_IO_MIN_BUF > 0
+ else
+# endif /* SM_IO_MIN_BUF > 0 */
+# endif /* SM_IO_MAX_BUF > 0 */
+# if SM_IO_MIN_BUF > 0
+ if (st.st_blksize < SM_IO_MIN_BUF)
+ st.st_blksize = SM_IO_MIN_BUF;
+# endif /* SM_IO_MIN_BUF > 0 */
+ }
+#endif /* SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 */
+
+ /*
+ ** Optimise fseek() only if it is a regular file. (The test for
+ ** sm_std_seek is mainly paranoia.) It is safe to set _blksize
+ ** unconditionally; it will only be used if SMOPT is also set.
+ */
+
+ if ((fp->f_flags & SMSTR) == 0)
+ {
+ *bufsize = st.st_blksize;
+ fp->f_blksize = st.st_blksize;
+ }
+ else
+ *bufsize = SM_IO_BUFSIZ;
+ if ((st.st_mode & S_IFMT) == S_IFREG &&
+ fp->f_seek == sm_stdseek)
+ return SMOPT;
+ else
+ return SMNPT;
+}
diff --git a/contrib/sendmail/libsm/match.c b/contrib/sendmail/libsm/match.c
new file mode 100644
index 0000000..e42b865a3
--- /dev/null
+++ b/contrib/sendmail/libsm/match.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: match.c,v 1.10 2001/09/11 04:04:48 gshapiro Exp $")
+
+#include <sm/string.h>
+
+/*
+** SM_MATCH -- Match a character string against a glob pattern.
+**
+** Parameters:
+** str -- string.
+** par -- pattern to find in str.
+**
+** Returns:
+** true on match, false on non-match.
+**
+** A pattern consists of normal characters, which match themselves,
+** and meta-sequences. A * matches any sequence of characters.
+** A ? matches any single character. A [ introduces a character class.
+** A ] marks the end of a character class; if the ] is missing then
+** the [ matches itself rather than introducing a character class.
+** A character class matches any of the characters between the brackets.
+** The range of characters from X to Y inclusive is written X-Y.
+** If the first character after the [ is ! then the character class is
+** complemented.
+**
+** To include a ] in a character class, make it the first character
+** listed (after the !, if any). To include a -, make it the first
+** character listed (after the !, if any) or the last character.
+** It is impossible for a ] to be the final character in a range.
+** For glob patterns that literally match "*", "?" or "[",
+** use [*], [?] or [[].
+*/
+
+bool
+sm_match(str, pat)
+ const char *str;
+ const char *pat;
+{
+ bool ccnot, ccmatch, ccfirst;
+ const char *ccstart;
+ char c, c2;
+
+ for (;;)
+ {
+ switch (*pat)
+ {
+ case '\0':
+ return *str == '\0';
+ case '?':
+ if (*str == '\0')
+ return false;
+ ++pat;
+ ++str;
+ continue;
+ case '*':
+ ++pat;
+ if (*pat == '\0')
+ {
+ /* optimize case of trailing '*' */
+ return true;
+ }
+ for (;;)
+ {
+ if (sm_match(pat, str))
+ return true;
+ if (*str == '\0')
+ return false;
+ ++str;
+ }
+ /* NOTREACHED */
+ case '[':
+ ccstart = pat++;
+ ccnot = false;
+ if (*pat == '!')
+ {
+ ccnot = true;
+ ++pat;
+ }
+ ccmatch = false;
+ ccfirst = true;
+ for (;;)
+ {
+ if (*pat == '\0')
+ {
+ pat = ccstart;
+ goto defl;
+ }
+ if (*pat == ']' && !ccfirst)
+ break;
+ c = *pat++;
+ ccfirst = false;
+ if (*pat == '-' && pat[1] != ']')
+ {
+ ++pat;
+ if (*pat == '\0')
+ {
+ pat = ccstart;
+ goto defl;
+ }
+ c2 = *pat++;
+ if (*str >= c && *str <= c2)
+ ccmatch = true;
+ }
+ else
+ {
+ if (*str == c)
+ ccmatch = true;
+ }
+ }
+ if (ccmatch ^ ccnot)
+ {
+ ++pat;
+ ++str;
+ }
+ else
+ return false;
+ continue;
+ default:
+ defl:
+ if (*pat != *str)
+ return false;
+ ++pat;
+ ++str;
+ continue;
+ }
+ }
+}
diff --git a/contrib/sendmail/libsm/mbdb.c b/contrib/sendmail/libsm/mbdb.c
new file mode 100644
index 0000000..fcb5117
--- /dev/null
+++ b/contrib/sendmail/libsm/mbdb.c
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: mbdb.c,v 1.28 2002/01/07 23:29:43 gshapiro Exp $")
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#include <sm/limits.h>
+#include <sm/conf.h>
+#include <sm/assert.h>
+#include <sm/bitops.h>
+#include <sm/errstring.h>
+#include <sm/heap.h>
+#include <sm/mbdb.h>
+#include <sm/string.h>
+#include <sm/sysexits.h>
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+# include <sm/ldap.h>
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+
+typedef struct
+{
+ char *mbdb_typename;
+ int (*mbdb_initialize) __P((char *));
+ int (*mbdb_lookup) __P((char *name, SM_MBDB_T *user));
+ void (*mbdb_terminate) __P((void));
+} SM_MBDB_TYPE_T;
+
+static int mbdb_pw_initialize __P((char *));
+static int mbdb_pw_lookup __P((char *name, SM_MBDB_T *user));
+static void mbdb_pw_terminate __P((void));
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+static struct sm_ldap_struct LDAPLMAP;
+static int mbdb_ldap_initialize __P((char *));
+static int mbdb_ldap_lookup __P((char *name, SM_MBDB_T *user));
+static void mbdb_ldap_terminate __P((void));
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+
+static SM_MBDB_TYPE_T SmMbdbTypes[] =
+{
+ { "pw", mbdb_pw_initialize, mbdb_pw_lookup, mbdb_pw_terminate },
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+ { "ldap", mbdb_ldap_initialize, mbdb_ldap_lookup, mbdb_ldap_terminate },
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+ { NULL, NULL, NULL, NULL }
+};
+
+static SM_MBDB_TYPE_T *SmMbdbType = &SmMbdbTypes[0];
+
+/*
+** SM_MBDB_INITIALIZE -- specify which mailbox database to use
+**
+** If this function is not called, then the "pw" implementation
+** is used by default; this implementation uses getpwnam().
+**
+** Parameters:
+** mbdb -- Which mailbox database to use.
+** The argument has the form "name" or "name.arg".
+** "pw" means use getpwnam().
+**
+** Results:
+** EX_OK on success, or an EX_* code on failure.
+*/
+
+int
+sm_mbdb_initialize(mbdb)
+ char *mbdb;
+{
+ size_t namelen;
+ int err;
+ char *name;
+ char *arg;
+ SM_MBDB_TYPE_T *t;
+
+ SM_REQUIRE(mbdb != NULL);
+
+ name = mbdb;
+ arg = strchr(mbdb, '.');
+ if (arg == NULL)
+ namelen = strlen(name);
+ else
+ {
+ namelen = arg - name;
+ ++arg;
+ }
+
+ for (t = SmMbdbTypes; t->mbdb_typename != NULL; ++t)
+ {
+ if (strlen(t->mbdb_typename) == namelen &&
+ strncmp(name, t->mbdb_typename, namelen) == 0)
+ {
+ err = t->mbdb_initialize(arg);
+ if (err == EX_OK)
+ SmMbdbType = t;
+ return err;
+ }
+ }
+ return EX_UNAVAILABLE;
+}
+
+/*
+** SM_MBDB_TERMINATE -- terminate connection to the mailbox database
+**
+** Because this function closes any cached file descriptors that
+** are being held open for the connection to the mailbox database,
+** it should be called for security reasons prior to dropping privileges
+** and execing another process.
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+void
+sm_mbdb_terminate()
+{
+ SmMbdbType->mbdb_terminate();
+}
+
+/*
+** SM_MBDB_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** If the user does not exist, return EX_NOUSER.
+** If a temporary failure (eg, a network failure) occurred,
+** return EX_TEMPFAIL. Otherwise return EX_OSERR.
+*/
+
+int
+sm_mbdb_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ return SmMbdbType->mbdb_lookup(name, user);
+}
+
+/*
+** SM_MBDB_FROMPW -- copy from struct pw to SM_MBDB_T
+**
+** Parameters:
+** user -- destination user information structure
+** pw -- source passwd structure
+**
+** Results:
+** none.
+*/
+
+void
+sm_mbdb_frompw(user, pw)
+ SM_MBDB_T *user;
+ struct passwd *pw;
+{
+ SM_REQUIRE(user != NULL);
+ (void) sm_strlcpy(user->mbdb_name, pw->pw_name,
+ sizeof(user->mbdb_name));
+ user->mbdb_uid = pw->pw_uid;
+ user->mbdb_gid = pw->pw_gid;
+ sm_pwfullname(pw->pw_gecos, pw->pw_name, user->mbdb_fullname,
+ sizeof(user->mbdb_fullname));
+ (void) sm_strlcpy(user->mbdb_homedir, pw->pw_dir,
+ sizeof(user->mbdb_homedir));
+ (void) sm_strlcpy(user->mbdb_shell, pw->pw_shell,
+ sizeof(user->mbdb_shell));
+}
+
+/*
+** SM_PWFULLNAME -- build full name of user from pw_gecos field.
+**
+** This routine interprets the strange entry that would appear
+** in the GECOS field of the password file.
+**
+** Parameters:
+** gecos -- name to build.
+** user -- the login name of this user (for &).
+** buf -- place to put the result.
+** buflen -- length of buf.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_pwfullname(gecos, user, buf, buflen)
+ register char *gecos;
+ char *user;
+ char *buf;
+ size_t buflen;
+{
+ register char *p;
+ register char *bp = buf;
+
+ if (*gecos == '*')
+ gecos++;
+
+ /* copy gecos, interpolating & to be full name */
+ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+ {
+ if (bp >= &buf[buflen - 1])
+ {
+ /* buffer overflow -- just use login name */
+ (void) sm_strlcpy(buf, user, buflen);
+ return;
+ }
+ if (*p == '&')
+ {
+ /* interpolate full name */
+ (void) sm_strlcpy(bp, user, buflen - (bp - buf));
+ *bp = toupper(*bp);
+ bp += strlen(bp);
+ }
+ else
+ *bp++ = *p;
+ }
+ *bp = '\0';
+}
+
+/*
+** /etc/passwd implementation.
+*/
+
+/*
+** MBDB_PW_INITIALIZE -- initialize getpwnam() version
+**
+** Parameters:
+** arg -- unused.
+**
+** Results:
+** EX_OK.
+*/
+
+/* ARGSUSED0 */
+static int
+mbdb_pw_initialize(arg)
+ char *arg;
+{
+ return EX_OK;
+}
+
+/*
+** MBDB_PW_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** Failure: EX_NOUSER.
+*/
+
+static int
+mbdb_pw_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ struct passwd *pw;
+
+#ifdef HESIOD
+ /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
+ {
+ char *p;
+
+ for (p = name; *p != '\0'; p++)
+ if (!isascii(*p) || !isdigit(*p))
+ break;
+ if (*p == '\0')
+ return EX_NOUSER;
+ }
+#endif /* HESIOD */
+
+ errno = 0;
+ pw = getpwnam(name);
+ if (pw == NULL)
+ {
+#if 0
+ /*
+ ** getpwnam() isn't advertised as setting errno.
+ ** In fact, under FreeBSD, non-root getpwnam() on
+ ** non-existant users returns NULL with errno = EPERM.
+ ** This test won't work.
+ */
+ switch (errno)
+ {
+ case 0:
+ return EX_NOUSER;
+ case EIO:
+ return EX_OSERR;
+ default:
+ return EX_TEMPFAIL;
+ }
+#endif /* 0 */
+ return EX_NOUSER;
+ }
+
+ sm_mbdb_frompw(user, pw);
+ return EX_OK;
+}
+
+/*
+** MBDB_PW_TERMINATE -- terminate connection to the mailbox database
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+static void
+mbdb_pw_terminate()
+{
+ endpwent();
+}
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+/*
+** LDAP example implementation based on RFC 2307, "An Approach for Using
+** LDAP as a Network Information Service":
+**
+** ( nisSchema.1.0 NAME 'uidNumber'
+** DESC 'An integer uniquely identifying a user in an
+** administrative domain'
+** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
+**
+** ( nisSchema.1.1 NAME 'gidNumber'
+** DESC 'An integer uniquely identifying a group in an
+** administrative domain'
+** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
+**
+** ( nisSchema.1.2 NAME 'gecos'
+** DESC 'The GECOS field; the common name'
+** EQUALITY caseIgnoreIA5Match
+** SUBSTRINGS caseIgnoreIA5SubstringsMatch
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.1.3 NAME 'homeDirectory'
+** DESC 'The absolute path to the home directory'
+** EQUALITY caseExactIA5Match
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.1.4 NAME 'loginShell'
+** DESC 'The path to the login shell'
+** EQUALITY caseExactIA5Match
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
+** DESC 'Abstraction of an account with POSIX attributes'
+** MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+** MAY ( userPassword $ loginShell $ gecos $ description ) )
+**
+*/
+
+# define MBDB_LDAP_LABEL "MailboxDatabase"
+
+# ifndef MBDB_LDAP_FILTER
+# define MBDB_LDAP_FILTER "(&(objectClass=posixAccount)(uid=%0))"
+# endif /* MBDB_LDAP_FILTER */
+
+# ifndef MBDB_DEFAULT_LDAP_BASEDN
+# define MBDB_DEFAULT_LDAP_BASEDN NULL
+# endif /* MBDB_DEFAULT_LDAP_BASEDN */
+
+# ifndef MBDB_DEFAULT_LDAP_SERVER
+# define MBDB_DEFAULT_LDAP_SERVER NULL
+# endif /* MBDB_DEFAULT_LDAP_SERVER */
+
+/*
+** MBDB_LDAP_INITIALIZE -- initialize LDAP version
+**
+** Parameters:
+** arg -- LDAP specification
+**
+** Results:
+** EX_OK on success, or an EX_* code on failure.
+*/
+
+static int
+mbdb_ldap_initialize(arg)
+ char *arg;
+{
+ sm_ldap_clear(&LDAPLMAP);
+ LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN;
+ LDAPLMAP.ldap_host = MBDB_DEFAULT_LDAP_SERVER;
+ LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER;
+
+ /* Only want one match */
+ LDAPLMAP.ldap_sizelimit = 1;
+
+ /* interpolate new ldap_base and ldap_host from arg if given */
+ if (arg != NULL && *arg != '\0')
+ {
+ char *new;
+ char *sep;
+ size_t len;
+
+ len = strlen(arg) + 1;
+ new = sm_malloc(len);
+ if (new == NULL)
+ return EX_TEMPFAIL;
+ (void) sm_strlcpy(new, arg, len);
+ sep = strrchr(new, '@');
+ if (sep != NULL)
+ {
+ *sep++ = '\0';
+ LDAPLMAP.ldap_host = sep;
+ }
+ LDAPLMAP.ldap_base = new;
+ }
+
+ /* No connection yet, connect */
+ if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP))
+ return EX_UNAVAILABLE;
+ return EX_OK;
+}
+
+
+/*
+** MBDB_LDAP_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** Failure: EX_NOUSER.
+*/
+
+#define NEED_FULLNAME 0x01
+#define NEED_HOMEDIR 0x02
+#define NEED_SHELL 0x04
+#define NEED_UID 0x08
+#define NEED_GID 0x10
+
+static int
+mbdb_ldap_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ int msgid;
+ int need;
+ int ret;
+ int save_errno;
+ LDAPMessage *entry;
+ BerElement *ber;
+ char *attr = NULL;
+
+ if (strlen(name) >= sizeof(user->mbdb_name))
+ {
+ errno = EINVAL;
+ return EX_NOUSER;
+ }
+
+ if (LDAPLMAP.ldap_filter == NULL)
+ {
+ /* map not initialized, but don't have arg here */
+ errno = EFAULT;
+ return EX_TEMPFAIL;
+ }
+
+ if (LDAPLMAP.ldap_ld == NULL)
+ {
+ /* map not open, try to open now */
+ if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP))
+ return EX_TEMPFAIL;
+ }
+
+ sm_ldap_setopts(LDAPLMAP.ldap_ld, &LDAPLMAP);
+ msgid = sm_ldap_search(&LDAPLMAP, name);
+ if (msgid == -1)
+ {
+ save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld) + E_LDAPBASE;
+# ifdef LDAP_SERVER_DOWN
+ if (errno == LDAP_SERVER_DOWN)
+ {
+ /* server disappeared, try reopen on next search */
+ sm_ldap_close(&LDAPLMAP);
+ }
+# endif /* LDAP_SERVER_DOWN */
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+
+ /* Get results */
+ ret = ldap_result(LDAPLMAP.ldap_ld, msgid, 1,
+ (LDAPLMAP.ldap_timeout.tv_sec == 0 ? NULL :
+ &(LDAPLMAP.ldap_timeout)),
+ &(LDAPLMAP.ldap_res));
+
+ if (ret != LDAP_RES_SEARCH_RESULT &&
+ ret != LDAP_RES_SEARCH_ENTRY)
+ {
+ if (ret == 0)
+ errno = ETIMEDOUT;
+ else
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+ entry = ldap_first_entry(LDAPLMAP.ldap_ld, LDAPLMAP.ldap_res);
+ if (entry == NULL)
+ {
+ save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ if (save_errno == LDAP_SUCCESS)
+ {
+ errno = ENOENT;
+ ret = EX_NOUSER;
+ }
+ else
+ {
+ errno = save_errno;
+ ret = EX_TEMPFAIL;
+ }
+ goto abort;
+ }
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ ret = EX_OK;
+ need = NEED_FULLNAME|NEED_HOMEDIR|NEED_SHELL|NEED_UID|NEED_GID;
+ for (attr = ldap_first_attribute(LDAPLMAP.ldap_ld, entry, &ber);
+ attr != NULL;
+ attr = ldap_next_attribute(LDAPLMAP.ldap_ld, entry, ber))
+ {
+ char **vals;
+
+ vals = ldap_get_values(LDAPLMAP.ldap_ld, entry, attr);
+ if (vals == NULL)
+ {
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ if (errno == LDAP_SUCCESS)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ continue;
+ }
+
+ /* Must be an error */
+ errno += E_LDAPBASE;
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ if (vals[0] == NULL || vals[0][0] == '\0')
+ goto skip;
+
+ if (strcasecmp(attr, "gecos") == 0)
+ {
+ if (!bitset(NEED_FULLNAME, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_fullname))
+ goto skip;
+
+ sm_pwfullname(vals[0], name, user->mbdb_fullname,
+ sizeof(user->mbdb_fullname));
+ need &= ~NEED_FULLNAME;
+ }
+ else if (strcasecmp(attr, "homeDirectory") == 0)
+ {
+ if (!bitset(NEED_HOMEDIR, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_homedir))
+ goto skip;
+
+ (void) sm_strlcpy(user->mbdb_homedir, vals[0],
+ sizeof(user->mbdb_homedir));
+ need &= ~NEED_HOMEDIR;
+ }
+ else if (strcasecmp(attr, "loginShell") == 0)
+ {
+ if (!bitset(NEED_SHELL, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_shell))
+ goto skip;
+
+ (void) sm_strlcpy(user->mbdb_shell, vals[0],
+ sizeof(user->mbdb_shell));
+ need &= ~NEED_SHELL;
+ }
+ else if (strcasecmp(attr, "uidNumber") == 0)
+ {
+ char *p;
+
+ if (!bitset(NEED_UID, need))
+ goto skip;
+
+ for (p = vals[0]; *p != '\0'; p++)
+ {
+ /* allow negative numbers */
+ if (p == vals[0] && *p == '-')
+ {
+ /* but not simply '-' */
+ if (*(p + 1) == '\0')
+ goto skip;
+ }
+ else if (!isascii(*p) || !isdigit(*p))
+ goto skip;
+ }
+ user->mbdb_uid = atoi(vals[0]);
+ need &= ~NEED_UID;
+ }
+ else if (strcasecmp(attr, "gidNumber") == 0)
+ {
+ char *p;
+
+ if (!bitset(NEED_GID, need))
+ goto skip;
+
+ for (p = vals[0]; *p != '\0'; p++)
+ {
+ /* allow negative numbers */
+ if (p == vals[0] && *p == '-')
+ {
+ /* but not simply '-' */
+ if (*(p + 1) == '\0')
+ goto skip;
+ }
+ else if (!isascii(*p) || !isdigit(*p))
+ goto skip;
+ }
+ user->mbdb_gid = atoi(vals[0]);
+ need &= ~NEED_GID;
+ }
+
+skip:
+ ldap_value_free(vals);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ }
+
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+
+ /*
+ ** We check errno != LDAP_DECODING_ERROR since
+ ** OpenLDAP 1.X has a very ugly *undocumented*
+ ** hack of returning this error code from
+ ** ldap_next_attribute() if the library freed the
+ ** ber attribute. See:
+ ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
+ */
+
+ if (errno != LDAP_SUCCESS &&
+ errno != LDAP_DECODING_ERROR)
+ {
+ /* Must be an error */
+ errno += E_LDAPBASE;
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+ abort:
+ save_errno = errno;
+ if (attr != NULL)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ attr = NULL;
+ }
+ if (LDAPLMAP.ldap_res != NULL)
+ {
+ ldap_msgfree(LDAPLMAP.ldap_res);
+ LDAPLMAP.ldap_res = NULL;
+ }
+ if (ret == EX_OK)
+ {
+ if (need == 0)
+ {
+ (void) sm_strlcpy(user->mbdb_name, name,
+ sizeof(user->mbdb_name));
+ save_errno = 0;
+ }
+ else
+ {
+ ret = EX_NOUSER;
+ save_errno = EINVAL;
+ }
+ }
+ errno = save_errno;
+ return ret;
+}
+
+/*
+** MBDB_LDAP_TERMINATE -- terminate connection to the mailbox database
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+static void
+mbdb_ldap_terminate()
+{
+ sm_ldap_close(&LDAPLMAP);
+}
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
diff --git a/contrib/sendmail/libsm/mpeix.c b/contrib/sendmail/libsm/mpeix.c
new file mode 100644
index 0000000..d0767b5
--- /dev/null
+++ b/contrib/sendmail/libsm/mpeix.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: mpeix.c,v 1.4 2001/12/14 23:54:18 gshapiro Exp $")
+
+#ifdef MPE
+/*
+** MPE lacks many common functions required across all sendmail programs
+** so we define implementations for these functions here.
+*/
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+# include <mpe.h>
+# include <netinet/in.h>
+# include <pwd.h>
+# include <sys/socket.h>
+# include <sys/stat.h>
+# include <unistd.h>
+# include <sm/conf.h>
+
+/*
+** CHROOT -- dummy chroot() function
+**
+** The MPE documentation for sendmail says that chroot-based
+** functionality is not implemented because MPE lacks chroot. But
+** rather than mucking around with all the sendmail calls to chroot,
+** we define this dummy function to return an ENOSYS failure just in
+** case a sendmail user attempts to enable chroot-based functionality.
+**
+** Parameters:
+** path -- pathname of new root (ignored).
+**
+** Returns:
+** -1 and errno == ENOSYS (function not implemented)
+*/
+
+int
+chroot(path)
+ char *path;
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+/*
+** ENDPWENT -- dummy endpwent() function
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+*/
+
+void
+endpwent()
+{
+ return;
+}
+
+/*
+** In addition to missing functions, certain existing MPE functions have
+** slightly different semantics (or bugs) compared to normal Unix OSes.
+**
+** Here we define wrappers for these functions to make them behave in the
+** manner expected by sendmail.
+*/
+
+/*
+** SENDMAIL_MPE_BIND -- shadow function for the standard socket bind()
+**
+** MPE requires GETPRIVMODE() for AF_INET sockets less than port 1024.
+**
+** Parameters:
+** sd -- socket descriptor.
+** addr -- socket address.
+** addrlen -- length of socket address.
+**
+** Results:
+** 0 -- success
+** != 0 -- failure
+*/
+
+#undef bind
+int
+sendmail_mpe_bind(sd, addr, addrlen)
+ int sd;
+ void *addr;
+ int addrlen;
+{
+ bool priv = false;
+ int result;
+ extern void GETPRIVMODE __P((void));
+ extern void GETUSERMODE __P((void));
+
+ if (addrlen == sizeof(struct sockaddr_in) &&
+ ((struct sockaddr_in *)addr)->sin_family == AF_INET)
+ {
+ /* AF_INET */
+ if (((struct sockaddr_in *)addr)->sin_port > 0 &&
+ ((struct sockaddr_in *)addr)->sin_port < 1024)
+ {
+ priv = true;
+ GETPRIVMODE();
+ }
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr = 0;
+ result = bind(sd, addr, addrlen);
+ if (priv)
+ GETUSERMODE();
+ return result;
+ }
+
+ /* AF_UNIX */
+ return bind(sd, addr, addrlen);
+}
+
+/*
+** SENDMAIL_MPE__EXIT -- wait for children to terminate, then _exit()
+**
+** Child processes cannot survive the death of their parent on MPE, so
+** we must call wait() before _exit() in order to prevent this
+** infanticide.
+**
+** Parameters:
+** status -- _exit status value.
+**
+** Returns:
+** none.
+*/
+
+#undef _exit
+void
+sendmail_mpe__exit(status)
+ int status;
+{
+ int result;
+
+ /* Wait for all children to terminate. */
+ do
+ {
+ result = wait(NULL);
+ } while (result > 0 || errno == EINTR);
+ _exit(status);
+}
+
+/*
+** SENDMAIL_MPE_EXIT -- wait for children to terminate, then exit()
+**
+** Child processes cannot survive the death of their parent on MPE, so
+** we must call wait() before exit() in order to prevent this
+** infanticide.
+**
+** Parameters:
+** status -- exit status value.
+**
+** Returns:
+** none.
+*/
+
+#undef exit
+void
+sendmail_mpe_exit(status)
+ int status;
+{
+ int result;
+
+ /* Wait for all children to terminate. */
+ do
+ {
+ result = wait(NULL);
+ } while (result > 0 || errno == EINTR);
+ exit(status);
+}
+
+/*
+** SENDMAIL_MPE_FCNTL -- shadow function for fcntl()
+**
+** MPE requires sfcntl() for sockets, and fcntl() for everything
+** else. This shadow routine determines the descriptor type and
+** makes the appropriate call.
+**
+** Parameters:
+** same as fcntl().
+**
+** Returns:
+** same as fcntl().
+*/
+
+#undef fcntl
+int
+sendmail_mpe_fcntl(int fildes, int cmd, ...)
+{
+ int len, result;
+ struct sockaddr sa;
+
+ void *arg;
+ va_list ap;
+
+ va_start(ap, cmd);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+
+ len = sizeof sa;
+ if (getsockname(fildes, &sa, &len) == -1)
+ {
+ if (errno == EAFNOSUPPORT)
+ {
+ /* AF_UNIX socket */
+ return sfcntl(fildes, cmd, arg);
+ }
+ else if (errno == ENOTSOCK)
+ {
+ /* file or pipe */
+ return fcntl(fildes, cmd, arg);
+ }
+
+ /* unknown getsockname() failure */
+ return (-1);
+ }
+ else
+ {
+ /* AF_INET socket */
+ if ((result = sfcntl(fildes, cmd, arg)) != -1 &&
+ cmd == F_GETFL)
+ result |= O_RDWR; /* fill in some missing flags */
+ return result;
+ }
+}
+
+/*
+** SENDMAIL_MPE_GETPWNAM - shadow function for getpwnam()
+**
+** Several issues apply here:
+**
+** - MPE user names MUST have one '.' separator character
+** - MPE user names MUST be in upper case
+** - MPE does not initialize all fields in the passwd struct
+**
+** Parameters:
+** name -- username string.
+**
+** Returns:
+** pointer to struct passwd if found else NULL
+*/
+
+static char *sendmail_mpe_nullstr = "";
+
+#undef getpwnam
+extern struct passwd *getpwnam(const char *);
+
+struct passwd *
+sendmail_mpe_getpwnam(name)
+ const char *name;
+{
+ int dots = 0;
+ int err;
+ int i = strlen(name);
+ char *upper;
+ struct passwd *result = NULL;
+
+ if (i <= 0)
+ {
+ errno = EINVAL;
+ return result;
+ }
+
+ if ((upper = (char *)malloc(i + 1)) != NULL)
+ {
+ /* upshift the username parameter and count the dots */
+ while (i >= 0)
+ {
+ if (name[i] == '.')
+ {
+ dots++;
+ upper[i] = '.';
+ }
+ else
+ upper[i] = toupper(name[i]);
+ i--;
+ }
+
+ if (dots != 1)
+ {
+ /* prevent bug when dots == 0 */
+ err = EINVAL;
+ }
+ else if ((result = getpwnam(upper)) != NULL)
+ {
+ /* init the uninitialized fields */
+ result->pw_gecos = sendmail_mpe_nullstr;
+ result->pw_passwd = sendmail_mpe_nullstr;
+ result->pw_age = sendmail_mpe_nullstr;
+ result->pw_comment = sendmail_mpe_nullstr;
+ result->pw_audid = 0;
+ result->pw_audflg = 0;
+ }
+ err = errno;
+ free(upper);
+ }
+ errno = err;
+ return result;
+}
+
+/*
+** SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid()
+**
+** Initializes the uninitalized fields in the passwd struct.
+**
+** Parameters:
+** uid -- uid to obtain passwd data for
+**
+** Returns:
+** pointer to struct passwd or NULL if not found
+*/
+
+#undef getpwuid
+extern struct passwd *getpwuid __P((uid_t));
+
+struct passwd *
+sendmail_mpe_getpwuid(uid)
+ uid_t uid;
+{
+ struct passwd *result;
+
+ if ((result = getpwuid(uid)) != NULL)
+ {
+ /* initialize the uninitialized fields */
+ result->pw_gecos = sendmail_mpe_nullstr;
+ result->pw_passwd = sendmail_mpe_nullstr;
+ result->pw_age = sendmail_mpe_nullstr;
+ result->pw_comment = sendmail_mpe_nullstr;
+ result->pw_audid = 0;
+ result->pw_audflg = 0;
+ }
+ return result;
+}
+
+/*
+** OK boys and girls, time for some serious voodoo!
+**
+** MPE does not have a complete implementation of POSIX users and groups:
+**
+** - there is no uid 0 superuser
+** - setuid/setgid file permission bits exist but have no-op functionality
+** - setgid() exists, but only supports new gid == current gid (boring!)
+** - setuid() forces a gid change to the new uid's primary (and only) gid
+**
+** ...all of which thoroughly annoys sendmail.
+**
+** So what to do? We can't go on an #ifdef MPE rampage throughout
+** sendmail, because there are only about a zillion references to uid 0
+** and so success (and security) would probably be rather dubious by the
+** time we finished.
+**
+** Instead we take the approach of defining wrapper functions for the
+** gid/uid management functions getegid(), geteuid(), setgid(), and
+** setuid() in order to implement the following model:
+**
+** - the sendmail program thinks it is a setuid-root (uid 0) program
+** - uid 0 is recognized as being valid, but does not grant extra powers
+** - MPE priv mode allows sendmail to call setuid(), not uid 0
+** - file access is still controlled by the real non-zero uid
+** - the other programs (vacation, etc) have standard MPE POSIX behavior
+**
+** This emulation model is activated by use of the program file setgid and
+** setuid mode bits which exist but are unused by MPE. If the setgid mode
+** bit is on, then gid emulation will be enabled. If the setuid mode bit is
+** on, then uid emulation will be enabled. So for the mail daemon, we need
+** to do chmod u+s,g+s /SENDMAIL/CURRENT/SENDMAIL.
+**
+** The following flags determine the current emulation state:
+**
+** true == emulation enabled
+** false == emulation disabled, use unmodified MPE semantics
+*/
+
+static bool sendmail_mpe_flaginit = false;
+static bool sendmail_mpe_gidflag = false;
+static bool sendmail_mpe_uidflag = false;
+
+/*
+** SENDMAIL_MPE_GETMODE -- return the mode bits for the current process
+**
+** Parameters:
+** none.
+**
+** Returns:
+** file mode bits for the current process program file.
+*/
+
+mode_t
+sendmail_mpe_getmode()
+{
+ int status = 666;
+ int myprogram_length;
+ int myprogram_syntax = 2;
+ char formaldesig[28];
+ char myprogram[PATH_MAX + 2];
+ char path[PATH_MAX + 1];
+ struct stat st;
+ extern HPMYPROGRAM __P((int parms, char *formaldesig, int *status,
+ int *length, char *myprogram,
+ int *myprogram_length, int *myprogram_syntax));
+
+ myprogram_length = sizeof(myprogram);
+ HPMYPROGRAM(6, formaldesig, &status, NULL, myprogram,
+ &myprogram_length, &myprogram_syntax);
+
+ /* should not occur, do not attempt emulation */
+ if (status != 0)
+ return 0;
+
+ memcpy(&path, &myprogram[1], myprogram_length - 2);
+ path[myprogram_length - 2] = '\0';
+
+ /* should not occur, do not attempt emulation */
+ if (stat(path, &st) < 0)
+ return 0;
+
+ return st.st_mode;
+}
+
+/*
+** SENDMAIL_MPE_EMULGID -- should we perform gid emulation?
+**
+** If !sendmail_mpe_flaginit then obtain the mode bits to determine
+** if the setgid bit is on, we want gid emulation and so set
+** sendmail_mpe_gidflag to true. Otherwise we do not want gid emulation
+** and so set sendmail_mpe_gidflag to false.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** true -- perform gid emulation
+** false -- do not perform gid emulation
+*/
+
+bool
+sendmail_mpe_emulgid()
+{
+ if (!sendmail_mpe_flaginit)
+ {
+ mode_t mode;
+
+ mode = sendmail_mpe_getmode();
+ sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
+ sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
+ sendmail_mpe_flaginit = true;
+ }
+ return sendmail_mpe_gidflag;
+}
+
+/*
+** SENDMAIL_MPE_EMULUID -- should we perform uid emulation?
+**
+** If sendmail_mpe_uidflag == -1 then obtain the mode bits to determine
+** if the setuid bit is on, we want uid emulation and so set
+** sendmail_mpe_uidflag to true. Otherwise we do not want uid emulation
+** and so set sendmail_mpe_uidflag to false.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** true -- perform uid emulation
+** false -- do not perform uid emulation
+*/
+
+bool
+sendmail_mpe_emuluid()
+{
+ if (!sendmail_mpe_flaginit)
+ {
+ mode_t mode;
+
+ mode = sendmail_mpe_getmode();
+ sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
+ sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
+ sendmail_mpe_flaginit = true;
+ }
+ return sendmail_mpe_uidflag;
+}
+
+/*
+** SENDMAIL_MPE_GETEGID -- shadow function for getegid()
+**
+** If emulation mode is in effect and the saved egid has been
+** initialized, return the saved egid; otherwise return the value of the
+** real getegid() function.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** emulated egid if present, else true egid.
+*/
+
+static uid_t sendmail_mpe_egid = -1;
+
+#undef getegid
+gid_t
+sendmail_mpe_getegid()
+{
+ if (sendmail_mpe_emulgid() && sendmail_mpe_egid != -1)
+ return sendmail_mpe_egid;
+ return getegid();
+}
+
+/*
+** SENDMAIL_MPE_GETEUID -- shadow function for geteuid()
+**
+** If emulation mode is in effect, return the saved euid; otherwise
+** return the value of the real geteuid() function.
+**
+** Note that the initial value of the saved euid is zero, to simulate
+** a setuid-root program.
+**
+** Parameters:
+** none
+**
+** Returns:
+** emulated euid if in emulation mode, else true euid.
+*/
+
+static uid_t sendmail_mpe_euid = 0;
+
+#undef geteuid
+uid_t
+sendmail_mpe_geteuid()
+{
+ if (sendmail_mpe_emuluid())
+ return sendmail_mpe_euid;
+ return geteuid();
+}
+
+/*
+** SENDMAIL_MPE_SETGID -- shadow function for setgid()
+**
+** Simulate a call to setgid() without actually calling the real
+** function. Implement the expected uid 0 semantics.
+**
+** Note that sendmail will also be calling setuid() which will force an
+** implicit real setgid() to the proper primary gid. So it doesn't matter
+** that we don't actually alter the real gid in this shadow function.
+**
+** Parameters:
+** gid -- desired gid.
+**
+** Returns:
+** 0 -- emulated success
+** -1 -- emulated failure
+*/
+
+#undef setgid
+int
+sendmail_mpe_setgid(gid)
+ gid_t gid;
+{
+ if (sendmail_mpe_emulgid())
+ {
+ if (gid == getgid() || sendmail_mpe_euid == 0)
+ {
+ sendmail_mpe_egid = gid;
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+ }
+ return setgid(gid);
+}
+
+/*
+** SENDMAIL_MPE_SETUID -- shadow function for setuid()
+**
+** setuid() is broken as of MPE 7.0 in that it changes the current
+** working directory to be the home directory of the new uid. Thus
+** we must obtain the cwd and restore it after the setuid().
+**
+** Note that expected uid 0 semantics have been added, as well as
+** remembering the new uid for later use by the other shadow functions.
+**
+** Parameters:
+** uid -- desired uid.
+**
+** Returns:
+** 0 -- success
+** -1 -- failure
+**
+** Globals:
+** sendmail_mpe_euid
+*/
+
+#undef setuid
+int
+sendmail_mpe_setuid(uid)
+ uid_t uid;
+{
+ char *cwd;
+ char cwd_buf[PATH_MAX+1];
+ int result;
+ extern void GETPRIVMODE __P((void));
+ extern void GETUSERMODE __P((void));
+
+ if (sendmail_mpe_emuluid())
+ {
+ if (uid == 0)
+ {
+ if (sendmail_mpe_euid != 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ sendmail_mpe_euid = 0;
+ return 0;
+ }
+
+ /* Preserve the current working directory */
+ if ((cwd = getcwd(cwd_buf, PATH_MAX + 1)) == NULL)
+ return -1;
+
+ GETPRIVMODE();
+ result = setuid(uid);
+ GETUSERMODE();
+
+ /* Restore the current working directory */
+ chdir(cwd_buf);
+
+ if (result == 0)
+ sendmail_mpe_euid = uid;
+
+ return result;
+ }
+ return setuid(uid);
+}
+#endif /* MPE */
diff --git a/contrib/sendmail/libsm/niprop.c b/contrib/sendmail/libsm/niprop.c
new file mode 100644
index 0000000..ad58867
--- /dev/null
+++ b/contrib/sendmail/libsm/niprop.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: niprop.c,v 1.8 2001/09/11 04:04:48 gshapiro Exp $")
+
+#if NETINFO
+#include <ctype.h>
+#include <stdlib.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/debug.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+#include <sm/heap.h>
+
+/*
+** NI_PROPVAL -- NetInfo property value lookup routine
+**
+** Parameters:
+** keydir -- the NetInfo directory name in which to search
+** for the key.
+** keyprop -- the name of the property in which to find the
+** property we are interested. Defaults to "name".
+** keyval -- the value for which we are really searching.
+** valprop -- the property name for the value in which we
+** are interested.
+** sepchar -- if non-nil, this can be multiple-valued, and
+** we should return a string separated by this
+** character.
+**
+** Returns:
+** NULL -- if:
+** 1. the directory is not found
+** 2. the property name is not found
+** 3. the property contains multiple values
+** 4. some error occurred
+** else -- the value of the lookup.
+**
+** Example:
+** To search for an alias value, use:
+** ni_propval("/aliases", "name", aliasname, "members", ',')
+**
+** Notes:
+** Caller should free the return value of ni_proval
+*/
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN "."
+# define PARENT_NETINFO_DOMAIN ".."
+# define MAX_NI_LEVELS 256
+
+char *
+ni_propval(keydir, keyprop, keyval, valprop, sepchar)
+ char *keydir;
+ char *keyprop;
+ char *keyval;
+ char *valprop;
+ int sepchar;
+{
+ char *propval = NULL;
+ int i;
+ int j, alen, l;
+ void *ni = NULL;
+ void *lastni = NULL;
+ ni_status nis;
+ ni_id nid;
+ ni_namelist ninl;
+ register char *p;
+ char keybuf[1024];
+
+ /*
+ ** Create the full key from the two parts.
+ **
+ ** Note that directory can end with, e.g., "name=" to specify
+ ** an alternate search property.
+ */
+
+ i = strlen(keydir) + strlen(keyval) + 2;
+ if (keyprop != NULL)
+ i += strlen(keyprop) + 1;
+ if (i >= sizeof keybuf)
+ return NULL;
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, keydir, "/");
+ if (keyprop != NULL)
+ {
+ (void) sm_strlcat2(keybuf, keyprop, "=", sizeof keybuf);
+ }
+ (void) sm_strlcat(keybuf, keyval, sizeof keybuf);
+
+#if 0
+ if (tTd(38, 21))
+ sm_dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
+ keydir, keyprop, keyval, valprop, sepchar, keybuf);
+#endif /* 0 */
+
+ /*
+ ** If the passed directory and property name are found
+ ** in one of netinfo domains we need to search (starting
+ ** from the local domain moving all the way back to the
+ ** root domain) set propval to the property's value
+ ** and return it.
+ */
+
+ for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
+ {
+ if (i == 0)
+ {
+ nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_open(LOCAL) = %d\n", nis);
+#endif /* 0 */
+ }
+ else
+ {
+ if (lastni != NULL)
+ ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_open(PARENT) = %d\n", nis);
+#endif /* 0 */
+ }
+
+ /*
+ ** Don't bother if we didn't get a handle on a
+ ** proper domain. This is not necessarily an error.
+ ** We would get a positive ni_status if, for instance
+ ** we never found the directory or property and tried
+ ** to open the parent of the root domain!
+ */
+
+ if (nis != 0)
+ break;
+
+ /*
+ ** Find the path to the server information.
+ */
+
+ if (ni_pathsearch(ni, &nid, keybuf) != 0)
+ continue;
+
+ /*
+ ** Find associated value information.
+ */
+
+ if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
+ continue;
+
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_lookupprop: len=%d\n",
+ ninl.ni_namelist_len);
+#endif /* 0 */
+
+ /*
+ ** See if we have an acceptable number of values.
+ */
+
+ if (ninl.ni_namelist_len <= 0)
+ continue;
+
+ if (sepchar == '\0' && ninl.ni_namelist_len > 1)
+ {
+ ni_namelist_free(&ninl);
+ continue;
+ }
+
+ /*
+ ** Calculate number of bytes needed and build result
+ */
+
+ alen = 1;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ alen += strlen(ninl.ni_namelist_val[j]) + 1;
+ propval = p = sm_malloc(alen);
+ if (propval == NULL)
+ goto cleanup;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ {
+ (void) sm_strlcpy(p, ninl.ni_namelist_val[j], alen);
+ l = strlen(p);
+ p += l;
+ *p++ = sepchar;
+ alen -= l + 1;
+ }
+ *--p = '\0';
+
+ ni_namelist_free(&ninl);
+ }
+
+ cleanup:
+ if (ni != NULL)
+ ni_free(ni);
+ if (lastni != NULL && ni != lastni)
+ ni_free(lastni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_propval returns: '%s'\n", propval);
+#endif /* 0 */
+
+ return propval;
+}
+#endif /* NETINFO */
diff --git a/contrib/sendmail/libsm/path.c b/contrib/sendmail/libsm/path.c
new file mode 100644
index 0000000..6932e1f
--- /dev/null
+++ b/contrib/sendmail/libsm/path.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: path.c,v 1.9 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/path.h>
+#include <sm/string.h>
+
diff --git a/contrib/sendmail/libsm/put.c b/contrib/sendmail/libsm/put.c
new file mode 100644
index 0000000..d513b98
--- /dev/null
+++ b/contrib/sendmail/libsm/put.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: put.c,v 1.27 2001/12/19 05:19:35 ca Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/errstring.h>
+#include <sm/string.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_PUTC -- output a character to the file
+**
+** Function version of the macro sm_io_putc (in <sm/io.h>).
+**
+** Parameters:
+** fp -- file to output to
+** timeout -- time to complete putc
+** c -- int value of character to output
+**
+** Returns:
+** Failure: returns SM_IO_EOF _and_ sets errno
+** Success: returns sm_putc() value.
+**
+*/
+
+#undef sm_io_putc
+
+int
+sm_io_putc(fp, timeout, c)
+ SM_FILE_T *fp;
+ int timeout;
+ int c;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ return sm_putc(fp, timeout, c);
+}
+
+
+/*
+** SM_PERROR -- print system error messages to smioerr
+**
+** Parameters:
+** s -- message to print
+**
+** Returns:
+** none
+*/
+
+void
+sm_perror(s)
+ const char *s;
+{
+ int save_errno = errno;
+
+ if (s != NULL && *s != '\0')
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s: ", s);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
+ sm_errstring(save_errno));
+}
diff --git a/contrib/sendmail/libsm/refill.c b/contrib/sendmail/libsm/refill.c
new file mode 100644
index 0000000..10c7cde
--- /dev/null
+++ b/contrib/sendmail/libsm/refill.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: refill.c,v 1.49 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/conf.h>
+#include <sm/assert.h>
+#include "local.h"
+
+static int sm_lflush __P((SM_FILE_T *, int *));
+
+/*
+** SM_IO_RD_TIMEOUT -- measured timeout for reads
+**
+** This #define uses a select() to wait for the 'fd' to become readable.
+** The select() can be active for up to 'To' time. The select() may not
+** use all of the the 'To' time. Hence, the amount of "wall-clock" time is
+** measured to decide how much to subtract from 'To' to update it. On some
+** BSD-based/like systems the timeout for a select() is updated for the
+** amount of time used. On many/most systems this does not happen. Therefore
+** the updating of 'To' must be done ourselves; a copy of 'To' is passed
+** since a BSD-like system will have updated it and we don't want to
+** double the time used!
+** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
+** sendmail buffered file type in sendmail/bf.c; see use below).
+**
+** Parameters
+** fp -- the file pointer for the active file
+** fd -- raw file descriptor (from 'fp') to use for select()
+** to -- struct timeval of the timeout
+** timeout -- the original timeout value
+** sel_ret -- the return value from the select()
+**
+** Returns:
+** nothing, flow through code
+*/
+
+#define SM_IO_RD_TIMEOUT(fp, fd, to, timeout, sel_ret) \
+{ \
+ struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
+ fd_set sm_io_to_mask, sm_io_x_mask; \
+ errno = 0; \
+ if (timeout == SM_TIME_IMMEDIATE) \
+ { \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ FD_ZERO(&sm_io_to_mask); \
+ FD_SET((fd), &sm_io_to_mask); \
+ FD_ZERO(&sm_io_x_mask); \
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+ (sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL, \
+ &sm_io_x_mask, (to)); \
+ if ((sel_ret) < 0) \
+ { \
+ /* something went wrong, errno set */ \
+ fp->f_r = 0; \
+ fp->f_flags |= SMERR; \
+ return SM_IO_EOF; \
+ } \
+ else if ((sel_ret) == 0) \
+ { \
+ /* timeout */ \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ /* calulate wall-clock time used */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+ timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
+ timersub((to), &sm_io_to_diff, (to)); \
+}
+
+/*
+** SM_LFLUSH -- flush a file if it is line buffered and writable
+**
+** Parameters:
+** fp -- file pointer to flush
+** timeout -- original timeout value (in milliseconds)
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0
+*/
+
+static int
+sm_lflush(fp, timeout)
+ SM_FILE_T *fp;
+ int *timeout;
+{
+
+ if ((fp->f_flags & (SMLBF|SMWR)) == (SMLBF|SMWR))
+ return sm_flush(fp, timeout);
+ return 0;
+}
+
+/*
+** SM_REFILL -- refill a buffer
+**
+** Parameters:
+** fp -- file pointer for buffer refill
+** timeout -- time to complete filling the buffer in milliseconds
+**
+** Returns:
+** Success: returns 0
+** Failure: returns SM_IO_EOF
+*/
+
+int
+sm_refill(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ int ret, r;
+ struct timeval to;
+ int fd;
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. And we're not EOF or ERR really.
+ ** So... the failure is we couldn't do it in time.
+ */
+
+ errno = EAGAIN;
+ fp->f_r = 0; /* just to be sure */
+ return 0;
+ }
+
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ fp->f_r = 0; /* largely a convenience for callers */
+
+ if (fp->f_flags & SMFEOF)
+ return SM_IO_EOF;
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ /* if not already reading, have to be reading and writing */
+ if ((fp->f_flags & SMRD) == 0)
+ {
+ if ((fp->f_flags & SMRW) == 0)
+ {
+ errno = EBADF;
+ fp->f_flags |= SMERR;
+ return SM_IO_EOF;
+ }
+
+ /* switch to reading */
+ if (fp->f_flags & SMWR)
+ {
+ if (sm_flush(fp, &timeout))
+ return SM_IO_EOF;
+ fp->f_flags &= ~SMWR;
+ fp->f_w = 0;
+ fp->f_lbfsize = 0;
+ }
+ fp->f_flags |= SMRD;
+ }
+ else
+ {
+ /*
+ ** We were reading. If there is an ungetc buffer,
+ ** we must have been reading from that. Drop it,
+ ** restoring the previous buffer (if any). If there
+ ** is anything in that buffer, return.
+ */
+
+ if (HASUB(fp))
+ {
+ FREEUB(fp);
+ if ((fp->f_r = fp->f_ur) != 0)
+ {
+ fp->f_p = fp->f_up;
+
+ /* revert blocking state */
+ return 0;
+ }
+ }
+ }
+
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+
+ /*
+ ** Before reading from a line buffered or unbuffered file,
+ ** flush all line buffered output files, per the ANSI C standard.
+ */
+
+ if (fp->f_flags & (SMLBF|SMNBF))
+ (void) sm_fwalk(sm_lflush, &timeout);
+
+ /*
+ ** If this file is linked to another, and we are going to hang
+ ** on the read, flush the linked file before continuing.
+ */
+
+ if (fp->f_flushfp != NULL &&
+ (*fp->f_getinfo)(fp, SM_IO_IS_READABLE, NULL) <= 0)
+ sm_flush(fp->f_flushfp, &timeout);
+
+ fp->f_p = fp->f_bf.smb_base;
+
+ /*
+ ** The do-while loop stops trying to read when something is read
+ ** or it appears that the timeout has expired before finding
+ ** something available to be read (via select()).
+ */
+
+ ret = 0;
+ do
+ {
+ errno = 0; /* needed to ensure EOF correctly found */
+ r = (*fp->f_read)(fp, (char *)fp->f_p, fp->f_bf.smb_size);
+ if (r <= 0)
+ {
+ if (r == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, r, timeout))
+ goto err; /* errno set */
+
+ /* read would block */
+ SM_IO_RD_TIMEOUT(fp, fd, &to, timeout, ret);
+ }
+ } while (r <= 0 && ret > 0);
+
+err:
+ if (r <= 0)
+ {
+ if (r == 0)
+ fp->f_flags |= SMFEOF;
+ else
+ fp->f_flags |= SMERR;
+ fp->f_r = 0;
+ return SM_IO_EOF;
+ }
+ fp->f_r = r;
+ return 0;
+}
+
+/*
+** SM_RGET -- refills buffer and returns first character
+**
+** Handle sm_getc() when the buffer ran out:
+** Refill, then return the first character in the newly-filled buffer.
+**
+** Parameters:
+** fp -- file pointer to work on
+** timeout -- time to complete refill
+**
+** Returns:
+** Success: first character in refilled buffer as an int
+** Failure: SM_IO_EOF
+*/
+
+int
+sm_rget(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ if (sm_refill(fp, timeout) == 0)
+ {
+ fp->f_r--;
+ return *fp->f_p++;
+ }
+ return SM_IO_EOF;
+}
diff --git a/contrib/sendmail/libsm/rewind.c b/contrib/sendmail/libsm/rewind.c
new file mode 100644
index 0000000..597c6db
--- /dev/null
+++ b/contrib/sendmail/libsm/rewind.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: rewind.c,v 1.18 2001/09/11 04:04:49 gshapiro Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_REWIND -- rewind the file
+**
+** Seeks the file to the begining and clears any outstanding errors.
+**
+** Parameters:
+** fp -- the flie pointer for rewind
+** timeout -- time to complete the rewind
+**
+** Returns:
+** none.
+*/
+
+void
+sm_io_rewind(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ (void) sm_io_seek(fp, timeout, 0L, SM_IO_SEEK_SET);
+ (void) sm_io_clearerr(fp);
+ errno = 0; /* not required, but seems reasonable */
+}
diff --git a/contrib/sendmail/libsm/rpool.c b/contrib/sendmail/libsm/rpool.c
new file mode 100644
index 0000000..8632166
--- /dev/null
+++ b/contrib/sendmail/libsm/rpool.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: rpool.c,v 1.24 2002/01/11 21:54:43 ca Exp $")
+
+/*
+** resource pools
+** For documentation, see rpool.html
+*/
+
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/rpool.h>
+#include <sm/varargs.h>
+#include <sm/conf.h>
+#if _FFR_PERF_RPOOL
+# include <syslog.h>
+#endif /* _FFR_PERF_RPOOL */
+
+const char SmRpoolMagic[] = "sm_rpool";
+
+typedef union
+{
+ SM_POOLLINK_T link;
+ char align[SM_ALIGN_SIZE];
+} SM_POOLHDR_T;
+
+/*
+** Tune this later
+*/
+
+#define POOLSIZE 4096
+#define BIG_OBJECT_RATIO 10
+
+/*
+** SM_RPOOL_ALLOCBLOCK_X -- allocate a new block for an rpool.
+**
+** Parameters:
+** rpool -- rpool to which the block should be added.
+** size -- size of block.
+**
+** Returns:
+** Pointer to block.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+static char *
+sm_rpool_allocblock_x(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+{
+ SM_POOLLINK_T *p;
+
+ p = sm_malloc_x(sizeof(SM_POOLHDR_T) + size);
+ p->sm_pnext = rpool->sm_pools;
+ rpool->sm_pools = p;
+ return (char*) p + sizeof(SM_POOLHDR_T);
+}
+
+/*
+** SM_RPOOL_ALLOCBLOCK -- allocate a new block for an rpool.
+**
+** Parameters:
+** rpool -- rpool to which the block should be added.
+** size -- size of block.
+**
+** Returns:
+** Pointer to block, NULL on failure.
+*/
+
+static char *
+sm_rpool_allocblock(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+{
+ SM_POOLLINK_T *p;
+
+ p = sm_malloc(sizeof(SM_POOLHDR_T) + size);
+ if (p == NULL)
+ return NULL;
+ p->sm_pnext = rpool->sm_pools;
+ rpool->sm_pools = p;
+ return (char*) p + sizeof(SM_POOLHDR_T);
+}
+
+/*
+** SM_RPOOL_MALLOC_TAGGED_X -- allocate memory from rpool
+**
+** Parameters:
+** rpool -- rpool from which memory should be allocated;
+** can be NULL, use sm_malloc() then.
+** size -- size of block.
+** file -- filename.
+** line -- line number in file.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to block.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+**
+** Notice: XXX
+** if size == 0 and the rpool is new (no memory
+** allocated yet) NULL is returned!
+** We could solve this by
+** - wasting 1 byte (size < avail)
+** - checking for rpool->sm_poolptr != NULL
+** - not asking for 0 sized buffer
+*/
+
+void *
+#if SM_HEAP_CHECK
+sm_rpool_malloc_tagged_x(rpool, size, file, line, group)
+ SM_RPOOL_T *rpool;
+ size_t size;
+ char *file;
+ int line;
+ int group;
+#else /* SM_HEAP_CHECK */
+sm_rpool_malloc_x(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+#endif /* SM_HEAP_CHECK */
+{
+ char *ptr;
+
+ if (rpool == NULL)
+ return sm_malloc_tagged_x(size, file, line, group);
+
+ /* Ensure that size is properly aligned. */
+ if (size & SM_ALIGN_BITS)
+ size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
+
+ /* The common case. This is optimized for speed. */
+ if (size <= rpool->sm_poolavail)
+ {
+ ptr = rpool->sm_poolptr;
+ rpool->sm_poolptr += size;
+ rpool->sm_poolavail -= size;
+ return ptr;
+ }
+
+ /*
+ ** The slow case: we need to call malloc.
+ ** The SM_REQUIRE assertion is deferred until now, for speed.
+ ** That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
+ ** so the common case code won't be triggered on a dangling pointer.
+ */
+
+ SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
+
+ /*
+ ** If size > sm_poolsize, then malloc a new block especially for
+ ** this request. Future requests will be allocated from the
+ ** current pool.
+ **
+ ** What if the current pool is mostly unallocated, and the current
+ ** request is larger than the available space, but < sm_poolsize?
+ ** If we discard the current pool, and start allocating from a new
+ ** pool, then we will be wasting a lot of space. For this reason,
+ ** we malloc a block just for the current request if size >
+ ** sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
+ ** Thus, the most space that we will waste at the end of a pool
+ ** is sm_bigobjectsize - 1.
+ */
+
+ if (size > rpool->sm_bigobjectsize)
+ {
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_nbigblocks;
+#endif /* _FFR_PERF_RPOOL */
+ return sm_rpool_allocblock_x(rpool, size);
+ }
+ SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
+ ptr = sm_rpool_allocblock_x(rpool, rpool->sm_poolsize);
+ rpool->sm_poolptr = ptr + size;
+ rpool->sm_poolavail = rpool->sm_poolsize - size;
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_npools;
+#endif /* _FFR_PERF_RPOOL */
+ return ptr;
+}
+
+/*
+** SM_RPOOL_MALLOC_TAGGED -- allocate memory from rpool
+**
+** Parameters:
+** rpool -- rpool from which memory should be allocated;
+** can be NULL, use sm_malloc() then.
+** size -- size of block.
+** file -- filename.
+** line -- line number in file.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to block, NULL on failure.
+**
+** Notice: XXX
+** if size == 0 and the rpool is new (no memory
+** allocated yet) NULL is returned!
+** We could solve this by
+** - wasting 1 byte (size < avail)
+** - checking for rpool->sm_poolptr != NULL
+** - not asking for 0 sized buffer
+*/
+
+void *
+#if SM_HEAP_CHECK
+sm_rpool_malloc_tagged(rpool, size, file, line, group)
+ SM_RPOOL_T *rpool;
+ size_t size;
+ char *file;
+ int line;
+ int group;
+#else /* SM_HEAP_CHECK */
+sm_rpool_malloc(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+#endif /* SM_HEAP_CHECK */
+{
+ char *ptr;
+
+ if (rpool == NULL)
+ return sm_malloc_tagged(size, file, line, group);
+
+ /* Ensure that size is properly aligned. */
+ if (size & SM_ALIGN_BITS)
+ size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
+
+ /* The common case. This is optimized for speed. */
+ if (size <= rpool->sm_poolavail)
+ {
+ ptr = rpool->sm_poolptr;
+ rpool->sm_poolptr += size;
+ rpool->sm_poolavail -= size;
+ return ptr;
+ }
+
+ /*
+ ** The slow case: we need to call malloc.
+ ** The SM_REQUIRE assertion is deferred until now, for speed.
+ ** That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
+ ** so the common case code won't be triggered on a dangling pointer.
+ */
+
+ SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
+
+ /*
+ ** If size > sm_poolsize, then malloc a new block especially for
+ ** this request. Future requests will be allocated from the
+ ** current pool.
+ **
+ ** What if the current pool is mostly unallocated, and the current
+ ** request is larger than the available space, but < sm_poolsize?
+ ** If we discard the current pool, and start allocating from a new
+ ** pool, then we will be wasting a lot of space. For this reason,
+ ** we malloc a block just for the current request if size >
+ ** sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
+ ** Thus, the most space that we will waste at the end of a pool
+ ** is sm_bigobjectsize - 1.
+ */
+
+ if (size > rpool->sm_bigobjectsize)
+ {
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_nbigblocks;
+#endif /* _FFR_PERF_RPOOL */
+ return sm_rpool_allocblock(rpool, size);
+ }
+ SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
+ ptr = sm_rpool_allocblock(rpool, rpool->sm_poolsize);
+ if (ptr == NULL)
+ return NULL;
+ rpool->sm_poolptr = ptr + size;
+ rpool->sm_poolavail = rpool->sm_poolsize - size;
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_npools;
+#endif /* _FFR_PERF_RPOOL */
+ return ptr;
+}
+
+/*
+** SM_RPOOL_NEW_X -- create a new rpool.
+**
+** Parameters:
+** parent -- pointer to parent rpool, can be NULL.
+**
+** Returns:
+** Pointer to new rpool.
+*/
+
+SM_RPOOL_T *
+sm_rpool_new_x(parent)
+ SM_RPOOL_T *parent;
+{
+ SM_RPOOL_T *rpool;
+
+ rpool = sm_malloc_x(sizeof(SM_RPOOL_T));
+ if (parent == NULL)
+ rpool->sm_parentlink = NULL;
+ else
+ {
+ SM_TRY
+ rpool->sm_parentlink = sm_rpool_attach_x(parent,
+ (SM_RPOOL_RFREE_T) sm_rpool_free,
+ (void *) rpool);
+ SM_EXCEPT(exc, "*")
+ sm_free(rpool);
+ sm_exc_raise_x(exc);
+ SM_END_TRY
+ }
+ rpool->sm_magic = SmRpoolMagic;
+
+ rpool->sm_poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
+ rpool->sm_bigobjectsize = rpool->sm_poolsize / BIG_OBJECT_RATIO;
+ rpool->sm_poolptr = NULL;
+ rpool->sm_poolavail = 0;
+ rpool->sm_pools = NULL;
+
+ rpool->sm_rptr = NULL;
+ rpool->sm_ravail = 0;
+ rpool->sm_rlists = NULL;
+#if _FFR_PERF_RPOOL
+ rpool->sm_nbigblocks = 0;
+ rpool->sm_npools = 0;
+#endif /* _FFR_PERF_RPOOL */
+
+ return rpool;
+}
+
+/*
+** SM_RPOOL_SETSIZES -- set sizes for rpool.
+**
+** Parameters:
+** poolsize -- size of a single rpool block.
+** bigobjectsize -- if this size is exceeded, an individual
+** block is allocated (must be less or equal poolsize).
+**
+** Returns:
+** none.
+*/
+
+void
+sm_rpool_setsizes(rpool, poolsize, bigobjectsize)
+ SM_RPOOL_T *rpool;
+ size_t poolsize;
+ size_t bigobjectsize;
+{
+ SM_REQUIRE(poolsize >= bigobjectsize);
+ if (poolsize == 0)
+ poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
+ if (bigobjectsize == 0)
+ bigobjectsize = poolsize / BIG_OBJECT_RATIO;
+ rpool->sm_poolsize = poolsize;
+ rpool->sm_bigobjectsize = bigobjectsize;
+}
+
+/*
+** SM_RPOOL_FREE -- free an rpool and release all of its resources.
+**
+** Parameters:
+** rpool -- rpool to free.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_rpool_free(rpool)
+ SM_RPOOL_T *rpool;
+{
+ SM_RLIST_T *rl, *rnext;
+ SM_RESOURCE_T *r, *rmax;
+ SM_POOLLINK_T *pp, *pnext;
+
+ if (rpool == NULL)
+ return;
+
+ /*
+ ** It's important to free the resources before the memory pools,
+ ** because the resource free functions might modify the contents
+ ** of the memory pools.
+ */
+
+ rl = rpool->sm_rlists;
+ if (rl != NULL)
+ {
+ rmax = rpool->sm_rptr;
+ for (;;)
+ {
+ for (r = rl->sm_rvec; r < rmax; ++r)
+ {
+ if (r->sm_rfree != NULL)
+ r->sm_rfree(r->sm_rcontext);
+ }
+ rnext = rl->sm_rnext;
+ sm_free(rl);
+ if (rnext == NULL)
+ break;
+ rl = rnext;
+ rmax = &rl->sm_rvec[SM_RLIST_MAX];
+ }
+ }
+
+ /*
+ ** Now free the memory pools.
+ */
+
+ for (pp = rpool->sm_pools; pp != NULL; pp = pnext)
+ {
+ pnext = pp->sm_pnext;
+ sm_free(pp);
+ }
+
+ /*
+ ** Disconnect rpool from its parent.
+ */
+
+ if (rpool->sm_parentlink != NULL)
+ *rpool->sm_parentlink = NULL;
+
+ /*
+ ** Setting these fields to zero means that any future to attempt
+ ** to use the rpool after it is freed will cause an assertion failure.
+ */
+
+ rpool->sm_magic = NULL;
+ rpool->sm_poolavail = 0;
+ rpool->sm_ravail = 0;
+
+#if _FFR_PERF_RPOOL
+ if (rpool->sm_nbigblocks > 0 || rpool->sm_npools > 1)
+ syslog(LOG_NOTICE,
+ "perf: rpool=%lx, sm_nbigblocks=%d, sm_npools=%d",
+ (long) rpool, rpool->sm_nbigblocks, rpool->sm_npools);
+ rpool->sm_nbigblocks = 0;
+ rpool->sm_npools = 0;
+#endif /* _FFR_PERF_RPOOL */
+ sm_free(rpool);
+}
+
+/*
+** SM_RPOOL_ATTACH_X -- attach a resource to an rpool.
+**
+** Parameters:
+** rpool -- rpool to which resource should be attached.
+** rfree -- function to call when rpool is freed.
+** rcontext -- argument for function to call when rpool is freed.
+**
+** Returns:
+** Pointer to allocated function.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+SM_RPOOL_ATTACH_T
+sm_rpool_attach_x(rpool, rfree, rcontext)
+ SM_RPOOL_T *rpool;
+ SM_RPOOL_RFREE_T rfree;
+ void *rcontext;
+{
+ SM_RLIST_T *rl;
+ SM_RPOOL_ATTACH_T a;
+
+ SM_REQUIRE_ISA(rpool, SmRpoolMagic);
+
+ if (rpool->sm_ravail == 0)
+ {
+ rl = sm_malloc_x(sizeof(SM_RLIST_T));
+ rl->sm_rnext = rpool->sm_rlists;
+ rpool->sm_rlists = rl;
+ rpool->sm_rptr = rl->sm_rvec;
+ rpool->sm_ravail = SM_RLIST_MAX;
+ }
+
+ a = &rpool->sm_rptr->sm_rfree;
+ rpool->sm_rptr->sm_rfree = rfree;
+ rpool->sm_rptr->sm_rcontext = rcontext;
+ ++rpool->sm_rptr;
+ --rpool->sm_ravail;
+ return a;
+}
diff --git a/contrib/sendmail/libsm/rpool.html b/contrib/sendmail/libsm/rpool.html
new file mode 100644
index 0000000..f796bc0
--- /dev/null
+++ b/contrib/sendmail/libsm/rpool.html
@@ -0,0 +1,187 @@
+<html>
+<head>
+ <title>libsm : Resource Pools</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Resource Pools </h1>
+ <br> $Id: rpool.html,v 1.4 2000/12/07 17:33:09 dmoen Exp $
+</center>
+
+<h2> Introduction </h2>
+
+A resource pool is an object that owns a collection of objects
+that can be freed all at once.
+
+<p>
+Resource pools simplify storage management.
+
+<p>
+Resource pools also speed up memory management.
+For example, here are some memory allocation statistics from a
+run of <tt>`sendmail -q`</tt> that delivered 3 messages:
+<blockquote><pre>
+ 18 1 82 12 87 24 7 42 2 84
+ 3046 2 18 13 6 25 89 44 2 88
+ 728 3 15 14 2 26 14 48 1 91
+ 31 4 9 15 3 27 104 52 3 92
+ 103 5 394 16 80 28 8 56 2 96
+ 125 6 16 17 1 31 2 60 1 100
+ 45 7 14 18 59 32 10 64 9 108
+ 130 8 6 19 1 33 6 68 3 135
+ 40 9 111 20 7 34 1 72 10 140
+ 37 10 7 21 54 36 10 76
+ 34 11 4 22 38 40 5 80
+</pre></blockquote>
+The second number in each pair is the size of a memory block; the first
+number is the number of blocks of that size. We can see that sendmail
+allocates large numbers of 2 byte blocks. These memory blocks can be
+allocated and freed more quickly using resource pools, because:
+<ul>
+<li>
+ When you allocate a small block from a resource pool, the rpool
+ implementation carves off a chunk of a large preallocated block,
+ and hands you a pointer to it.
+<li>
+ When you free a resource pool, only a small number of large
+ blocks need to be freed.
+</ul>
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/rpool.h&gt;
+
+typedef void (*SM_RPOOL_RFREE_T)(void *rcontext);
+typedef struct sm_rpool SM_RPOOL_T;
+typedef ... SM_RPOOL_ATTACH_T;
+
+SM_RPOOL_T *
+sm_rpool_new_x(
+ SM_RPOOL_T *parent);
+
+void
+sm_rpool_free(
+ SM_RPOOL_T *rpool);
+
+void *
+sm_rpool_malloc_x(
+ SM_RPOOL_T *rpool,
+ size_t size);
+
+SM_RPOOL_ATTACH_T
+sm_rpool_attach_x(
+ SM_RPOOL_T *rpool,
+ SM_RPOOL_RFREE_T rfree,
+ void *rcontext);
+
+void
+sm_rpool_detach(
+ SM_RPOOL_ATTACH_T);
+
+void
+sm_rpool_setsizes(
+ SM_RPOOL_T *rpool,
+ size_t poolsize,
+ size_t bigobjectsize);
+</pre>
+
+<h2> Description </h2>
+
+<dl>
+<dt>
+<tt> SM_RPOOL_T *sm_rpool_new_x(SM_RPOOL_T *parent) </tt>
+<dd>
+ Create a new resource pool object.
+ Raise an exception if there is insufficient heap space.
+ Initially, no memory is allocated for memory pools or resource lists.
+ <p>
+ If parent != NULL then the new rpool will be added as a resource
+ to the specified parent rpool, so that when the parent is freed,
+ the child is also freed. However, even if a parent is specified,
+ you can free the rpool at any time, and it will be automatically
+ disconnected from the parent.
+ <p>
+<dt>
+<tt> void *sm_rpool_malloc_x(SM_RPOOL_T *rpool, size_t size) </tt>
+<dd>
+ Allocate a block of memory from a memory pool owned by the rpool.
+ Raise an exception if there is insufficient heap space.
+ A series of small allocation requests can be satisfied allocating
+ them from the same memory pool, which reduces the number of calls
+ to malloc.
+ All of the memory allocated by sm_rpool_malloc_x is freed when
+ the rpool is freed, and not before then.
+ <p>
+<dt>
+<tt> void sm_rpool_setsizes(SM_RPOOL_T *rpool, size_t poolsize, size_t bigobjectsize) </tt>
+<dd>
+ Set memory pool parameters.
+ You can safely call this function at any time, but an especially
+ good time to call it is immediately after creating the rpool,
+ before any pooled objects have been allocated using sm_rpool_malloc_x.
+ <p>
+ <tt>poolsize</tt> is the number of bytes of pool memory
+ that will be available in the next pool object to be allocated.
+ If you happen to know the total number of bytes of memory that
+ you will allocate from an rpool using sm_rpool_malloc_x
+ (including alignment padding), then you can pass that value
+ as the poolsize, and only a single pool will be allocated
+ during the lifetime of the rpool.
+ <tt>poolsize</tt> is an optimization, not a hard limit:
+ if you allocate more than this number of bytes from the rpool,
+ then more than one memory pool may be allocated by the rpool
+ to satisfy your requests.
+ <p>
+ <tt>bigobjectsize</tt> is a value &lt;= <tt>poolsize</tt>.
+ It is used when an <tt>sm_rpool_malloc_x</tt> request exceeds
+ the number of bytes available in the current pool.
+ If the request is &gt; <tt>bigobjectsize</tt> then the request
+ will be satisfied by allocating a new block just for this specific
+ request, and the current pool is not affected.
+ If the request is &lt;= <tt>bigobjectsize</tt> then the current
+ pool is closed and a new memory pool is allocated, from which the
+ request is satisfied.
+ Consequently, no more than <tt>bigobjectsize-1</tt> bytes will
+ ever be wasted at the end of a given pool.
+ <p>
+ If poolsize or bigobjectsize are 0, then suitable default values
+ are chosen.
+ <p>
+<dt>
+<tt> SM_RPOOL_ATTACH_T sm_rpool_attach_x(SM_RPOOL_T *rpool, SM_RPOOL_RFREE_T rfree, void *rcontext) </tt>
+<dd>
+ Attach an object to a resource pool, along with its free function.
+ When the rpool is freed, the specified object will also be freed.
+ Raise an exception if there is insufficient heap space.
+ <p>
+ The return value is a magic cookie which, if passed to
+ sm_rpool_detach, disconnects the object from the resource pool,
+ which prevents the object's free function from being called when
+ the rpool is freed.
+ <p>
+<dt>
+<tt> void sm_rpool_detach(SM_RPOOL_ATTACH_T a) </tt>
+<dd>
+ The argument is a magic cookie returned by <tt>sm_rpool_attach_t</tt>,
+ and refers to the object that was attached to an rpool by a specific
+ call to <tt>sm_rpool_attach_t</tt>.
+ Disconnect the object from the resource pool,
+ which prevents the object's free function from being called when
+ the rpool is freed.
+ <p>
+<dt>
+<tt> void sm_rpool_free(SM_RPOOL_T *rpool) </tt>
+<dd>
+ Free an rpool object.
+ All memory allocated using sm_rpool_malloc_x
+ and all objects attached using sm_rpool_attach_x
+ are freed at this time.
+ If the rpool has a parent rpool, it is detached from its parent.
+</dl>
+
+</body>
+</html>
diff --git a/contrib/sendmail/libsm/setvbuf.c b/contrib/sendmail/libsm/setvbuf.c
new file mode 100644
index 0000000..172a767
--- /dev/null
+++ b/contrib/sendmail/libsm/setvbuf.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: setvbuf.c,v 1.32 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_IO_SETVBUF -- set the buffering type for a file
+**
+** Set one of the different kinds of buffering, optionally including
+** a buffer.
+** If 'size' is == 0 then an "optimal" size will be selected.
+** If 'buf' is == NULL then space will be allocated at 'size'.
+**
+** Parameters:
+** fp -- the file that buffering is to be changed for
+** timeout -- time allowed for completing the function
+** buf -- buffer to use
+** mode -- buffering method to use
+** size -- size of 'buf'
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: 0 (zero)
+*/
+
+int
+sm_io_setvbuf(fp, timeout, buf, mode, size)
+ SM_FILE_T *fp;
+ int timeout;
+ char *buf;
+ int mode;
+ size_t size;
+{
+ int ret, flags;
+ size_t iosize;
+ int ttyflag;
+ int fd;
+ struct timeval to;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ /*
+ ** Verify arguments. The `int' limit on `size' is due to this
+ ** particular implementation. Note, buf and size are ignored
+ ** when setting SM_IO_NBF.
+ */
+
+ if (mode != SM_IO_NBF)
+ if ((mode != SM_IO_FBF && mode != SM_IO_LBF &&
+ mode != SM_IO_NOW) || (int) size < 0)
+ return SM_IO_EOF;
+
+ /*
+ ** Write current buffer, if any. Discard unread input (including
+ ** ungetc data), cancel line buffering, and free old buffer if
+ ** malloc()ed. We also clear any eof condition, as if this were
+ ** a seek.
+ */
+
+ ret = 0;
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+ (void) sm_flush(fp, &timeout);
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_r = fp->f_lbfsize = 0;
+ flags = fp->f_flags;
+ if (flags & SMMBF)
+ {
+ sm_free((void *) fp->f_bf.smb_base);
+ fp->f_bf.smb_base = NULL;
+ }
+ flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW |
+ SMFBF);
+
+ /* If setting unbuffered mode, skip all the hard work. */
+ if (mode == SM_IO_NBF)
+ goto nbf;
+
+ /*
+ ** Find optimal I/O size for seek optimization. This also returns
+ ** a `tty flag' to suggest that we check isatty(fd), but we do not
+ ** care since our caller told us how to buffer.
+ */
+
+ flags |= sm_whatbuf(fp, &iosize, &ttyflag);
+ if (size == 0)
+ {
+ buf = NULL; /* force local allocation */
+ size = iosize;
+ }
+
+ /* Allocate buffer if needed. */
+ if (buf == NULL)
+ {
+ if ((buf = sm_malloc(size)) == NULL)
+ {
+ /*
+ ** Unable to honor user's request. We will return
+ ** failure, but try again with file system size.
+ */
+
+ ret = SM_IO_EOF;
+ if (size != iosize)
+ {
+ size = iosize;
+ buf = sm_malloc(size);
+ }
+ }
+ if (buf == NULL)
+ {
+ /* No luck; switch to unbuffered I/O. */
+nbf:
+ fp->f_flags = flags | SMNBF;
+ fp->f_w = 0;
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return ret;
+ }
+ flags |= SMMBF;
+ }
+
+ /*
+ ** Kill any seek optimization if the buffer is not the
+ ** right size.
+ **
+ ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
+ */
+
+ if (size != iosize)
+ flags |= SMNPT;
+
+ /*
+ ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on
+ ** exit (since we are buffered in some way).
+ */
+
+ if (mode == SM_IO_LBF)
+ flags |= SMLBF;
+ else if (mode == SM_IO_NOW)
+ flags |= SMNOW;
+ else if (mode == SM_IO_FBF)
+ flags |= SMFBF;
+ fp->f_flags = flags;
+ fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf;
+ fp->f_bf.smb_size = size;
+ /* fp->f_lbfsize is still 0 */
+ if (flags & SMWR)
+ {
+ /*
+ ** Begin or continue writing: see sm_wsetup(). Note
+ ** that SMNBF is impossible (it was handled earlier).
+ */
+
+ if (flags & SMLBF)
+ {
+ fp->f_w = 0;
+ fp->f_lbfsize = -fp->f_bf.smb_size;
+ }
+ else
+ fp->f_w = size;
+ }
+ else
+ {
+ /* begin/continue reading, or stay in intermediate state */
+ fp->f_w = 0;
+ }
+
+ atexit(sm_cleanup);
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/shm.c b/contrib/sendmail/libsm/shm.c
new file mode 100644
index 0000000..35ae028
--- /dev/null
+++ b/contrib/sendmail/libsm/shm.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: shm.c,v 1.10 2001/12/14 00:22:58 ca Exp $")
+
+#if SM_CONF_SHM
+# include <stdlib.h>
+# include <unistd.h>
+# include <errno.h>
+# include <sm/shm.h>
+
+/*
+** SM_SHMSTART -- initialize shared memory segment.
+**
+** Parameters:
+** key -- key for shared memory.
+** size -- size of segment.
+** shmflag -- initial flags.
+** shmid -- pointer to return id.
+** owner -- create segment.
+**
+** Returns:
+** pointer to shared memory segment,
+** NULL on failure.
+**
+** Side Effects:
+** attaches shared memory segment.
+*/
+
+void *
+sm_shmstart(key, size, shmflg, shmid, owner)
+ key_t key;
+ int size;
+ int shmflg;
+ int *shmid;
+ bool owner;
+{
+ int save_errno;
+ void *shm = SM_SHM_NULL;
+
+ /* default: user/group accessible */
+ if (shmflg == 0)
+ shmflg = SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3);
+ if (owner)
+ shmflg |= IPC_CREAT|IPC_EXCL;
+ *shmid = shmget(key, size, shmflg);
+ if (*shmid < 0)
+ goto error;
+
+ shm = shmat(*shmid, (void *) 0, 0);
+ if (shm == SM_SHM_NULL)
+ goto error;
+
+ return shm;
+
+ error:
+ save_errno = errno;
+ if (shm != SM_SHM_NULL || *shmid >= 0)
+ sm_shmstop(shm, *shmid, owner);
+ *shmid = SM_SHM_NO_ID;
+ errno = save_errno;
+ return (void *) 0;
+}
+
+/*
+** SM_SHMSTOP -- stop using shared memory segment.
+**
+** Parameters:
+** shm -- pointer to shared memory.
+** shmid -- id.
+** owner -- delete segment.
+**
+** Returns:
+** 0 on success.
+** < 0 on failure.
+**
+** Side Effects:
+** detaches (and maybe removes) shared memory segment.
+*/
+
+int
+sm_shmstop(shm, shmid, owner)
+ void *shm;
+ int shmid;
+ bool owner;
+{
+ int r;
+
+ if (shm != SM_SHM_NULL && (r = shmdt(shm)) < 0)
+ return r;
+ if (owner && shmid >= 0 && (r = shmctl(shmid, IPC_RMID, NULL)) < 0)
+ return r;
+ return 0;
+}
+#endif /* SM_CONF_SHM */
diff --git a/contrib/sendmail/libsm/signal.c b/contrib/sendmail/libsm/signal.c
new file mode 100644
index 0000000..9061efc
--- /dev/null
+++ b/contrib/sendmail/libsm/signal.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: signal.c,v 1.16 2001/09/11 04:04:49 gshapiro Exp $")
+
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sm/clock.h>
+#include <sm/signal.h>
+#include <signal.h>
+#include <sm/string.h>
+
+unsigned int volatile InCriticalSection; /* >0 if inside critical section */
+int volatile PendingSignal; /* pending signal to resend */
+
+/*
+** SM_SIGNAL -- set a signal handler
+**
+** This is essentially old BSD "signal(3)".
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+sigfunc_t
+sm_signal(sig, handler)
+ int sig;
+ sigfunc_t handler;
+{
+# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
+ struct sigaction n, o;
+# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
+
+ /*
+ ** First, try for modern signal calls
+ ** and restartable syscalls
+ */
+
+# ifdef SA_RESTART
+ (void) memset(&n, '\0', sizeof n);
+# if USE_SA_SIGACTION
+ n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
+ n.sa_flags = SA_RESTART|SA_SIGINFO;
+# else /* USE_SA_SIGACTION */
+ n.sa_handler = handler;
+ n.sa_flags = SA_RESTART;
+# endif /* USE_SA_SIGACTION */
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+# else /* SA_RESTART */
+
+ /*
+ ** Else check for SYS5SIGNALS or
+ ** BSD4_3 signals
+ */
+
+# if defined(SYS5SIGNALS) || defined(BSD4_3)
+# ifdef BSD4_3
+ return signal(sig, handler);
+# else /* BSD4_3 */
+ return sigset(sig, handler);
+# endif /* BSD4_3 */
+# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
+
+ /*
+ ** Finally, if nothing else is available,
+ ** go for a default
+ */
+
+ (void) memset(&n, '\0', sizeof n);
+ n.sa_handler = handler;
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
+# endif /* SA_RESTART */
+}
+/*
+** SM_BLOCKSIGNAL -- hold a signal to prevent delivery
+**
+** Parameters:
+** sig -- the signal to block.
+**
+** Returns:
+** 1 signal was previously blocked
+** 0 signal was not previously blocked
+** -1 on failure.
+*/
+
+int
+sm_blocksignal(sig)
+ int sig;
+{
+# ifdef BSD4_3
+# ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+# endif /* ! sigmask */
+ return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ sigfunc_t handler;
+
+ handler = sigset(sig, SIG_HOLD);
+ if (handler == SIG_ERR)
+ return -1;
+ else
+ return handler == SIG_HOLD;
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset, oset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, sig);
+ if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
+ return -1;
+ else
+ return sigismember(&oset, sig);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+/*
+** SM_RELEASESIGNAL -- release a held signal
+**
+** Parameters:
+** sig -- the signal to release.
+**
+** Returns:
+** 1 signal was previously blocked
+** 0 signal was not previously blocked
+** -1 on failure.
+*/
+
+int
+sm_releasesignal(sig)
+ int sig;
+{
+# ifdef BSD4_3
+ return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ sigfunc_t handler;
+
+ handler = sigset(sig, SIG_HOLD);
+ if (sigrelse(sig) < 0)
+ return -1;
+ else
+ return handler == SIG_HOLD;
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset, oset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, sig);
+ if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
+ return -1;
+ else
+ return sigismember(&oset, sig);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+/*
+** PEND_SIGNAL -- Add a signal to the pending signal list
+**
+** Parameters:
+** sig -- signal to add
+**
+** Returns:
+** none.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+void
+pend_signal(sig)
+ int sig;
+{
+ int sigbit;
+ int save_errno = errno;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+#endif /* SM_CONF_SETITIMER */
+
+ /*
+ ** Don't want to interrupt something critical, hence delay
+ ** the alarm for one second. Hopefully, by then we
+ ** will be out of the critical section. If not, then
+ ** we will just delay again. The events to be run will
+ ** still all be run, maybe just a little bit late.
+ */
+
+ switch (sig)
+ {
+ case SIGHUP:
+ sigbit = PEND_SIGHUP;
+ break;
+
+ case SIGINT:
+ sigbit = PEND_SIGINT;
+ break;
+
+ case SIGTERM:
+ sigbit = PEND_SIGTERM;
+ break;
+
+ case SIGUSR1:
+ sigbit = PEND_SIGUSR1;
+ break;
+
+ case SIGALRM:
+ /* don't have to pend these */
+ sigbit = 0;
+ break;
+
+ default:
+ /* If we get here, we are in trouble */
+ abort();
+
+ /* NOTREACHED */
+ /* shut up stupid compiler warning on HP-UX 11 */
+ sigbit = 0;
+ break;
+ }
+
+ if (sigbit != 0)
+ PendingSignal |= sigbit;
+ (void) sm_signal(SIGALRM, sm_tick);
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 1;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(1);
+#endif /* SM_CONF_SETITIMER */
+ errno = save_errno;
+}
+/*
+** SM_ALLSIGNALS -- act on all signals
+**
+** Parameters:
+** block -- whether to block or release all signals.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_allsignals(block)
+ bool block;
+{
+# ifdef BSD4_3
+# ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+# endif /* ! sigmask */
+ if (block)
+ {
+ int mask = 0;
+
+ mask |= sigmask(SIGALRM);
+ mask |= sigmask(SIGCHLD);
+ mask |= sigmask(SIGHUP);
+ mask |= sigmask(SIGINT);
+ mask |= sigmask(SIGTERM);
+ mask |= sigmask(SIGUSR1);
+
+ (void) sigblock(mask);
+ }
+ else
+ sigsetmask(0);
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ if (block)
+ {
+ (void) sigset(SIGALRM, SIG_HOLD);
+ (void) sigset(SIGCHLD, SIG_HOLD);
+ (void) sigset(SIGHUP, SIG_HOLD);
+ (void) sigset(SIGINT, SIG_HOLD);
+ (void) sigset(SIGTERM, SIG_HOLD);
+ (void) sigset(SIGUSR1, SIG_HOLD);
+ }
+ else
+ {
+ (void) sigset(SIGALRM, SIG_DFL);
+ (void) sigset(SIGCHLD, SIG_DFL);
+ (void) sigset(SIGHUP, SIG_DFL);
+ (void) sigset(SIGINT, SIG_DFL);
+ (void) sigset(SIGTERM, SIG_DFL);
+ (void) sigset(SIGUSR1, SIG_DFL);
+ }
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, SIGALRM);
+ (void) sigaddset(&sset, SIGCHLD);
+ (void) sigaddset(&sset, SIGHUP);
+ (void) sigaddset(&sset, SIGINT);
+ (void) sigaddset(&sset, SIGTERM);
+ (void) sigaddset(&sset, SIGUSR1);
+ (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+/*
+** SM_SIGNAL_NOOP -- A signal no-op function
+**
+** Parameters:
+** sig -- signal received
+**
+** Returns:
+** SIGFUNC_RETURN
+*/
+
+/* ARGSUSED */
+SIGFUNC_DECL
+sm_signal_noop(sig)
+ int sig;
+{
+ int save_errno = errno;
+
+ FIX_SYSV_SIGNAL(sig, sm_signal_noop);
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+
diff --git a/contrib/sendmail/libsm/smstdio.c b/contrib/sendmail/libsm/smstdio.c
new file mode 100644
index 0000000..758c936
--- /dev/null
+++ b/contrib/sendmail/libsm/smstdio.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.29 2001/09/11 04:04:49 gshapiro Exp $")
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include "local.h"
+
+/*
+** Overall:
+** This is a file type which implements a layer on top of the system
+** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
+** "bound late" because of the manner which Linux implements stdio.
+** When binding late (when fp->f_cookie==NULL) then the value of
+** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
+** stderr.
+*/
+
+/*
+** SM_STDIOOPEN -- open a file to system stdio implementation
+**
+** Parameters:
+** fp -- file pointer assign for this open
+** info -- info about file to open
+** flags -- indicating method of opening
+** rpool -- ignored
+**
+** Returns:
+** Failure: -1
+** Success: 0 (zero)
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdioopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register FILE *s;
+ char *stdiomode;
+
+ switch (flags)
+ {
+ case SM_IO_RDONLY:
+ stdiomode = "r";
+ break;
+ case SM_IO_WRONLY:
+ stdiomode = "w";
+ break;
+ case SM_IO_APPEND:
+ stdiomode = "a";
+ break;
+ case SM_IO_APPENDRW:
+ stdiomode = "a+";
+ break;
+ case SM_IO_RDWR:
+ default:
+ stdiomode = "r+";
+ break;
+ }
+
+ if ((s = fopen((char *)info, stdiomode)) == NULL)
+ return -1;
+ fp->f_cookie = s;
+ return 0;
+}
+
+/*
+** SETUP -- assign file type cookie when not already assigned
+**
+** Parameters:
+** fp - the file pointer to get the cookie assigned
+**
+** Return:
+** none.
+*/
+
+static void
+setup(fp)
+ SM_FILE_T *fp;
+{
+ if (fp->f_cookie == NULL)
+ {
+ switch (fp->f_ival)
+ {
+ case 0:
+ fp->f_cookie = stdin;
+ break;
+ case 1:
+ fp->f_cookie = stdout;
+ break;
+ case 2:
+ fp->f_cookie = stderr;
+ break;
+ default:
+ sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
+ break;
+ }
+ }
+}
+
+/*
+** SM_STDIOREAD -- read from the file
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location to place the read data
+** n - number of bytes to read
+**
+** Returns:
+** result from fread().
+*/
+
+ssize_t
+sm_stdioread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fread(buf, 1, n, s);
+}
+
+/*
+** SM_STDIOWRITE -- write to the file
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location of data to write
+** n - number of bytes to write
+**
+** Returns:
+** result from fwrite().
+*/
+
+ssize_t
+sm_stdiowrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fwrite(buf, 1, n, s);
+}
+
+/*
+** SM_STDIOSEEK -- set position within file
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- new location based on 'whence'
+** whence -- indicates "base" for 'offset'
+**
+** Returns:
+** result from fseek().
+*/
+
+off_t
+sm_stdioseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fseek(s, offset, whence);
+}
+
+/*
+** SM_STDIOCLOSE -- close the file
+**
+** Parameters:
+** fp -- close file pointer
+**
+** Return:
+** status from fclose()
+*/
+
+int
+sm_stdioclose(fp)
+ SM_FILE_T *fp;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fclose(s);
+}
+
+/*
+** SM_STDIOSETINFO -- set info for this open file
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information setting
+** valp -- memory location of info to set
+**
+** Return:
+** Failure: -1 and sets errno
+** Success: none (currently).
+*/
+
+/* ARGSUSED2 */
+int
+sm_stdiosetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STDIOGETINFO -- get info for this open file
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information request
+** valp -- memory location to place info
+**
+** Return:
+** Failure: -1 and sets errno
+** Success: none (currently).
+*/
+
+/* ARGSUSED2 */
+int
+sm_stdiogetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
+**
+** Parameters:
+** stream -- an open stdio stream, as returned by fopen()
+** mode -- the mode argument to fopen() which describes stream
+**
+** Return:
+** On success, return a pointer to an SM_FILE object which
+** can be used for reading and writing 'stream'.
+** Abort if mode is gibberish or stream is bad.
+** Raise an exception if we can't allocate memory.
+*/
+
+SM_FILE_T *
+sm_io_stdioopen(stream, mode)
+ FILE *stream;
+ char *mode;
+{
+ int fd;
+ bool r, w;
+ int ioflags;
+ SM_FILE_T *fp;
+
+ fd = fileno(stream);
+ SM_REQUIRE(fd >= 0);
+
+ r = w = false;
+ switch (mode[0])
+ {
+ case 'r':
+ r = true;
+ break;
+ case 'w':
+ case 'a':
+ w = true;
+ break;
+ default:
+ sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
+ }
+ if (strchr(&mode[1], '+') != NULL)
+ r = w = true;
+ if (r && w)
+ ioflags = SMRW;
+ else if (r)
+ ioflags = SMRD;
+ else
+ ioflags = SMWR;
+
+ fp = sm_fp(SmFtRealStdio, ioflags, NULL);
+ fp->f_file = fd;
+ fp->f_cookie = stream;
+ return fp;
+}
diff --git a/contrib/sendmail/libsm/snprintf.c b/contrib/sendmail/libsm/snprintf.c
new file mode 100644
index 0000000..5ee3006
--- /dev/null
+++ b/contrib/sendmail/libsm/snprintf.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: snprintf.c,v 1.23 2001/09/11 04:04:49 gshapiro Exp $")
+#include <limits.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_SNPRINTF -- format a string to a memory location of restricted size
+**
+** Parameters:
+** str -- memory location to place formatted string
+** n -- size of buffer pointed to by str, capped to
+** a maximum of INT_MAX
+** fmt -- the formatting directives
+** ... -- the data to satisfy the formatting
+**
+** Returns:
+** Failure: -1
+** Success: number of bytes that would have been written
+** to str, not including the trailing '\0',
+** up to a maximum of INT_MAX, as if there was
+** no buffer size limitation. If the result >= n
+** then the output was truncated.
+**
+** Side Effects:
+** If n > 0, then between 0 and n-1 bytes of formatted output
+** are written into 'str', followed by a '\0'.
+*/
+
+int
+#if SM_VA_STD
+sm_snprintf(char *str, size_t n, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_snprintf(str, n, fmt, va_alist)
+ char *str;
+ size_t n;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+ SM_FILE_T fake;
+
+ /* While snprintf(3) specifies size_t stdio uses an int internally */
+ if (n > INT_MAX)
+ n = INT_MAX;
+ SM_VA_START(ap, fmt);
+
+ /* XXX put this into a static? */
+ fake.sm_magic = SmFileMagic;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_cookie = &fake;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = n ? n - 1 : 0;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_snprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (n > 0)
+ *fake.f_p = '\0';
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/sscanf.c b/contrib/sendmail/libsm/sscanf.c
new file mode 100644
index 0000000..178e76b
--- /dev/null
+++ b/contrib/sendmail/libsm/sscanf.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: sscanf.c,v 1.24 2001/09/11 04:04:49 gshapiro Exp $")
+#include <string.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_EOFREAD -- dummy read function for faked file below
+**
+** Parameters:
+** fp -- file pointer
+** buf -- location to place read data
+** len -- number of bytes to read
+**
+** Returns:
+** 0 (zero) always
+*/
+
+static ssize_t
+sm_eofread __P((
+ SM_FILE_T *fp,
+ char *buf,
+ size_t len));
+
+/* ARGSUSED0 */
+static ssize_t
+sm_eofread(fp, buf, len)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t len;
+{
+ return 0;
+}
+
+/*
+** SM_IO_SSCANF -- scan a string to find data units
+**
+** Parameters:
+** str -- strings containing data
+** fmt -- format directive for finding data units
+** ... -- memory locations to place format found data units
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: number of data units found
+**
+** Side Effects:
+** Attempts to strlen() 'str'; if not a '\0' terminated string
+** then the call may SEGV/fail.
+** Faking the string 'str' as a file.
+*/
+
+int
+#if SM_VA_STD
+sm_io_sscanf(const char *str, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_sscanf(str, fmt, va_alist)
+ const char *str;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_FILE_T fake;
+ SM_VA_LOCAL_DECL
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_flags = SMRD;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *) str;
+ fake.f_bf.smb_size = fake.f_r = strlen(str);
+ fake.f_file = -1;
+ fake.f_read = sm_eofread;
+ fake.f_write = NULL;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_io_sscanf:fake";
+ fake.f_flushfp = NULL;
+ fake.f_ub.smb_base = NULL;
+ fake.f_lb.smb_base = NULL;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ SM_VA_START(ap, fmt);
+ ret = sm_vfscanf(&fake, SM_TIME_FOREVER, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/stdio.c b/contrib/sendmail/libsm/stdio.c
new file mode 100644
index 0000000..e688fb9
--- /dev/null
+++ b/contrib/sendmail/libsm/stdio.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: stdio.c,v 1.52 2001/09/18 21:45:23 gshapiro Exp $")
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/fdset.h>
+#include <sm/setjmp.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** Overall:
+** Small standard I/O/seek/close functions.
+** These maintain the `known seek offset' for seek optimization.
+*/
+
+/*
+** SM_STDOPEN -- open a file with stdio behavior
+**
+** Not associated with the system's stdio in libc.
+**
+** Parameters:
+** fp -- file pointer to be associated with the open
+** info -- pathname of the file to be opened
+** flags -- indicates type of access methods
+** rpool -- ignored
+**
+** Returns:
+** Failure: -1 and set errno
+** Success: 0 or greater (fd of file from open(2)).
+**
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ char *path = (char *) info;
+ int oflags;
+
+ switch (flags)
+ {
+ case SM_IO_RDWR:
+ oflags = O_RDWR;
+ break;
+ case SM_IO_RDWRTR:
+ oflags = O_RDWR | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_RDONLY:
+ oflags = O_RDONLY;
+ break;
+ case SM_IO_WRONLY:
+ oflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_APPEND:
+ oflags = O_APPEND | O_WRONLY | O_CREAT;
+ break;
+ case SM_IO_APPENDRW:
+ oflags = O_APPEND | O_RDWR | O_CREAT;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_file = open(path, oflags,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (fp->f_file < 0)
+ return -1; /* errno set by open() */
+
+ if (oflags & O_APPEND)
+ (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END);
+
+ return fp->f_file;
+}
+
+/*
+** SM_STDREAD -- read from the file
+**
+** Parameters:
+** fp -- file pointer to read from
+** buf -- location to place read data
+** n -- number of bytes to read
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: number of bytes read
+**
+** Side Effects:
+** Updates internal offset into file.
+*/
+
+ssize_t
+sm_stdread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register int ret;
+
+ ret = read(fp->f_file, buf, n);
+
+ /* if the read succeeded, update the current offset */
+ if (ret > 0)
+ fp->f_lseekoff += ret;
+ return ret;
+}
+
+/*
+** SM_STDWRITE -- write to the file
+**
+** Parameters:
+** fp -- file pointer ro write to
+** buf -- location of data to be written
+** n - number of bytes to write
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: number of bytes written
+*/
+
+ssize_t
+sm_stdwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ return write(fp->f_file, buf, n);
+}
+
+/*
+** SM_STDSEEK -- set the file offset position
+**
+** Parmeters:
+** fp -- file pointer to position
+** offset -- how far to position from "base" (set by 'whence')
+** whence -- indicates where the "base" of the 'offset' to start
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: the current offset
+**
+** Side Effects:
+** Updates the internal value of the offset.
+*/
+
+off_t
+sm_stdseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register off_t ret;
+
+ ret = lseek(fp->f_file, (off_t) offset, whence);
+ if (ret != (off_t) -1)
+ fp->f_lseekoff = ret;
+ return ret;
+}
+
+/*
+** SM_STDCLOSE -- close the file
+**
+** Parameters:
+** fp -- the file pointer to close
+**
+** Returns:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdclose(fp)
+ SM_FILE_T *fp;
+{
+ return close(fp->f_file);
+}
+
+/*
+** SM_STDSETMODE -- set the access mode for the file
+**
+** Called by sm_stdsetinfo().
+**
+** Parameters:
+** fp -- file pointer
+** mode -- new mode to set the file access to
+**
+** Results:
+** Success: 0 (zero);
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdsetmode(fp, mode)
+ SM_FILE_T *fp;
+ const int *mode;
+{
+ int flags = 0;
+
+ switch (*mode)
+ {
+ case SM_IO_RDWR:
+ flags |= SMRW;
+ break;
+ case SM_IO_RDONLY:
+ flags |= SMRD;
+ break;
+ case SM_IO_WRONLY:
+ flags |= SMWR;
+ break;
+ case SM_IO_APPEND:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_flags = fp->f_flags & ~SMMODEMASK;
+ fp->f_flags |= flags;
+ return 0;
+}
+
+/*
+** SM_STDGETMODE -- for getinfo determine open mode
+**
+** Called by sm_stdgetinfo().
+**
+** Parameters:
+** fp -- the file mode being determined
+** mode -- internal mode to map to external value
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: external mode value
+*/
+
+int
+sm_stdgetmode(fp, mode)
+ SM_FILE_T *fp;
+ int *mode;
+{
+ switch (fp->f_flags & SMMODEMASK)
+ {
+ case SMRW:
+ *mode = SM_IO_RDWR;
+ break;
+ case SMRD:
+ *mode = SM_IO_RDONLY;
+ break;
+ case SMWR:
+ *mode = SM_IO_WRONLY;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STDSETINFO -- set/modify information for a file
+**
+** Parameters:
+** fp -- file to set info for
+** what -- type of info to set
+** valp -- location of data used for setting
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0
+*/
+
+int
+sm_stdsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_stdsetmode(fp, (const int *)valp);
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_GETINFO -- get information about the open file
+**
+** Parameters:
+** fp -- file to get info for
+** what -- type of info to get
+** valp -- location to place found info
+**
+** Returns:
+** Success: may or may not place info in 'valp' depending
+** on 'what' value, and returns values >=0. Return
+** value may be the obtained info
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdgetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_stdgetmode(fp, (int *)valp);
+
+ case SM_IO_WHAT_FD:
+ return fp->f_file;
+
+ case SM_IO_IS_READABLE:
+ {
+ fd_set readfds;
+ struct timeval timeout;
+
+ FD_ZERO(&readfds);
+ SM_FD_SET(fp->f_file, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (select(fp->f_file + 1,
+ FDSET_CAST &readfds,
+ NULL,
+ NULL,
+ &timeout) > 0 &&
+ SM_FD_ISSET(fp->f_file, &readfds))
+ return 1;
+ return 0;
+ }
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STDFDOPEN -- open file by primative 'fd' rather than pathname
+**
+** I/O function to handle fdopen() stdio equivalence. The rest of
+** the functions are the same as the sm_stdopen() above.
+**
+** Parameters:
+** fp -- the file pointer to be associated with the open
+** name -- the primative file descriptor for association
+** flags -- indicates type of access methods
+** rpool -- ignored
+**
+** Results:
+** Success: primative file descriptor value
+** Failure: -1 and sets errno
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdfdopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ int oflags, tmp, fdflags, fd = *((int *) info);
+
+ switch (flags)
+ {
+ case SM_IO_RDWR:
+ oflags = O_RDWR | O_CREAT;
+ break;
+ case SM_IO_RDONLY:
+ oflags = O_RDONLY;
+ break;
+ case SM_IO_WRONLY:
+ oflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_APPEND:
+ oflags = O_APPEND | O_WRONLY | O_CREAT;
+ break;
+ case SM_IO_APPENDRW:
+ oflags = O_APPEND | O_RDWR | O_CREAT;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Make sure the mode the user wants is a subset of the actual mode. */
+ if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0)
+ return -1;
+
+ tmp = fdflags & O_ACCMODE;
+ if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE)))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_file = fd;
+ if (oflags & O_APPEND)
+ (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END);
+ return fp->f_file;
+}
+
+/*
+** SM_IO_FOPEN -- open a file
+**
+** Same interface and semantics as the open() system call,
+** except that it returns SM_FILE_T* instead of a file descriptor.
+**
+** Parameters:
+** pathname -- path of file to open
+** flags -- flags controlling the open
+** ... -- option "mode" for opening the file
+**
+** Returns:
+** Raises an exception on heap exhaustion.
+** Returns NULL and sets errno if open() fails.
+** Returns an SM_FILE_T pointer on success.
+*/
+
+SM_FILE_T *
+#if SM_VA_STD
+sm_io_fopen(char *pathname, int flags, ...)
+#else /* SM_VA_STD */
+sm_io_fopen(pathname, flags, va_alist)
+ char *pathname;
+ int flags;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ MODE_T mode;
+ SM_FILE_T *fp;
+ int ioflags;
+
+ if (flags & O_CREAT)
+ {
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, flags);
+ mode = (MODE_T) SM_VA_ARG(ap, int);
+ SM_VA_END(ap);
+ }
+ else
+ mode = 0;
+
+ switch (flags & O_ACCMODE)
+ {
+ case O_RDONLY:
+ ioflags = SMRD;
+ break;
+ case O_WRONLY:
+ ioflags = SMWR;
+ break;
+ case O_RDWR:
+ ioflags = SMRW;
+ break;
+ default:
+ sm_abort("sm_io_fopen: bad flags 0%o", flags);
+ }
+
+ fp = sm_fp(SmFtStdio, ioflags, NULL);
+ fp->f_file = open(pathname, flags, mode);
+ if (fp->f_file == -1)
+ {
+ fp->f_flags = 0;
+ fp->sm_magic = NULL;
+ return NULL;
+ }
+ return fp;
+}
diff --git a/contrib/sendmail/libsm/strcasecmp.c b/contrib/sendmail/libsm/strcasecmp.c
new file mode 100644
index 0000000..15f5ce8
--- /dev/null
+++ b/contrib/sendmail/libsm/strcasecmp.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strcasecmp.c,v 1.15 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/config.h>
+#include <sm/string.h>
+#include <string.h>
+
+/*
+** SM_STRCASECMP -- 8-bit clean version of strcasecmp
+**
+** Thank you, vendors, for making this all necessary.
+*/
+
+/*
+** This array is designed for mapping upper and lower case letter
+** together for a case independent comparison. The mappings are
+** based upon ascii character sequences.
+*/
+
+const unsigned char charmap[] =
+{
+ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
+ 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+ 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
+ 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
+ 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+ 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+ 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
+ 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
+ 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+ 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+ 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+ 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
+};
+
+int
+sm_strcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ while (charmap[*us1] == charmap[*us2])
+ {
+ if (*us1 == '\0')
+ return 0;
+ ++us1;
+ ++us2;
+ }
+ return charmap[*us1] - charmap[*us2];
+}
+
+int
+sm_strncasecmp(s1, s2, n)
+ const char *s1, *s2;
+ register size_t n;
+{
+ if (n != 0)
+ {
+ register const unsigned char *cm = charmap;
+ register const unsigned char *us1 = (const unsigned char *)s1;
+ register const unsigned char *us2 = (const unsigned char *)s2;
+
+ do
+ {
+ if (cm[*us1] != cm[*us2++])
+ return (cm[*us1] - cm[*--us2]);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/strdup.c b/contrib/sendmail/libsm/strdup.c
new file mode 100644
index 0000000..64fe5c2
--- /dev/null
+++ b/contrib/sendmail/libsm/strdup.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strdup.c,v 1.13 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/heap.h>
+#include <sm/string.h>
+
+/*
+** SM_STRNDUP_X -- Duplicate a string of a given length
+**
+** Allocates memory and copies source string (of given length) into it.
+**
+** Parameters:
+** s -- string to copy.
+** n -- length to copy.
+**
+** Returns:
+** copy of string, raises exception if out of memory.
+**
+** Side Effects:
+** allocate memory for new string.
+*/
+
+char *
+sm_strndup_x(s, n)
+ const char *s;
+ size_t n;
+{
+ char *d = sm_malloc_x(n + 1);
+
+ (void) memcpy(d, s, n);
+ d[n] = '\0';
+ return d;
+}
+
+/*
+** SM_STRDUP -- Duplicate a string
+**
+** Allocates memory and copies source string into it.
+**
+** Parameters:
+** s -- string to copy.
+**
+** Returns:
+** copy of string, NULL if out of memory.
+**
+** Side Effects:
+** allocate memory for new string.
+*/
+
+char *
+sm_strdup(s)
+ char *s;
+{
+ size_t l;
+ char *d;
+
+ l = strlen(s) + 1;
+ d = sm_malloc_tagged(l, "sm_strdup", 0, sm_heap_group());
+ if (d != NULL)
+ (void) sm_strlcpy(d, s, l);
+ return d;
+}
diff --git a/contrib/sendmail/libsm/strerror.c b/contrib/sendmail/libsm/strerror.c
new file mode 100644
index 0000000..ffdfb21
--- /dev/null
+++ b/contrib/sendmail/libsm/strerror.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strerror.c,v 1.23 2001/09/11 04:04:49 gshapiro Exp $")
+
+/*
+** define strerror for platforms that lack it.
+*/
+
+#include <errno.h>
+#include <stdio.h> /* sys_errlist, on some platforms */
+
+#include <sm/io.h> /* sm_snprintf */
+#include <sm/string.h>
+#include <sm/conf.h>
+#include <sm/errstring.h>
+
+#if !defined(ERRLIST_PREDEFINED)
+extern char *sys_errlist[];
+extern int sys_nerr;
+#endif /* !defined(ERRLIST_PREDEFINED) */
+
+#if !HASSTRERROR
+
+/*
+** STRERROR -- return error message string corresponding to an error number.
+**
+** Parameters:
+** err -- error number.
+**
+** Returns:
+** Error string (might be pointer to static buffer).
+*/
+
+char *
+strerror(err)
+ int err;
+{
+ static char buf[64];
+
+ if (err >= 0 && err < sys_nerr)
+ return (char *) sys_errlist[err];
+ else
+ {
+ (void) sm_snprintf(buf, sizeof(buf), "Error %d", err);
+ return buf;
+ }
+}
+#endif /* !HASSTRERROR */
diff --git a/contrib/sendmail/libsm/strexit.c b/contrib/sendmail/libsm/strexit.c
new file mode 100644
index 0000000..0f2cdfc
--- /dev/null
+++ b/contrib/sendmail/libsm/strexit.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strexit.c,v 1.5 2001/09/11 04:04:49 gshapiro Exp $")
+#include <sm/string.h>
+#include <sm/sysexits.h>
+
+/*
+** SM_STREXIT -- convert EX_* value from <sm/sysexits.h> to a character string
+**
+** This function is analogous to strerror(), except that it
+** operates on EX_* values from <sm/sysexits.h>.
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** pointer to a static message string
+*/
+
+char *
+sm_strexit(ex)
+ int ex;
+{
+ char *msg;
+ static char buf[64];
+
+ msg = sm_sysexitmsg(ex);
+ if (msg == NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf, "Unknown exit status %d",
+ ex);
+ msg = buf;
+ }
+ return msg;
+}
+
+/*
+** SM_SYSEXITMSG -- convert an EX_* value to a character string, or NULL
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** If ex is a known exit value, then a pointer to a static
+** message string is returned. Otherwise NULL is returned.
+*/
+
+char *
+sm_sysexitmsg(ex)
+ int ex;
+{
+ char *msg;
+
+ msg = sm_sysexmsg(ex);
+ if (msg != NULL)
+ return &msg[11];
+ else
+ return msg;
+}
+
+/*
+** SM_SYSEXMSG -- convert an EX_* value to a character string, or NULL
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** If ex is a known exit value, then a pointer to a static
+** string is returned. Otherwise NULL is returned.
+** The string contains the following fixed width fields:
+** [0] ':' if there is an errno value associated with this
+** exit value, otherwise ' '.
+** [1,3] 3 digit SMTP error code
+** [4] ' '
+** [5,9] 3 digit SMTP extended error code
+** [10] ' '
+** [11,] message string
+*/
+
+char *
+sm_sysexmsg(ex)
+ int ex;
+{
+ switch (ex)
+ {
+ case EX_USAGE:
+ return " 500 5.0.0 Command line usage error";
+ case EX_DATAERR:
+ return " 501 5.6.0 Data format error";
+ case EX_NOINPUT:
+ return ":550 5.3.0 Cannot open input";
+ case EX_NOUSER:
+ return " 550 5.1.1 User unknown";
+ case EX_NOHOST:
+ return " 550 5.1.2 Host unknown";
+ case EX_UNAVAILABLE:
+ return " 554 5.0.0 Service unavailable";
+ case EX_SOFTWARE:
+ return ":554 5.3.0 Internal error";
+ case EX_OSERR:
+ return ":451 4.0.0 Operating system error";
+ case EX_OSFILE:
+ return ":554 5.3.5 System file missing";
+ case EX_CANTCREAT:
+ return ":550 5.0.0 Can't create output";
+ case EX_IOERR:
+ return ":451 4.0.0 I/O error";
+ case EX_TEMPFAIL:
+ return " 450 4.0.0 Deferred";
+ case EX_PROTOCOL:
+ return " 554 5.5.0 Remote protocol error";
+ case EX_NOPERM:
+ return ":550 5.0.0 Insufficient permission";
+ case EX_CONFIG:
+ return " 554 5.3.5 Local configuration error";
+ default:
+ return NULL;
+ }
+}
diff --git a/contrib/sendmail/libsm/string.c b/contrib/sendmail/libsm/string.c
new file mode 100644
index 0000000..b0b6975
--- /dev/null
+++ b/contrib/sendmail/libsm/string.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: string.c,v 1.3 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <ctype.h>
+#include <errno.h>
+
+#include <sm/string.h>
+
+/*
+** STRIPQUOTES -- Strip quotes & quote bits from a string.
+**
+** Runs through a string and strips off unquoted quote
+** characters and quote bits. This is done in place.
+**
+** Parameters:
+** s -- the string to strip.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+void
+stripquotes(s)
+ char *s;
+{
+ register char *p;
+ register char *q;
+ register char c;
+
+ if (s == NULL)
+ return;
+
+ p = q = s;
+ do
+ {
+ c = *p++;
+ if (c == '\\')
+ c = *p++;
+ else if (c == '"')
+ continue;
+ *q++ = c;
+ } while (c != '\0');
+}
diff --git a/contrib/sendmail/libsm/stringf.c b/contrib/sendmail/libsm/stringf.c
new file mode 100644
index 0000000..b6a7f66
--- /dev/null
+++ b/contrib/sendmail/libsm/stringf.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: stringf.c,v 1.15 2001/09/11 04:04:49 gshapiro Exp $")
+#include <errno.h>
+#include <stdio.h>
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+
+/*
+** SM_STRINGF_X -- printf() to dynamically allocated string.
+**
+** Takes the same arguments as printf.
+** It returns a pointer to a dynamically allocated string
+** containing the text that printf would print to standard output.
+** It raises an exception on error.
+** The name comes from a PWB Unix function called stringf.
+**
+** Parameters:
+** fmt -- format string.
+** ... -- arguments for format.
+**
+** Returns:
+** Pointer to a dynamically allocated string.
+**
+** Exceptions:
+** F:sm_heap -- out of memory (via sm_vstringf_x()).
+*/
+
+char *
+#if SM_VA_STD
+sm_stringf_x(const char *fmt, ...)
+#else /* SM_VA_STD */
+sm_stringf_x(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ SM_VA_LOCAL_DECL
+ char *s;
+
+ SM_VA_START(ap, fmt);
+ s = sm_vstringf_x(fmt, ap);
+ SM_VA_END(ap);
+ return s;
+}
+
+/*
+** SM_VSTRINGF_X -- printf() to dynamically allocated string.
+**
+** Parameters:
+** fmt -- format string.
+** ap -- arguments for format.
+**
+** Returns:
+** Pointer to a dynamically allocated string.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+char *
+sm_vstringf_x(fmt, ap)
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ char *s;
+
+ sm_vasprintf(&s, fmt, ap);
+ if (s == NULL)
+ {
+ if (errno == ENOMEM)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ sm_exc_raisenew_x(&SmEtypeOs, errno, "sm_vasprintf", NULL);
+ }
+ return s;
+}
diff --git a/contrib/sendmail/libsm/strio.c b/contrib/sendmail/libsm/strio.c
new file mode 100644
index 0000000..203d192
--- /dev/null
+++ b/contrib/sendmail/libsm/strio.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: strio.c,v 1.40 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sm/rpool.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** Cookie structure for the "strio" file type
+*/
+
+struct sm_str_obj
+{
+ char *strio_base;
+ char *strio_end;
+ size_t strio_size;
+ size_t strio_offset;
+ int strio_flags;
+};
+
+typedef struct sm_str_obj SM_STR_OBJ_T;
+
+/*
+** SM_STRGROW -- increase storage space for string
+**
+** Parameters:
+** s -- current cookie
+** size -- new storage size request
+**
+** Returns:
+** true iff successful.
+*/
+
+static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
+
+static bool
+sm_strgrow(s, size)
+ SM_STR_OBJ_T *s;
+ size_t size;
+{
+ register void *p;
+
+ if (s->strio_size >= size)
+ return true;
+ p = sm_realloc(s->strio_base, size);
+ if (p == NULL)
+ return false;
+ s->strio_base = p;
+ s->strio_end = s->strio_base + size;
+ s->strio_size = size;
+ return true;
+}
+
+/*
+** SM_STRREAD -- read a portion of the string
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location to place read data
+** n -- number of bytes to read
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes read
+*/
+
+ssize_t
+sm_strread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+ int len;
+
+ if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW))
+ {
+ errno = EBADF;
+ return -1;
+ }
+ len = SM_MIN(s->strio_size - s->strio_offset, n);
+ (void) memmove(buf, s->strio_base + s->strio_offset, len);
+ s->strio_offset += len;
+ return len;
+}
+
+/*
+** SM_STRWRITE -- write a portion of the string
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location of data for writting
+** n -- number of bytes to write
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes written
+*/
+
+ssize_t
+sm_strwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+ if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW))
+ {
+ errno = EBADF;
+ return -1;
+ }
+ if (n + s->strio_offset > s->strio_size)
+ {
+ if (!sm_strgrow(s, n + s->strio_offset))
+ return 0;
+ }
+ (void) memmove(s->strio_base + s->strio_offset, buf, n);
+ s->strio_offset += n;
+ return n;
+}
+
+/*
+** SM_STRSEEK -- position the offset pointer for the string
+**
+** Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid
+** values for whence.
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- number of bytes offset from "base"
+** whence -- determines "base" for 'offset'
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes read
+*/
+
+off_t
+sm_strseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register off_t ret;
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+reseek:
+ switch (whence)
+ {
+ case SM_IO_SEEK_SET:
+ ret = offset;
+ break;
+ case SM_IO_SEEK_CUR:
+ ret = s->strio_offset + offset;
+ break;
+ case SM_IO_SEEK_END:
+ ret = s->strio_size;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ if (ret < 0 || ret > (off_t)(size_t)(-1)) /* XXX ugly */
+ return -1;
+ if ((size_t) ret > s->strio_size)
+ {
+ if (sm_strgrow(s, (size_t)ret))
+ goto reseek;
+
+ /* errno set by sm_strgrow */
+ return -1;
+ }
+ s->strio_offset = (size_t) ret;
+ return ret;
+}
+
+/*
+** SM_STROPEN -- open a string file type
+**
+** Parameters:
+** fp -- file pointer open to be associated with
+** info -- flags for methods of access (was mode)
+** flags -- ignored
+** rpool -- resource pool to use memory from (if applicable)
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stropen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register SM_STR_OBJ_T *s;
+ int *strmode = (int *) info;
+
+#if SM_RPOOL
+ s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
+#else /* SM_RPOOL */
+ s = sm_malloc(sizeof(SM_STR_OBJ_T));
+ if (s == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+#endif /* SM_RPOOL */
+
+ fp->f_cookie = s;
+ s->strio_offset = 0;
+ s->strio_base = 0;
+ s->strio_end = 0;
+ switch (*strmode)
+ {
+ case SM_IO_RDWR:
+ s->strio_flags = SMRW;
+ break;
+ case SM_IO_RDONLY:
+ s->strio_flags = SMRD;
+ break;
+ case SM_IO_WRONLY:
+ s->strio_flags = SMWR;
+ break;
+ case SM_IO_APPEND:
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STRCLOSE -- close the string file type and free resources
+**
+** Parameters:
+** fp -- file pointer
+**
+** Results:
+** Success: 0 (zero)
+*/
+
+int
+sm_strclose(fp)
+ SM_FILE_T *fp;
+{
+ SM_STR_OBJ_T *s = fp->f_cookie;
+
+#if !SM_RPOOL
+ sm_free(s->strio_base);
+ s->strio_base = NULL;
+#endif /* !SM_RPOOL */
+ return 0;
+}
+
+/*
+** SM_STRSETMODE -- set mode info for the file
+**
+** Note: changing the mode can be a safe way to have the "parent"
+** set up a string that the "child" is not to modify
+**
+** Parameters:
+** fp -- the file pointer
+** mode -- location of new mode to set
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_strsetmode(fp, mode)
+ SM_FILE_T *fp;
+ const int *mode;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+ int flags;
+
+ switch (*mode)
+ {
+ case SM_IO_RDWR:
+ flags = SMRW;
+ break;
+ case SM_IO_RDONLY:
+ flags = SMRD;
+ break;
+ case SM_IO_WRONLY:
+ flags = SMWR;
+ break;
+ case SM_IO_APPEND:
+ errno = EINVAL;
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ s->strio_flags &= ~SMMODEMASK;
+ s->strio_flags |= flags;
+ return 0;
+}
+
+/*
+** SM_STRGETMODE -- get mode info for the file
+**
+** Parameters:
+** fp -- the file pointer
+** mode -- location to store current mode
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_strgetmode(fp, mode)
+ SM_FILE_T *fp;
+ int *mode;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+ switch (s->strio_flags & SMMODEMASK)
+ {
+ case SMRW:
+ *mode = SM_IO_RDWR;
+ break;
+ case SMRD:
+ *mode = SM_IO_RDONLY;
+ break;
+ case SMWR:
+ *mode = SM_IO_WRONLY;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STRSETINFO -- set info for the file
+**
+** Currently only SM_IO_WHAT_MODE is supported for 'what'.
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information to set
+** valp -- location to data for doing set
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: sm_strsetmode() return [0 (zero)]
+*/
+
+int
+sm_strsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch(what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_strsetmode(fp, (int *) valp);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STRGETINFO -- get info for the file
+**
+** Currently only SM_IO_WHAT_MODE is supported for 'what'.
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information requested
+** valp -- location to return information in
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: sm_strgetmode() return [0 (zero)]
+*/
+
+int
+sm_strgetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch(what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_strgetmode(fp, (int *) valp);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STRIO_INIT -- initializes a write-only string type
+**
+** Original comments below. This function does not appear to be used anywhere.
+** The same functionality can be done by changing the mode of the file.
+** ------------
+** sm_strio_init initializes an SM_FILE_T structure as a write-only file
+** that writes into the specified buffer:
+** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer.
+** Attempts to write more than size-1 characters into the buffer will fail
+** silently (no error is reported).
+** - Use sm_io_fflush to nul terminate the string in the buffer
+** (the write pointer is not advanced).
+** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc.
+**
+** Parameters:
+** fp -- file pointer
+** buf -- memory location for stored data
+** size -- size of 'buf'
+**
+** Results:
+** none.
+*/
+
+void
+sm_strio_init(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t size;
+{
+ fp->sm_magic = SmFileMagic;
+ fp->f_flags = SMWR | SMSTR;
+ fp->f_file = -1;
+ fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf;
+ fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0);
+ fp->f_lbfsize = 0;
+ fp->f_r = 0;
+ fp->f_read = NULL;
+ fp->f_seek = NULL;
+ fp->f_getinfo = NULL;
+ fp->f_setinfo = NULL;
+}
diff --git a/contrib/sendmail/libsm/strl.c b/contrib/sendmail/libsm/strl.c
new file mode 100644
index 0000000..fbf6c06
--- /dev/null
+++ b/contrib/sendmail/libsm/strl.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strl.c,v 1.29 2001/10/03 16:09:32 ca Exp $")
+#include <sm/config.h>
+#include <sm/string.h>
+
+/*
+** Notice: this file is used by libmilter. Please try to avoid
+** using libsm specific functions.
+*/
+
+/*
+** XXX the type of the length parameter has been changed
+** from size_t to ssize_t to avoid theoretical problems with negative
+** numbers passed into these functions.
+** The real solution to this problem is to make sure that this doesn't
+** happen, but for now we'll use this workaround.
+*/
+
+/*
+** SM_STRLCPY -- size bounded string copy
+**
+** This is a bounds-checking variant of strcpy.
+** If size > 0, copy up to size-1 characters from the nul terminated
+** string src to dst, nul terminating the result. If size == 0,
+** the dst buffer is not modified.
+** Additional note: this function has been "tuned" to run fast and tested
+** as such (versus versions in some OS's libc).
+**
+** The result is strlen(src). You can detect truncation (not all
+** of the characters in the source string were copied) using the
+** following idiom:
+**
+** char *s, buf[BUFSIZ];
+** ...
+** if (sm_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
+** goto overflow;
+**
+** Parameters:
+** dst -- destination buffer
+** src -- source string
+** size -- size of destination buffer
+**
+** Returns:
+** strlen(src)
+*/
+
+size_t
+sm_strlcpy(dst, src, size)
+ register char *dst;
+ register const char *src;
+ ssize_t size;
+{
+ register ssize_t i;
+
+ if (size-- <= 0)
+ return strlen(src);
+ for (i = 0; i < size && (dst[i] = src[i]) != 0; i++)
+ continue;
+ dst[i] = '\0';
+ if (src[i] == '\0')
+ return i;
+ else
+ return i + strlen(src + i);
+}
+
+/*
+** SM_STRLCAT -- size bounded string concatenation
+**
+** This is a bounds-checking variant of strcat.
+** If strlen(dst) < size, then append at most size - strlen(dst) - 1
+** characters from the source string to the destination string,
+** nul terminating the result. Otherwise, dst is not modified.
+**
+** The result is the initial length of dst + the length of src.
+** You can detect overflow (not all of the characters in the
+** source string were copied) using the following idiom:
+**
+** char *s, buf[BUFSIZ];
+** ...
+** if (sm_strlcat(buf, s, sizeof(buf)) >= sizeof(buf))
+** goto overflow;
+**
+** Parameters:
+** dst -- nul-terminated destination string buffer
+** src -- nul-terminated source string
+** size -- size of destination buffer
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+*/
+
+size_t
+sm_strlcat(dst, src, size)
+ register char *dst;
+ register const char *src;
+ ssize_t size;
+{
+ register ssize_t i, j, o;
+
+ o = strlen(dst);
+ if (size < o + 1)
+ return o + strlen(src);
+ size -= o + 1;
+ for (i = 0, j = o; i < size && (dst[j] = src[i]) != 0; i++, j++)
+ continue;
+ dst[j] = '\0';
+ if (src[i] == '\0')
+ return j;
+ else
+ return j + strlen(src + i);
+}
+/*
+** SM_STRLCAT2 -- append two strings to dst obeying length and
+** '\0' terminate it
+**
+** strlcat2 will append at most len - strlen(dst) - 1 chars.
+** terminates with '\0' if len > 0
+** dst = dst "+" src1 "+" src2
+** use this instead of sm_strlcat(dst,src1); sm_strlcat(dst,src2);
+** for better speed.
+**
+** Parameters:
+** dst -- "destination" string.
+** src1 -- "from" string 1.
+** src2 -- "from" string 2.
+** len -- max. length of "destination" string.
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+** if this is greater than len then an overflow would have
+** occurred.
+**
+*/
+
+size_t
+sm_strlcat2(dst, src1, src2, len)
+ register char *dst;
+ register const char *src1;
+ register const char *src2;
+ ssize_t len;
+{
+ register ssize_t i, j, o;
+
+ /* current size of dst */
+ o = strlen(dst);
+
+ /* max. size is less than current? */
+ if (len < o + 1)
+ return o + strlen(src1) + strlen(src2);
+
+ len -= o + 1; /* space left in dst */
+
+ /* copy the first string; i: index in src1; j: index in dst */
+ for (i = 0, j = o; i < len && (dst[j] = src1[i]) != 0; i++, j++)
+ continue;
+
+ /* src1: end reached? */
+ if (src1[i] != '\0')
+ {
+ /* no: terminate dst; there is space since i < len */
+ dst[j] = '\0';
+ return j + strlen(src1 + i) + strlen(src2);
+ }
+
+ len -= i; /* space left in dst */
+
+ /* copy the second string; i: index in src2; j: index in dst */
+ for (i = 0; i < len && (dst[j] = src2[i]) != 0; i++, j++)
+ continue;
+ dst[j] = '\0'; /* terminate dst; there is space since i < len */
+ if (src2[i] == '\0')
+ return j;
+ else
+ return j + strlen(src2 + i);
+}
+
+/*
+** SM_STRLCPYN -- concatenate n strings and assign the result to dst
+** while obeying length and '\0' terminate it
+**
+** dst = src1 "+" src2 "+" ...
+** use this instead of sm_snprintf() for string values
+** and repeated sm_strlc*() calls for better speed.
+**
+** Parameters:
+** dst -- "destination" string.
+** len -- max. length of "destination" string.
+** n -- number of strings
+** strings...
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+** if this is greater than len then an overflow would have
+** occurred.
+*/
+
+size_t
+#ifdef __STDC__
+sm_strlcpyn(char *dst, ssize_t len, int n, ...)
+#else /* __STDC__ */
+sm_strlcpyn(dst, len, n, va_alist)
+ register char *dst;
+ ssize_t len;
+ int n;
+ va_dcl
+#endif /* __STDC__ */
+{
+ register ssize_t i, j;
+ char *str;
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, n);
+
+ if (len-- <= 0) /* This allows space for the terminating '\0' */
+ {
+ i = 0;
+ while (n-- > 0)
+ i += strlen(SM_VA_ARG(ap, char *));
+ return i;
+ }
+
+ j = 0; /* index in dst */
+
+ /* loop through all source strings */
+ while (n-- > 0)
+ {
+ str = SM_VA_ARG(ap, char *);
+
+ /* copy string; i: index in str; j: index in dst */
+ for (i = 0; j < len && (dst[j] = str[i]) != 0; i++, j++)
+ continue;
+
+ /* str: end reached? */
+ if (str[i] != '\0')
+ {
+ /* no: terminate dst; there is space since j < len */
+ dst[j] = '\0';
+ j += strlen(str + i);
+ while (n-- > 0)
+ j += strlen(SM_VA_ARG(ap, char *));
+ return j;
+ }
+ }
+
+ dst[j] = '\0'; /* terminate dst; there is space since j < len */
+ return j;
+}
+
+#if 0
+/*
+** SM_STRLAPP -- append string if it fits into buffer.
+**
+** If size > 0, copy up to size-1 characters from the nul terminated
+** string src to dst, nul terminating the result. If size == 0,
+** the dst buffer is not modified.
+**
+** This routine is useful for appending strings in a loop, e.g, instead of
+** s = buf;
+** for (ptr, ptr != NULL, ptr = next->ptr)
+** {
+** (void) sm_strlcpy(s, ptr->string, sizeof buf - (s - buf));
+** s += strlen(s);
+** }
+** replace the loop body with:
+** if (!sm_strlapp(*s, ptr->string, sizeof buf - (s - buf)))
+** break;
+** it's faster...
+**
+** XXX interface isn't completely clear (yet), hence this code is
+** not available.
+**
+**
+** Parameters:
+** dst -- (pointer to) destination buffer
+** src -- source string
+** size -- size of destination buffer
+**
+** Returns:
+** true if strlen(src) < size
+**
+** Side Effects:
+** modifies dst if append succeeds (enough space).
+*/
+
+bool
+sm_strlapp(dst, src, size)
+ register char **dst;
+ register const char *src;
+ ssize_t size;
+{
+ register size_t i;
+
+ if (size-- <= 0)
+ return false;
+ for (i = 0; i < size && ((*dst)[i] = src[i]) != '\0'; i++)
+ continue;
+ (*dst)[i] = '\0';
+ if (src[i] == '\0')
+ {
+ *dst += i;
+ return true;
+ }
+
+ /* undo */
+ (*dst)[0] = '\0';
+ return false;
+}
+#endif /* 0 */
diff --git a/contrib/sendmail/libsm/strrevcmp.c b/contrib/sendmail/libsm/strrevcmp.c
new file mode 100644
index 0000000..d0ed630
--- /dev/null
+++ b/contrib/sendmail/libsm/strrevcmp.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: strrevcmp.c,v 1.5 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/config.h>
+#include <sm/string.h>
+#include <string.h>
+
+/* strcasecmp.c */
+extern const unsigned char charmap[];
+
+/*
+** SM_STRREVCASECMP -- compare two strings starting at the end (ignore case)
+**
+** Parameters:
+** s1 -- first string.
+** s2 -- second string.
+**
+** Returns:
+** strcasecmp(reverse(s1), reverse(s2))
+*/
+
+int
+sm_strrevcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ register int i1, i2;
+
+ i1 = strlen(s1) - 1;
+ i2 = strlen(s2) - 1;
+ while (i1 >= 0 && i2 >= 0 &&
+ charmap[(unsigned char) s1[i1]] ==
+ charmap[(unsigned char) s2[i2]])
+ {
+ --i1;
+ --i2;
+ }
+ if (i1 < 0)
+ {
+ if (i2 < 0)
+ return 0;
+ else
+ return -1;
+ }
+ else
+ {
+ if (i2 < 0)
+ return 1;
+ else
+ return (charmap[(unsigned char) s1[i1]] -
+ charmap[(unsigned char) s2[i2]]);
+ }
+}
+/*
+** SM_STRREVCMP -- compare two strings starting at the end
+**
+** Parameters:
+** s1 -- first string.
+** s2 -- second string.
+**
+** Returns:
+** strcmp(reverse(s1), reverse(s2))
+*/
+
+int
+sm_strrevcmp(s1, s2)
+ const char *s1, *s2;
+{
+ register int i1, i2;
+
+ i1 = strlen(s1) - 1;
+ i2 = strlen(s2) - 1;
+ while (i1 >= 0 && i2 >= 0 && s1[i1] == s2[i2])
+ {
+ --i1;
+ --i2;
+ }
+ if (i1 < 0)
+ {
+ if (i2 < 0)
+ return 0;
+ else
+ return -1;
+ }
+ else
+ {
+ if (i2 < 0)
+ return 1;
+ else
+ return s1[i1] - s2[i2];
+ }
+}
diff --git a/contrib/sendmail/libsm/strto.c b/contrib/sendmail/libsm/strto.c
new file mode 100644
index 0000000..87e84bf
--- /dev/null
+++ b/contrib/sendmail/libsm/strto.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1992
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: strto.c,v 1.18 2001/12/30 04:59:37 gshapiro Exp $")
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sm/limits.h>
+#include <sm/conf.h>
+#include <sm/string.h>
+
+/*
+** SM_STRTOLL -- Convert a string to a (signed) long long integer.
+**
+** Ignores `locale' stuff. Assumes that the upper and lower case
+** alphabets and digits are each contiguous.
+**
+** Parameters:
+** nptr -- string containing number
+** endptr -- location of first invalid character
+** base -- numeric base that 'nptr' number is based in
+**
+** Returns:
+** Failure: on underflow LLONG_MIN is returned; on overflow
+** LLONG_MAX is returned and errno is set.
+** When 'endptr' == '\0' then the entire string 'nptr'
+** was valid.
+** Success: returns the converted number
+*/
+
+LONGLONG_T
+sm_strtoll(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register bool neg;
+ register const char *s;
+ register LONGLONG_T acc, cutoff;
+ register int c;
+ register int any, cutlim;
+
+ /*
+ ** Skip white space and pick up leading +/- sign if any.
+ ** If base is 0, allow 0x for hex and 0 for octal, else
+ ** assume decimal; if base is already 16, allow 0x.
+ */
+
+ s = nptr;
+ do
+ {
+ c = (unsigned char) *s++;
+ } while (isascii(c) && isspace(c));
+ if (c == '-')
+ {
+ neg = true;
+ c = *s++;
+ }
+ else
+ {
+ neg = false;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ ** Compute the cutoff value between legal numbers and illegal
+ ** numbers. That is the largest legal value, divided by the
+ ** base. An input number that is greater than this value, if
+ ** followed by a legal input character, is too big. One that
+ ** is equal to this value may be valid or not; the limit
+ ** between valid and invalid numbers is then based on the last
+ ** digit. For instance, if the range for long-long's is
+ ** [-9223372036854775808..9223372036854775807] and the input base
+ ** is 10, cutoff will be set to 922337203685477580 and cutlim to
+ ** either 7 (!neg) or 8 (neg), meaning that if we have
+ ** accumulated a value > 922337203685477580, or equal but the
+ ** next digit is > 7 (or 8), the number is too big, and we will
+ ** return a range error.
+ **
+ ** Set any if any `digits' consumed; make it negative to indicate
+ ** overflow.
+ */
+
+ cutoff = neg ? LLONG_MIN : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ if (neg)
+ {
+ if (cutlim > 0)
+ {
+ cutlim -= base;
+ cutoff += 1;
+ }
+ cutlim = -cutlim;
+ }
+ for (acc = 0, any = 0;; c = (unsigned char) *s++)
+ {
+ if (isascii(c) && isdigit(c))
+ c -= '0';
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (neg)
+ {
+ if (acc < cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = LLONG_MIN;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc -= c;
+ }
+ }
+ else
+ {
+ if (acc > cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = LLONG_MAX;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ }
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return acc;
+}
+
+/*
+** SM_STRTOULL -- Convert a string to an unsigned long long integer.
+**
+** Ignores `locale' stuff. Assumes that the upper and lower case
+** alphabets and digits are each contiguous.
+**
+** Parameters:
+** nptr -- string containing (unsigned) number
+** endptr -- location of first invalid character
+** base -- numeric base that 'nptr' number is based in
+**
+** Returns:
+** Failure: on overflow ULLONG_MAX is returned and errno is set.
+** When 'endptr' == '\0' then the entire string 'nptr'
+** was valid.
+** Success: returns the converted number
+*/
+
+ULONGLONG_T
+sm_strtoull(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s;
+ register ULONGLONG_T acc, cutoff;
+ register int c;
+ register bool neg;
+ register int any, cutlim;
+
+ /* See sm_strtoll for comments as to the logic used. */
+ s = nptr;
+ do
+ {
+ c = (unsigned char) *s++;
+ } while (isascii(c) && isspace(c));
+ neg = (c == '-');
+ if (neg)
+ {
+ c = *s++;
+ }
+ else
+ {
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ cutoff = ULLONG_MAX / (ULONGLONG_T)base;
+ cutlim = ULLONG_MAX % (ULONGLONG_T)base;
+ for (acc = 0, any = 0;; c = (unsigned char) *s++)
+ {
+ if (isascii(c) && isdigit(c))
+ c -= '0';
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (acc > cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= (ULONGLONG_T)base;
+ acc += c;
+ }
+ }
+ if (neg && any > 0)
+ acc = -((LONGLONG_T) acc);
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return acc;
+}
diff --git a/contrib/sendmail/libsm/syslogio.c b/contrib/sendmail/libsm/syslogio.c
new file mode 100644
index 0000000..24fa3a2
--- /dev/null
+++ b/contrib/sendmail/libsm/syslogio.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: syslogio.c,v 1.29 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#ifdef SM_RPOOL
+# include <sm/rpool.h>
+#endif /* SM_RPOOL */
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** Overall:
+** This is a output file type that copies its output to the syslog daemon.
+** Each line of output is written as a separate syslog message.
+** The client is responsible for calling openlog() before writing to
+** any syslog file, and calling closelog() after all syslog output is complete.
+** The only state associated with a syslog file is 'int priority',
+** which we store in fp->f_ival.
+*/
+
+/*
+** SM_SYSLOGOPEN -- open a file pointer to syslog
+**
+** Parameters:
+** fp -- file pointer assigned for the open
+** info -- priority level of the syslog messages
+** flags -- not used
+** rpool -- ignored
+**
+** Returns:
+** 0 (zero) success always (see Overall)
+*/
+
+int
+sm_syslogopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ int *priority = (int *)info;
+
+ fp->f_ival = *priority;
+ return 0;
+}
+
+/*
+** SM_SYSLOGREAD -- read function for syslog
+**
+** This is a "stub" function (placeholder) that always returns an error.
+** It is an error to read syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- buffer to place the data read
+** n -- number of bytes to read
+**
+** Returns:
+** -1 (error) always and sets errno
+*/
+
+ssize_t
+sm_syslogread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ /* an error to read */
+ errno = ENODEV;
+ return -1;
+}
+
+/*
+** SM_SYSLOGWRITE -- write function for syslog
+**
+** Send output to syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- buffer that the write data comes from
+** n -- number of bytes to write
+**
+** Returns:
+** 0 (zero) for success always
+*/
+
+/*
+** XXX TODO: more work needs to be done to ensure that each line of output
+** XXX written to a syslog file is mapped to exactly one syslog message.
+*/
+ssize_t
+sm_syslogwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ syslog(fp->f_ival, "%s", buf);
+ return 0;
+}
+
+/*
+** SM_SYSLOGSEEK -- position the syslog file offset
+**
+** This is a "stub" function (placeholder) that always returns an error.
+** It is an error to seek syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- the new offset position relative to 'whence'
+** whence -- flag indicating start of 'offset'
+**
+** Returns:
+** -1 (error) always.
+*/
+
+off_t
+sm_syslogseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ errno = ENODEV;
+ return -1;
+}
+
+/*
+** SM_SYSLOGCLOSE -- close the syslog file pointer
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Returns:
+** 0 (zero) success always (see Overall)
+**
+*/
+
+int
+sm_syslogclose(fp)
+ SM_FILE_T *fp;
+{
+ return 0;
+}
+
+/*
+** SM_SYSLOGSETINFO -- set information for the file pointer
+**
+** Parameters:
+** fp -- the file pointer being set
+** what -- what information is being set
+** valp -- information content being set to
+**
+** Returns:
+** -1 on failure
+** 0 (zero) on success
+**
+** Side Effects:
+** Sets internal file pointer data
+*/
+
+int
+sm_syslogsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_SL_PRIO:
+ fp->f_ival = *((int *)(valp));
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_SYSLOGGETINFO -- get information relating to the file pointer
+**
+** Parameters:
+** fp -- the file pointer being queried
+** what -- the information type being queried
+** valp -- location to placed queried information
+**
+** Returns:
+** 0 (zero) on success
+** -1 on failure
+**
+** Side Effects:
+** Fills in 'valp' with data.
+*/
+
+int
+sm_sysloggetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_SL_PRIO:
+ *((int *)(valp)) = fp->f_ival;
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
diff --git a/contrib/sendmail/libsm/t-cf.c b/contrib/sendmail/libsm/t-cf.c
new file mode 100644
index 0000000..9078514
--- /dev/null
+++ b/contrib/sendmail/libsm/t-cf.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-cf.c,v 1.7 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sm/cf.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SM_CF_OPT_T opt;
+ int err;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "Usage: %s .cf-file option\n", argv[0]);
+ exit(1);
+ }
+ opt.opt_name = argv[2];
+ opt.opt_val = NULL;
+ err = sm_cf_getopt(argv[1], 1, &opt);
+ if (err)
+ {
+ fprintf(stderr, "%s: %s\n", argv[1], strerror(err));
+ exit(1);
+ }
+ if (opt.opt_val == NULL)
+ printf("Error: option \"%s\" not found\n", opt.opt_name);
+ else
+ printf("%s=%s\n", opt.opt_name, opt.opt_val);
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/t-event.c b/contrib/sendmail/libsm/t-event.c
new file mode 100644
index 0000000..b562da7
--- /dev/null
+++ b/contrib/sendmail/libsm/t-event.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: t-event.c,v 1.7 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+
+#include <sm/clock.h>
+#include <sm/test.h>
+
+int check;
+
+void
+evcheck(arg)
+ int arg;
+{
+ SM_TEST(arg == 3);
+ SM_TEST(check == 0);
+ check++;
+}
+
+void
+ev1(arg)
+ int arg;
+{
+ SM_TEST(arg == 1);
+}
+
+/* define as x if you want debug output */
+#define DBG_OUT(x)
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_EVENT *ev;
+
+ sm_test_begin(argc, argv, "test event handling");
+ fprintf(stdout, "this test may hang. If there is no output within twelve seconds, abort it\nand recompile with -DSM_CONF_SETITIMER=%d\n",
+ SM_CONF_SETITIMER == 0 ? 1 : 0);
+ sleep(1);
+ SM_TEST(1 == 1);
+ DBG_OUT(fprintf(stdout, "We're back, test 1 seems to work.\n"));
+ ev = sm_seteventm(1000, ev1, 1);
+ sleep(1);
+ SM_TEST(2 == 2);
+ DBG_OUT(fprintf(stdout, "We're back, test 2 seems to work.\n"));
+
+ /* schedule an event in 9s */
+ ev = sm_seteventm(9000, ev1, 2);
+ sleep(1);
+
+ /* clear the event before it can fire */
+ sm_clrevent(ev);
+ SM_TEST(3 == 3);
+ DBG_OUT(fprintf(stdout, "We're back, test 3 seems to work.\n"));
+
+ /* schedule an event in 1s */
+ check = 0;
+ ev = sm_seteventm(1000, evcheck, 3);
+ sleep(2);
+
+ /* clear the event */
+ sm_clrevent(ev);
+ SM_TEST(4 == 4);
+ SM_TEST(check == 1);
+ DBG_OUT(fprintf(stdout, "We're back, test 4 seems to work.\n"));
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-exc.c b/contrib/sendmail/libsm/t-exc.c
new file mode 100644
index 0000000..a6922e0
--- /dev/null
+++ b/contrib/sendmail/libsm/t-exc.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-exc.c,v 1.20 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <string.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+const SM_EXC_TYPE_T EtypeTest1 =
+{
+ SmExcTypeMagic,
+ "E:test1",
+ "i",
+ sm_etype_printf,
+ "test1 exception argv[0]=%0",
+};
+
+const SM_EXC_TYPE_T EtypeTest2 =
+{
+ SmExcTypeMagic,
+ "E:test2",
+ "i",
+ sm_etype_printf,
+ "test2 exception argv[0]=%0",
+};
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ void *p;
+ int volatile x;
+ char *unknown, *cant;
+
+ sm_test_begin(argc, argv, "test exception handling");
+
+ /*
+ ** SM_TRY
+ */
+
+ cant = "can't happen";
+ x = 0;
+ SM_TRY
+ x = 1;
+ SM_END_TRY
+ SM_TEST(x == 1);
+
+ /*
+ ** SM_FINALLY-0
+ */
+
+ x = 0;
+ SM_TRY
+ x = 1;
+ SM_FINALLY
+ x = 2;
+ SM_END_TRY
+ SM_TEST(x == 2);
+
+ /*
+ ** SM_FINALLY-1
+ */
+
+ x = 0;
+ SM_TRY
+ SM_TRY
+ x = 1;
+ sm_exc_raisenew_x(&EtypeTest1, 17);
+ SM_FINALLY
+ x = 2;
+ sm_exc_raisenew_x(&EtypeTest2, 42);
+ SM_END_TRY
+ SM_EXCEPT(exc, "E:test2")
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "got exception test2: can't happen\n");
+ SM_EXCEPT(exc, "E:test1")
+ SM_TEST(x == 2 && exc->exc_argv[0].v_int == 17);
+ if (!(x == 2 && exc->exc_argv[0].v_int == 17))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "can't happen: x=%d argv[0]=%d\n",
+ x, exc->exc_argv[0].v_int);
+ }
+ SM_EXCEPT(exc, "*")
+ {
+ unknown = "unknown exception: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_END_TRY
+
+ x = 3;
+ SM_TRY
+ x = 4;
+ sm_exc_raisenew_x(&EtypeTest1, 94);
+ SM_FINALLY
+ x = 5;
+ sm_exc_raisenew_x(&EtypeTest2, 95);
+ SM_EXCEPT(exc, "E:test2")
+ {
+ unknown = "got exception test2: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_EXCEPT(exc, "E:test1")
+ SM_TEST(x == 5 && exc->exc_argv[0].v_int == 94);
+ if (!(x == 5 && exc->exc_argv[0].v_int == 94))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "can't happen: x=%d argv[0]=%d\n",
+ x, exc->exc_argv[0].v_int);
+ }
+ SM_EXCEPT(exc, "*")
+ {
+ unknown = "unknown exception: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_END_TRY
+
+ SM_TRY
+ sm_exc_raisenew_x(&SmEtypeErr, "test %d", 0);
+ SM_EXCEPT(exc, "*")
+#if DEBUG
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "test 0 got an exception, as expected:\n");
+ sm_exc_print(exc, smioout);
+#endif /* DEBUG */
+ return sm_test_end();
+ SM_END_TRY
+
+ p = sm_malloc_x((size_t)(-1));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "sm_malloc_x unexpectedly succeeded, returning %p\n", p);
+ unknown = "sm_malloc_x unexpectedly succeeded";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-float.c b/contrib/sendmail/libsm/t-float.c
new file mode 100644
index 0000000..f3f059b
--- /dev/null
+++ b/contrib/sendmail/libsm/t-float.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-float.c,v 1.18 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ double d, d2;
+ double ld;
+ char buf[128];
+ char *r;
+
+ /*
+ ** Sendmail uses printf and scanf with doubles,
+ ** so make sure that this works.
+ */
+
+ sm_test_begin(argc, argv, "test floating point stuff");
+
+ d = 1.125;
+ sm_snprintf(buf, sizeof(buf), "%d %.3f %d", 0, d, 1);
+ r = "0 1.125 1";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ d = 1.125;
+ sm_snprintf(buf, sizeof(buf), "%.3f", d);
+ r = "1.125";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+ d2 = 0.0;
+ sm_io_sscanf(buf, "%lf", &d2);
+#if SM_CONF_BROKEN_STRTOD
+ if (d != d2)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "wanted %f, got %f\n", d, d2);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "error ignored since SM_CONF_BROKEN_STRTOD is set for this OS\n");
+ }
+#else /* SM_CONF_BROKEN_STRTOD */
+ if (!SM_TEST(d == d2))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "wanted %f, got %f\n", d, d2);
+#endif /* SM_CONF_BROKEN_STRTOD */
+
+ ld = 2.5;
+ sm_snprintf(buf, sizeof(buf), "%.3f %.1f", d, ld);
+ r = "1.125 2.5";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-fopen.c b/contrib/sendmail/libsm/t-fopen.c
new file mode 100644
index 0000000..4fbbc29
--- /dev/null
+++ b/contrib/sendmail/libsm/t-fopen.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-fopen.c,v 1.8 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+/* ARGSUSED0 */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_FILE_T *out;
+
+ sm_test_begin(argc, argv, "test sm_io_fopen");
+ out = sm_io_fopen("foo", O_WRONLY|O_APPEND|O_CREAT, 0666);
+ SM_TEST(out != NULL);
+ if (out != NULL)
+ {
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "foo\n");
+ sm_io_close(out, SM_TIME_DEFAULT);
+ }
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-heap.c b/contrib/sendmail/libsm/t-heap.c
new file mode 100644
index 0000000..7ddb60d
--- /dev/null
+++ b/contrib/sendmail/libsm/t-heap.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-heap.c,v 1.10 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/debug.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/test.h>
+#include <sm/xtrap.h>
+
+#if SM_HEAP_CHECK
+extern SM_DEBUG_T SmHeapCheck;
+# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
+#else /* SM_HEAP_CHECK */
+# define HEAP_CHECK 0
+#endif /* SM_HEAP_CHECK */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ void *p;
+
+ sm_test_begin(argc, argv, "test heap handling");
+ if (argc > 1)
+ sm_debug_addsettings_x(argv[1]);
+
+ p = sm_malloc(10);
+ SM_TEST(p != NULL);
+ p = sm_realloc_x(p, 20);
+ SM_TEST(p != NULL);
+ p = sm_realloc(p, 30);
+ SM_TEST(p != NULL);
+ if (HEAP_CHECK)
+ {
+ sm_dprintf("heap with 1 30-byte block allocated:\n");
+ sm_heap_report(smioout, 3);
+ }
+
+ if (HEAP_CHECK)
+ {
+ sm_free(p);
+ sm_dprintf("heap with 0 blocks allocated:\n");
+ sm_heap_report(smioout, 3);
+ sm_dprintf("xtrap count = %d\n", SmXtrapCount);
+ }
+
+#if DEBUG
+ /* this will cause a core dump */
+ sm_dprintf("about to free %p for the second time\n", p);
+ sm_free(p);
+#endif /* DEBUG */
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-match.c b/contrib/sendmail/libsm/t-match.c
new file mode 100644
index 0000000..d2776c0
--- /dev/null
+++ b/contrib/sendmail/libsm/t-match.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-match.c,v 1.9 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/string.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+#define try(str, pat, want) \
+ got = sm_match(str, pat); \
+ if (!SM_TEST(got == want)) \
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
+ "sm_match(\"%s\", \"%s\") returns %s\n", \
+ str, pat, got ? "true" : "false");
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ bool got;
+
+ sm_test_begin(argc, argv, "test sm_match");
+
+ try("foo", "foo", true);
+ try("foo", "bar", false);
+ try("foo[bar", "foo[bar", true);
+ try("foo[bar]", "foo[bar]", false);
+ try("foob", "foo[bar]", true);
+ try("a-b", "a[]-]b", true);
+ try("abcde", "a*e", true);
+ try("[", "[[]", true);
+ try("c", "[a-z]", true);
+ try("C", "[a-z]", false);
+ try("F:sm.heap", "[!F]*", false);
+ try("E:sm.err", "[!F]*", true);
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-path.c b/contrib/sendmail/libsm/t-path.c
new file mode 100644
index 0000000..fa6e345
--- /dev/null
+++ b/contrib/sendmail/libsm/t-path.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-path.c,v 1.8 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <string.h>
+#include <sm/path.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *r;
+
+ sm_test_begin(argc, argv, "test path handling");
+
+ SM_TEST(sm_path_isdevnull(SM_PATH_DEVNULL));
+ r = "/dev/null";
+ SM_TEST(sm_path_isdevnull(r));
+ r = "/nev/dull";
+ SM_TEST(!sm_path_isdevnull(r));
+ r = "nul";
+ SM_TEST(!sm_path_isdevnull(r));
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-rpool.c b/contrib/sendmail/libsm/t-rpool.c
new file mode 100644
index 0000000..b671a4b
--- /dev/null
+++ b/contrib/sendmail/libsm/t-rpool.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-rpool.c,v 1.18 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/debug.h>
+#include <sm/heap.h>
+#include <sm/rpool.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+static void
+rfree __P((
+ void *cx));
+
+static void
+rfree(cx)
+ void *cx;
+{
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "rfree freeing `%s'\n",
+ (char *) cx);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_RPOOL_T *rpool;
+ char *a[26];
+ int i, j;
+ SM_RPOOL_ATTACH_T att;
+
+ sm_test_begin(argc, argv, "test rpool");
+ sm_debug_addsetting_x("sm_check_heap", 1);
+ rpool = sm_rpool_new_x(NULL);
+ SM_TEST(rpool != NULL);
+ att = sm_rpool_attach_x(rpool, rfree, "attachment #1");
+ SM_TEST(att != NULL);
+ for (i = 0; i < 26; ++i)
+ {
+ size_t sz = i * i * i;
+
+ a[i] = sm_rpool_malloc_x(rpool, sz);
+ for (j = 0; j < sz; ++j)
+ a[i][j] = 'a' + i;
+ }
+ att = sm_rpool_attach_x(rpool, rfree, "attachment #2");
+ (void) sm_rpool_attach_x(rpool, rfree, "attachment #3");
+ sm_rpool_detach(att);
+
+ /* XXX more tests? */
+#if DEBUG
+ sm_dprintf("heap after filling up rpool:\n");
+ sm_heap_report(smioout, 3);
+ sm_dprintf("freeing rpool:\n");
+ sm_rpool_free(rpool);
+ sm_dprintf("heap after freeing rpool:\n");
+ sm_heap_report(smioout, 3);
+#endif /* DEBUG */
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-scanf.c b/contrib/sendmail/libsm/t-scanf.c
new file mode 100644
index 0000000..b3ca0bd
--- /dev/null
+++ b/contrib/sendmail/libsm/t-scanf.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-scanf.c,v 1.5 2001/11/13 00:51:28 ca Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i, d, h;
+ char buf[128];
+ char *r;
+
+ sm_test_begin(argc, argv, "test scanf point stuff");
+#if !SM_CONF_BROKEN_SIZE_T
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+"If tests for \"h == 2\" fail, check whether size_t is signed on your OS.\n\
+If that is the case, add -DSM_CONF_BROKEN_SIZE_T to confENVDEF\n\
+and start over. Otherwise contact sendmail.org.\n");
+#endif /* !SM_CONF_BROKEN_SIZE_T */
+
+ d = 2;
+ sm_snprintf(buf, sizeof(buf), "%d", d);
+ r = "2";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ i = sm_io_sscanf(buf, "%d", &h);
+ SM_TEST(i == 1);
+ SM_TEST(h == 2);
+
+ d = 2;
+ sm_snprintf(buf, sizeof(buf), "%d\n", d);
+ r = "2\n";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ i = sm_io_sscanf(buf, "%d", &h);
+ SM_TEST(i == 1);
+ SM_TEST(h == 2);
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-shm.c b/contrib/sendmail/libsm/t-shm.c
new file mode 100644
index 0000000..a739ad1
--- /dev/null
+++ b/contrib/sendmail/libsm/t-shm.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: t-shm.c,v 1.17 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <stdio.h>
+
+#if SM_CONF_SHM
+# include <stdlib.h>
+# include <unistd.h>
+# include <sys/wait.h>
+
+# include <sm/heap.h>
+# include <sm/string.h>
+# include <sm/test.h>
+# include <sm/shm.h>
+
+# define SHMSIZE 1024
+# define SHM_MAX 6400000
+# define T_SHMKEY 21
+
+
+/*
+** SHMINTER -- interactive testing of shared memory
+**
+** Parameters:
+** owner -- create segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+int shminter __P((bool));
+
+int
+shminter(owner)
+ bool owner;
+{
+ int *shm, shmid;
+ int i, j, t;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ while ((t = getchar()) != EOF)
+ {
+ switch (t)
+ {
+ case 'c':
+ *shm = 0;
+ break;
+ case 'i':
+ ++*shm;
+ break;
+ case 'd':
+ --*shm;
+ break;
+ case 's':
+ sleep(1);
+ break;
+ case 'l':
+ t = *shm;
+ for (i = 0; i < SHM_MAX; i++)
+ {
+ j += i;
+ ++*shm;
+ }
+ if (*shm != SHM_MAX + t)
+ fprintf(stderr, "error: %d != %d\n",
+ *shm, SHM_MAX + t);
+ break;
+ case 'v':
+ printf("shmval: %d\n", *shm);
+ break;
+ }
+ }
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+
+/*
+** SHMBIG -- testing of shared memory
+**
+** Parameters:
+** owner -- create segment.
+** size -- size of segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+int shmbig __P((bool, int));
+
+int
+shmbig(owner, size)
+ bool owner;
+ int size;
+{
+ int *shm, shmid;
+ int i;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, size, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ for (i = 0; i < size / sizeof(int); i++)
+ shm[i] = i;
+ for (i = 0; i < size / sizeof(int); i++)
+ {
+ if (shm[i] != i)
+ {
+ fprintf(stderr, "failed at %d: %d", i, shm[i]);
+ }
+ }
+
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+
+/*
+** SHMTEST -- test of shared memory
+**
+** Parameters:
+** owner -- create segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+# define MAX_CNT 10
+
+int
+shmtest(owner)
+ int owner;
+{
+ int *shm, shmid;
+ int cnt = 0;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ if (owner)
+ {
+ int r;
+
+ *shm = 1;
+ while (*shm == 1 && cnt++ < MAX_CNT)
+ sleep(1);
+ SM_TEST(cnt <= MAX_CNT);
+
+ /* release and re-acquire the segment */
+ r = sm_shmstop((void *) shm, shmid, owner);
+ SM_TEST(r == 0);
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ SM_TEST(shm != (int *) 0);
+ }
+ else
+ {
+ while (*shm != 1 && cnt++ < MAX_CNT)
+ sleep(1);
+ SM_TEST(cnt <= MAX_CNT);
+ *shm = 2;
+
+ /* wait a momemt so the segment is still in use */
+ sleep(2);
+ }
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ bool interactive = false;
+ bool owner = false;
+ int big = -1;
+ int ch;
+ int r = 0;
+ int status;
+ extern char *optarg;
+
+# define OPTIONS "b:io"
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) ch)
+ {
+ case 'b':
+ big = atoi(optarg);
+ break;
+
+ case 'i':
+ interactive = true;
+ break;
+
+ case 'o':
+ owner = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (interactive)
+ r = shminter(owner);
+ else if (big > 0)
+ r = shmbig(true, big);
+ else
+ {
+ pid_t pid;
+
+ if ((pid = fork()) < 0)
+ {
+ perror("fork failed\n");
+ return -1;
+ }
+
+ sm_test_begin(argc, argv, "test shared memory");
+ if (pid == 0)
+ {
+ /* give the parent the chance to setup data */
+ sleep(1);
+ r = shmtest(false);
+ }
+ else
+ {
+ r = shmtest(true);
+ (void) wait(&status);
+ }
+ SM_TEST(r == 0);
+ return sm_test_end();
+ }
+ return r;
+}
+#else /* SM_CONF_SHM */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ printf("No support for shared memory configured on this machine\n");
+ return 0;
+}
+#endif /* SM_CONF_SHM */
diff --git a/contrib/sendmail/libsm/t-smstdio.c b/contrib/sendmail/libsm/t-smstdio.c
new file mode 100644
index 0000000..3bad1c1
--- /dev/null
+++ b/contrib/sendmail/libsm/t-smstdio.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-smstdio.c,v 1.11 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *stream;
+ SM_FILE_T *fp;
+ char buf[128];
+ size_t n;
+ static char testmsg[] = "hello, world\n";
+
+ sm_test_begin(argc, argv,
+ "test sm_io_stdioopen, smiostdin, smiostdout");
+
+ stream = fopen("t-smstdio.1", "w");
+ SM_TEST(stream != NULL);
+
+ fp = sm_io_stdioopen(stream, "w");
+ SM_TEST(fp != NULL);
+
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", testmsg);
+ sm_io_close(fp, SM_TIME_DEFAULT);
+
+#if 0
+ /*
+ ** stream should now be closed. This is a tricky way to test
+ ** if it is still open. Alas, it core dumps on Linux.
+ */
+
+ fprintf(stream, "oops! stream is still open!\n");
+ fclose(stream);
+#endif
+
+ stream = fopen("t-smstdio.1", "r");
+ SM_TEST(stream != NULL);
+
+ fp = sm_io_stdioopen(stream, "r");
+ SM_TEST(fp != NULL);
+
+ n = sm_io_read(fp, SM_TIME_DEFAULT, buf, sizeof(buf));
+ if (SM_TEST(n == strlen(testmsg)))
+ {
+ buf[n] = '\0';
+ SM_TEST(strcmp(buf, testmsg) == 0);
+ }
+
+#if 0
+
+ /*
+ ** Copy smiostdin to smiostdout
+ ** gotta think some more about how to test smiostdin and smiostdout
+ */
+
+ while ((c = sm_io_getc(smiostdin)) != SM_IO_EOF)
+ sm_io_putc(smiostdout, c);
+#endif
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-string.c b/contrib/sendmail/libsm/t-string.c
new file mode 100644
index 0000000..0506e7a
--- /dev/null
+++ b/contrib/sendmail/libsm/t-string.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-string.c,v 1.11 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *s;
+ char buf[4096];
+ char foo[4];
+ char *r;
+ int n;
+
+ sm_test_begin(argc, argv, "test string utilities");
+
+ s = sm_stringf_x("%.3s%03d", "foobar", 42);
+ r = "foo042";
+ SM_TEST(strcmp(s, r) == 0);
+
+ s = sm_stringf_x("+%*x+", 2000, 0xCAFE);
+ sm_snprintf(buf, 4096, "+%*x+", 2000, 0xCAFE);
+ SM_TEST(strcmp(s, buf) == 0);
+
+ foo[3] = 1;
+ n = sm_snprintf(foo, sizeof(foo), "foobar%dbaz", 42);
+ SM_TEST(n == 11);
+ r = "foo";
+ SM_TEST(strcmp(foo, r) == 0);
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-strio.c b/contrib/sendmail/libsm/t-strio.c
new file mode 100644
index 0000000..bb18dae
--- /dev/null
+++ b/contrib/sendmail/libsm/t-strio.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-strio.c,v 1.11 2001/09/11 04:04:49 gshapiro Exp $")
+#include <sm/string.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char buf[20];
+ char *r;
+ SM_FILE_T f;
+
+ sm_test_begin(argc, argv, "test strio");
+ (void) memset(buf, '.', 20);
+ sm_strio_init(&f, buf, 10);
+ (void) sm_io_fprintf(&f, SM_TIME_DEFAULT, "foobarbazoom");
+ sm_io_flush(&f, SM_TIME_DEFAULT);
+ r = "foobarbaz";
+ SM_TEST(strcmp(buf, r) == 0);
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-strl.c b/contrib/sendmail/libsm/t-strl.c
new file mode 100644
index 0000000..5c118dc
--- /dev/null
+++ b/contrib/sendmail/libsm/t-strl.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-strl.c,v 1.15 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+#define MAXL 16
+#define N 5
+#define SIZE 128
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *s1, *s2, *s3;
+ int one, two, k;
+ char src1[N][SIZE], dst1[SIZE], dst2[SIZE];
+ char *r;
+
+ sm_test_begin(argc, argv, "test strl* string functions");
+ s1 = "abc";
+ s2 = "123";
+ s3 = sm_malloc_x(MAXL);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ SM_TEST(strcmp(s1, s3) == 0);
+
+ SM_TEST(sm_strlcat(s3, s2, 8) == 6);
+ r ="abc123";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 2) == 3);
+ r = "a";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcat(s3, s2, 3) == 4);
+ r = "a1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, MAXL) == 7);
+ r = "abc:123";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 6) == 7);
+ r = "abc:1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 2) == 7);
+ r = "abc";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 4) == 7);
+ r = "abc";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 5) == 7);
+ r = "abc:";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 6) == 7);
+ r = "abc:1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ for (k = 0; k < N; k++)
+ {
+ (void) sm_strlcpy(src1[k], "abcdef", sizeof src1);
+ }
+
+ one = sm_strlcpyn(dst1, sizeof dst1, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, sizeof dst2, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 10, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 10, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 5, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 5, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 0, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 0, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, sizeof dst1, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, sizeof dst2, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 15, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, 15, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 20, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, 20, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+
+ one = sm_strlcpyn(dst1, sizeof dst1, 0);
+ SM_TEST(one == 0);
+ r = "";
+ SM_TEST(strcmp(dst1, r) == 0);
+ one = sm_strlcpyn(dst1, 20, 1, src1[0]);
+ two = sm_snprintf(dst2, 20, "%s", src1[0]);
+ SM_TEST(one == two);
+ one = sm_strlcpyn(dst1, 2, 1, src1[0]);
+ two = sm_snprintf(dst2, 2, "%s", src1[0]);
+ SM_TEST(one == two);
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-strrevcmp.c b/contrib/sendmail/libsm/t-strrevcmp.c
new file mode 100644
index 0000000..fb8fb46
--- /dev/null
+++ b/contrib/sendmail/libsm/t-strrevcmp.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-strrevcmp.c,v 1.3 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *s1;
+ char *s2;
+
+ sm_test_begin(argc, argv, "test string compare");
+
+ s1 = "equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) == 0);
+
+ s1 = "equal";
+ s2 = "qual";
+ SM_TEST(sm_strrevcmp(s1, s2) > 0);
+
+ s1 = "qual";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) < 0);
+
+ s1 = "Equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) < 0);
+
+ s1 = "Equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcasecmp(s1, s2) == 0);
+
+ s1 = "Equal";
+ s2 = "eQuaL";
+ SM_TEST(sm_strrevcasecmp(s1, s2) == 0);
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/t-types.c b/contrib/sendmail/libsm/t-types.c
new file mode 100644
index 0000000..b1adb0c
--- /dev/null
+++ b/contrib/sendmail/libsm/t-types.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: t-types.c,v 1.16 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ LONGLONG_T ll;
+ LONGLONG_T volatile lt;
+ ULONGLONG_T ull;
+ char buf[128];
+ char *r;
+
+ sm_test_begin(argc, argv, "test standard integral types");
+
+ SM_TEST(sizeof(LONGLONG_T) == sizeof(ULONGLONG_T));
+
+ /*
+ ** sendmail assumes that ino_t, off_t and void* can be cast
+ ** to ULONGLONG_T without losing information.
+ */
+
+ if (!SM_TEST(sizeof(ino_t) <= sizeof(ULONGLONG_T)) ||
+ !SM_TEST(sizeof(off_t) <= sizeof(ULONGLONG_T)) ||
+ !SM_TEST(sizeof(void*) <= sizeof(ULONGLONG_T)))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\
+Your C compiler appears to support a 64 bit integral type,\n\
+but libsm is not configured to use it. You will need to set\n\
+either SM_CONF_LONGLONG or SM_CONF_QUAD_T to 1. See libsm/README\n\
+for more details.\n");
+ }
+
+ /*
+ ** Most compilers notice that LLONG_MIN - 1 generate an underflow.
+ ** Some compiler generate code that will use the 'X' status bit
+ ** in a CPU and hence (LLONG_MIN - 1 > LLONG_MIN) will be false.
+ ** So we have to decide whether we want compiler warnings or
+ ** a wrong test...
+ ** Question: where do we really need what this test tests?
+ */
+
+#if SM_CONF_TEST_LLONG
+ ll = LLONG_MIN;
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\
+Your C compiler maybe issued a warning during compilation,\n\
+please IGNORE the compiler warning!.\n");
+ lt = LLONG_MIN - 1;
+ SM_TEST(lt > ll);
+ sm_snprintf(buf, sizeof(buf), "%llx", ll);
+ r = "0";
+ if (!SM_TEST(buf[0] == '8')
+ || !SM_TEST(strspn(&buf[1], r) == sizeof(ll) * 2 - 1))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "oops: LLONG_MIN=%s\n", buf);
+ }
+
+ ll = LLONG_MAX;
+ lt = ll + 1;
+ SM_TEST(lt < ll);
+ sm_snprintf(buf, sizeof(buf), "%llx", ll);
+ r = "f";
+ if (!SM_TEST(buf[0] == '7')
+ || !SM_TEST(strspn(&buf[1], r) == sizeof(ll) * 2 - 1))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "oops: LLONG_MAX=%s\n", buf);
+ }
+#endif /* SM_CONF_TEST_LLONG */
+
+ ull = ULLONG_MAX;
+ SM_TEST(ull + 1 == 0);
+ sm_snprintf(buf, sizeof(buf), "%llx", ull);
+ r = "f";
+ SM_TEST(strspn(buf, r) == sizeof(ll) * 2);
+
+ /*
+ ** If QUAD_MAX is defined by <limits.h> then quad_t is defined.
+ ** Make sure LONGLONG_T is at least as big as quad_t.
+ */
+#ifdef QUAD_MAX
+ SM_TEST(QUAD_MAX <= LLONG_MAX);
+#endif
+
+ return sm_test_end();
+}
diff --git a/contrib/sendmail/libsm/test.c b/contrib/sendmail/libsm/test.c
new file mode 100644
index 0000000..361cc45
--- /dev/null
+++ b/contrib/sendmail/libsm/test.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(Id, "@(#)$Id: test.c,v 1.16 2002/01/08 17:54:40 ca Exp $")
+
+/*
+** Abstractions for writing libsm test programs.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sm/debug.h>
+#include <sm/test.h>
+
+extern char *optarg;
+extern int optind;
+extern int optopt;
+extern int opterr;
+
+int SmTestIndex;
+int SmTestNumErrors;
+bool SmTestVerbose;
+
+static char Help[] = "\
+%s [-h] [-d debugging] [-v]\n\
+\n\
+%s\n\
+\n\
+-h Display this help information.\n\
+-d debugging Set debug activation levels.\n\
+-v Verbose output.\n\
+";
+
+static char Usage[] = "\
+Usage: %s [-h] [-v]\n\
+Use %s -h for help.\n\
+";
+
+/*
+** SM_TEST_BEGIN -- initialize test system.
+**
+** Parameters:
+** argc -- argument counter.
+** argv -- argument vector.
+** testname -- description of tests.
+**
+** Results:
+** none.
+*/
+
+void
+sm_test_begin(argc, argv, testname)
+ int argc;
+ char **argv;
+ char *testname;
+{
+ int c;
+
+ SmTestIndex = 0;
+ SmTestNumErrors = 0;
+ SmTestVerbose = false;
+ opterr = 0;
+
+ while ((c = getopt(argc, argv, "vhd:")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ SmTestVerbose = true;
+ break;
+ case 'd':
+ sm_debug_addsettings_x(optarg);
+ break;
+ case 'h':
+ (void) fprintf(stdout, Help, argv[0], testname);
+ exit(0);
+ default:
+ (void) fprintf(stderr,
+ "Unknown command line option -%c\n",
+ optopt);
+ (void) fprintf(stderr, Usage, argv[0], argv[0]);
+ exit(1);
+ }
+ }
+}
+
+/*
+** SM_TEST -- single test.
+**
+** Parameters:
+** success -- did test succeeed?
+** expr -- expression that has been evaluated.
+** filename -- guess...
+** lineno -- line number.
+**
+** Results:
+** value of success.
+*/
+
+bool
+sm_test(success, expr, filename, lineno)
+ bool success;
+ char *expr;
+ char *filename;
+ int lineno;
+{
+ ++SmTestIndex;
+ if (SmTestVerbose)
+ (void) fprintf(stderr, "%d..", SmTestIndex);
+ if (!success)
+ {
+ ++SmTestNumErrors;
+ if (!SmTestVerbose)
+ (void) fprintf(stderr, "%d..", SmTestIndex);
+ (void) fprintf(stderr, "bad! %s:%d %s\n", filename, lineno,
+ expr);
+ }
+ else
+ {
+ if (SmTestVerbose)
+ (void) fprintf(stderr, "ok\n");
+ }
+ return success;
+}
+
+/*
+** SM_TEST_END -- end of test system.
+**
+** Parameters:
+** none.
+**
+** Results:
+** number of errors.
+*/
+
+int
+sm_test_end()
+{
+ (void) fprintf(stderr, "%d of %d tests completed successfully\n",
+ SmTestIndex - SmTestNumErrors, SmTestIndex);
+ if (SmTestNumErrors != 0)
+ (void) fprintf(stderr, "*** %d error%s in test! ***\n",
+ SmTestNumErrors,
+ SmTestNumErrors > 1 ? "s" : "");
+
+ return SmTestNumErrors;
+}
diff --git a/contrib/sendmail/libsm/ungetc.c b/contrib/sendmail/libsm/ungetc.c
new file mode 100644
index 0000000..7794af0
--- /dev/null
+++ b/contrib/sendmail/libsm/ungetc.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.28 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_SUBMORE_X -- expand ungetc buffer
+**
+** Expand the ungetc buffer `in place'. That is, adjust fp->f_p when
+** the buffer moves, so that it points the same distance from the end,
+** and move the bytes in the buffer around as necessary so that they
+** are all at the end (stack-style).
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Results:
+** none.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+static void
+sm_submore_x(fp)
+ register SM_FILE_T *fp;
+{
+ register int i;
+ register unsigned char *p;
+
+ if (fp->f_ub.smb_base == fp->f_ubuf)
+ {
+ /* Get a buffer; f_ubuf is fixed size. */
+ p = sm_malloc_x((size_t) SM_IO_BUFSIZ);
+ fp->f_ub.smb_base = p;
+ fp->f_ub.smb_size = SM_IO_BUFSIZ;
+ p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf);
+ for (i = sizeof(fp->f_ubuf); --i >= 0;)
+ p[i] = fp->f_ubuf[i];
+ fp->f_p = p;
+ return;
+ }
+ i = fp->f_ub.smb_size;
+ p = sm_realloc_x(fp->f_ub.smb_base, i << 1);
+
+ /* no overlap (hence can use memcpy) because we doubled the size */
+ (void) memcpy((void *) (p + i), (void *) p, (size_t) i);
+ fp->f_p = p + i;
+ fp->f_ub.smb_base = p;
+ fp->f_ub.smb_size = i << 1;
+}
+
+/*
+** SM_IO_UNGETC -- place a character back into the buffer just read
+**
+** Parameters:
+** fp -- the file pointer affected
+** timeout -- time to complete ungetc
+** c -- the character to place back
+**
+** Results:
+** On success, returns value of character placed back, 0-255.
+** Returns SM_IO_EOF if c == SM_IO_EOF or if last operation
+** was a write and flush failed.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+int
+sm_io_ungetc(fp, timeout, c)
+ register SM_FILE_T *fp;
+ int timeout;
+ int c;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (c == SM_IO_EOF)
+ return SM_IO_EOF;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Ungetting the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+ if ((fp->f_flags & SMRD) == 0)
+ {
+ /*
+ ** Not already reading: no good unless reading-and-writing.
+ ** Otherwise, flush any current write stuff.
+ */
+
+ if ((fp->f_flags & SMRW) == 0)
+ return SM_IO_EOF;
+ if (fp->f_flags & SMWR)
+ {
+ if (sm_flush(fp, &timeout))
+ return SM_IO_EOF;
+ fp->f_flags &= ~SMWR;
+ fp->f_w = 0;
+ fp->f_lbfsize = 0;
+ }
+ fp->f_flags |= SMRD;
+ }
+ c = (unsigned char) c;
+
+ /*
+ ** If we are in the middle of ungetc'ing, just continue.
+ ** This may require expanding the current ungetc buffer.
+ */
+
+ if (HASUB(fp))
+ {
+ if (fp->f_r >= fp->f_ub.smb_size)
+ sm_submore_x(fp);
+ *--fp->f_p = c;
+ fp->f_r++;
+ return c;
+ }
+ fp->f_flags &= ~SMFEOF;
+
+ /*
+ ** If we can handle this by simply backing up, do so,
+ ** but never replace the original character.
+ ** (This makes sscanf() work when scanning `const' data.)
+ */
+
+ if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base &&
+ fp->f_p[-1] == c)
+ {
+ fp->f_p--;
+ fp->f_r++;
+ return c;
+ }
+
+ /*
+ ** Create an ungetc buffer.
+ ** Initially, we will use the `reserve' buffer.
+ */
+
+ fp->f_ur = fp->f_r;
+ fp->f_up = fp->f_p;
+ fp->f_ub.smb_base = fp->f_ubuf;
+ fp->f_ub.smb_size = sizeof(fp->f_ubuf);
+ fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c;
+ fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1];
+ fp->f_r = 1;
+
+ return c;
+}
diff --git a/contrib/sendmail/libsm/vasprintf.c b/contrib/sendmail/libsm/vasprintf.c
new file mode 100644
index 0000000..9b3a12e
--- /dev/null
+++ b/contrib/sendmail/libsm/vasprintf.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: vasprintf.c,v 1.26 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include "local.h"
+
+/*
+** SM_VASPRINTF -- printf to a dynamically allocated string
+**
+** Write 'printf' output to a dynamically allocated string
+** buffer which is returned to the caller.
+**
+** Parameters:
+** str -- *str receives a pointer to the allocated string
+** fmt -- format directives for printing
+** ap -- variable argument list
+**
+** Results:
+** On failure, set *str to NULL, set errno, and return -1.
+**
+** On success, set *str to a pointer to a nul-terminated
+** string buffer containing printf output, and return the
+** length of the string (not counting the nul).
+*/
+
+#define SM_VA_BUFSIZE 128
+
+int
+sm_vasprintf(str, fmt, ap)
+ char **str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+ unsigned char *base;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR | SMALC;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)sm_malloc(SM_VA_BUFSIZE);
+ if (fake.f_bf.smb_base == NULL)
+ goto err2;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vasprintf:fake";
+ fake.f_bf.smb_size = fake.f_w = SM_VA_BUFSIZE - 1;
+ fake.f_timeout = SM_TIME_FOREVER;
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (ret == -1)
+ goto err;
+ *fake.f_p = '\0';
+
+ /* use no more space than necessary */
+ base = (unsigned char *) sm_realloc(fake.f_bf.smb_base, ret + 1);
+ if (base == NULL)
+ goto err;
+ *str = (char *)base;
+ return ret;
+
+err:
+ if (fake.f_bf.smb_base != NULL)
+ {
+ sm_free(fake.f_bf.smb_base);
+ fake.f_bf.smb_base = NULL;
+ }
+err2:
+ *str = NULL;
+ errno = ENOMEM;
+ return -1;
+}
diff --git a/contrib/sendmail/libsm/vfprintf.c b/contrib/sendmail/libsm/vfprintf.c
new file mode 100644
index 0000000..e2115bd
--- /dev/null
+++ b/contrib/sendmail/libsm/vfprintf.c
@@ -0,0 +1,1107 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: vfprintf.c,v 1.52 2001/09/11 04:04:49 gshapiro Exp $")
+
+/*
+** Overall:
+** Actual printing innards.
+** This code is large and complicated...
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sm/config.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "fvwrite.h"
+
+static void sm_find_arguments __P((const char *, va_list , va_list **));
+static void sm_grow_type_table_x __P((unsigned char **, int *));
+static int sm_print __P((SM_FILE_T *, int, struct sm_uio *));
+
+/*
+** SM_PRINT -- print/flush to the file
+**
+** Flush out all the vectors defined by the given uio,
+** then reset it so that it can be reused.
+**
+** Parameters:
+** fp -- file pointer
+** timeout -- time to complete operation (milliseconds)
+** uio -- vector list of memory locations of data for printing
+**
+** Results:
+** Success: 0 (zero)
+** Failure:
+*/
+
+static int
+sm_print(fp, timeout, uio)
+ SM_FILE_T *fp;
+ int timeout;
+ register struct sm_uio *uio;
+{
+ register int err;
+
+ if (uio->uio_resid == 0)
+ {
+ uio->uio_iovcnt = 0;
+ return 0;
+ }
+ err = sm_fvwrite(fp, timeout, uio);
+ uio->uio_resid = 0;
+ uio->uio_iovcnt = 0;
+ return err;
+}
+
+/*
+** SM_BPRINTF -- allow formating to an unbuffered file.
+**
+** Helper function for `fprintf to unbuffered unix file': creates a
+** temporary buffer (via a "fake" file pointer).
+** We only work on write-only files; this avoids
+** worries about ungetc buffers and so forth.
+**
+** Parameters:
+** fp -- the file to send the o/p to
+** fmt -- format instructions for the o/p
+** ap -- vectors of data units used for formating
+**
+** Results:
+** Failure: SM_IO_EOF and errno set
+** Success: number of data units used in the formating
+**
+** Side effects:
+** formatted o/p can be SM_IO_BUFSIZ length maximum
+*/
+
+static int
+sm_bprintf(fp, fmt, ap)
+ register SM_FILE_T *fp;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+ unsigned char buf[SM_IO_BUFSIZ];
+ extern const char SmFileMagic[];
+
+ /* copy the important variables */
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_flags = fp->f_flags & ~SMNBF;
+ fake.f_file = fp->f_file;
+ fake.f_cookie = fp->f_cookie;
+ fake.f_write = fp->f_write;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_bprintf:fake";
+
+ /* set up the buffer */
+ fake.f_bf.smb_base = fake.f_p = buf;
+ fake.f_bf.smb_size = fake.f_w = sizeof(buf);
+ fake.f_lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER))
+ ret = SM_IO_EOF; /* errno set by sm_io_flush */
+ if (fake.f_flags & SMERR)
+ fp->f_flags |= SMERR;
+ return ret;
+}
+
+
+#define BUF 40
+
+#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
+
+
+/* Macros for converting digits to letters and vice versa */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned) to_digit(c) <= 9)
+#define to_char(n) ((char) (n) + '0')
+
+/* Flags used during conversion. */
+#define ALT 0x001 /* alternate form */
+#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGINT 0x010 /* long integer */
+#define QUADINT 0x020 /* quad integer */
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+
+/*
+** SM_IO_VPRINTF -- performs actual formating for o/p
+**
+** Parameters:
+** fp -- file pointer for o/p
+** timeout -- time to complete the print
+** fmt0 -- formating directives
+** ap -- vectors with data units for formating
+**
+** Results:
+** Success: number of data units used for formatting
+** Failure: SM_IO_EOF and sets errno
+*/
+
+int
+sm_io_vfprintf(fp, timeout, fmt0, ap)
+ SM_FILE_T *fp;
+ int timeout;
+ const char *fmt0;
+ SM_VA_LOCAL_DECL
+{
+ register char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n, m, n2; /* handy integers (short term usage) */
+ register char *cp; /* handy char pointer (short term usage) */
+ register struct sm_iov *iovp;/* for PRINT macro */
+ register int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format (%.3d), or -1 */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+ wchar_t wc;
+ ULONGLONG_T _uquad; /* integer arguments %[diouxX] */
+ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec */
+ int size; /* size of converted field or string */
+ char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */
+#define NIOV 8
+ struct sm_uio uio; /* output information: summary */
+ struct sm_iov iov[NIOV];/* ... and individual io vectors */
+ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
+ char ox[2]; /* space for 0x hex-prefix */
+ va_list *argtable; /* args, built due to positional arg */
+ va_list statargtable[STATIC_ARG_TBL_SIZE];
+ int nextarg; /* 1-based argument index */
+ va_list orgap; /* original argument pointer */
+
+ /*
+ ** Choose PADSIZE to trade efficiency vs. size. If larger printf
+ ** fields occur frequently, increase PADSIZE and make the initialisers
+ ** below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+ static char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ /*
+ ** BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) do { \
+ iovp->iov_base = (ptr); \
+ iovp->iov_len = (len); \
+ uio.uio_resid += (len); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) \
+ { \
+ if (sm_print(fp, timeout, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+} while (0)
+#define PAD(howmany, with) do \
+{ \
+ if ((n = (howmany)) > 0) \
+ { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+} while (0)
+#define FLUSH() do \
+{ \
+ if (uio.uio_resid && sm_print(fp, timeout, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+} while (0)
+
+ /*
+ ** To extend shorts properly, we need both signed and unsigned
+ ** argument extraction methods.
+ */
+#define SARG() \
+ (flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \
+ flags&LONGINT ? GETARG(long) : \
+ flags&SHORTINT ? (long) (short) GETARG(int) : \
+ (long) GETARG(int))
+#define UARG() \
+ (flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \
+ flags&LONGINT ? GETARG(unsigned long) : \
+ flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \
+ (unsigned long) GETARG(unsigned int))
+
+ /*
+ ** Get * arguments, including the form *nn$. Preserve the nextarg
+ ** that the argument can be gotten once the type is determined.
+ */
+#define GETASTER(val) \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) \
+ { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') \
+ { \
+ int hold = nextarg; \
+ if (argtable == NULL) \
+ { \
+ argtable = statargtable; \
+ sm_find_arguments(fmt0, orgap, &argtable); \
+ } \
+ nextarg = n2; \
+ val = GETARG(int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } \
+ else \
+ { \
+ val = GETARG(int); \
+ }
+
+/*
+** Get the argument indexed by nextarg. If the argument table is
+** built, use it to get the argument. If its not, get the next
+** argument (and arguments must be gotten sequentially).
+*/
+
+#if SM_VA_STD
+# define GETARG(type) \
+ (((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \
+ nextarg++, SM_VA_ARG(ap, type))
+#else /* SM_VA_STD */
+# define GETARG(type) \
+ ((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \
+ (nextarg++, SM_VA_ARG(ap, type)))
+#endif /* SM_VA_STD */
+
+ /* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) &&
+ fp->f_file >= 0)
+ return sm_bprintf(fp, fmt0, ap);
+
+ fmt = (char *) fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ SM_VA_COPY(orgap, ap);
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+
+ /* Scan the format for conversions (`%' character). */
+ for (;;)
+ {
+ cp = fmt;
+ n = 0;
+ while ((wc = *fmt) != '\0')
+ {
+ if (wc == '%')
+ {
+ n = 1;
+ break;
+ }
+ fmt++;
+ }
+ if ((m = fmt - cp) != 0)
+ {
+ PRINT(cp, m);
+ ret += m;
+ }
+ if (n <= 0)
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch)
+ {
+ case ' ':
+
+ /*
+ ** ``If the space and + flags both appear, the space
+ ** flag will be ignored.''
+ ** -- ANSI X3J11
+ */
+
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+
+ /*
+ ** ``A negative field width argument is taken as a
+ ** - flag followed by a positive field width.''
+ ** -- ANSI X3J11
+ ** They don't exclude field widths read from args.
+ */
+
+ GETASTER(width);
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*')
+ {
+ GETASTER(n);
+ prec = n < 0 ? -1 : n;
+ goto rflag;
+ }
+ n = 0;
+ while (is_digit(ch))
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ }
+ if (ch == '$')
+ {
+ nextarg = n;
+ if (argtable == NULL)
+ {
+ argtable = statargtable;
+ sm_find_arguments(fmt0, orgap,
+ &argtable);
+ }
+ goto rflag;
+ }
+ prec = n < 0 ? -1 : n;
+ goto reswitch;
+ case '0':
+
+ /*
+ ** ``Note that 0 is taken as a flag, not as the
+ ** beginning of a field width.''
+ ** -- ANSI X3J11
+ */
+
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$')
+ {
+ nextarg = n;
+ if (argtable == NULL)
+ {
+ argtable = statargtable;
+ sm_find_arguments(fmt0, orgap,
+ &argtable);
+ }
+ goto rflag;
+ }
+ width = n;
+ goto reswitch;
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ if (*fmt == 'l')
+ {
+ fmt++;
+ flags |= QUADINT;
+ }
+ else
+ {
+ flags |= LONGINT;
+ }
+ goto rflag;
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+ case 'c':
+ *(cp = buf) = GETARG(int);
+ size = 1;
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ _uquad = SARG();
+ if ((LONGLONG_T) _uquad < 0)
+ {
+ _uquad = -(LONGLONG_T) _uquad;
+ sign = '-';
+ }
+ base = DEC;
+ goto number;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ {
+ double val;
+ char *p;
+ char fmt[16];
+ char out[150];
+ size_t len;
+
+ /*
+ ** This code implements floating point output
+ ** in the most portable manner possible,
+ ** relying only on 'sprintf' as defined by
+ ** the 1989 ANSI C standard.
+ ** We silently cap width and precision
+ ** at 120, to avoid buffer overflow.
+ */
+
+ val = GETARG(double);
+
+ p = fmt;
+ *p++ = '%';
+ if (sign)
+ *p++ = sign;
+ if (flags & ALT)
+ *p++ = '#';
+ if (flags & LADJUST)
+ *p++ = '-';
+ if (flags & ZEROPAD)
+ *p++ = '0';
+ *p++ = '*';
+ if (prec >= 0)
+ {
+ *p++ = '.';
+ *p++ = '*';
+ }
+ *p++ = ch;
+ *p = '\0';
+
+ if (width > 120)
+ width = 120;
+ if (prec > 120)
+ prec = 120;
+ if (prec >= 0)
+ sprintf(out, fmt, width, prec, val);
+ else
+ sprintf(out, fmt, width, val);
+ len = strlen(out);
+ PRINT(out, len);
+ FLUSH();
+ continue;
+ }
+ case 'n':
+ if (flags & QUADINT)
+ *GETARG(LONGLONG_T *) = ret;
+ else if (flags & LONGINT)
+ *GETARG(long *) = ret;
+ else if (flags & SHORTINT)
+ *GETARG(short *) = ret;
+ else
+ *GETARG(int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ _uquad = UARG();
+ base = OCT;
+ goto nosign;
+ case 'p':
+
+ /*
+ ** ``The argument shall be a pointer to void. The
+ ** value of the pointer is converted to a sequence
+ ** of printable characters, in an implementation-
+ ** defined manner.''
+ ** -- ANSI X3J11
+ */
+
+ /* NOSTRICT */
+ {
+ union
+ {
+ void *p;
+ ULONGLONG_T ll;
+ unsigned long l;
+ unsigned i;
+ } u;
+ u.p = GETARG(void *);
+ if (sizeof(void *) == sizeof(ULONGLONG_T))
+ _uquad = u.ll;
+ else if (sizeof(void *) == sizeof(long))
+ _uquad = u.l;
+ else
+ _uquad = u.i;
+ }
+ base = HEX;
+ xdigs = "0123456789abcdef";
+ flags |= HEXPREFIX;
+ ch = 'x';
+ goto nosign;
+ case 's':
+ if ((cp = GETARG(char *)) == NULL)
+ cp = "(null)";
+ if (prec >= 0)
+ {
+ /*
+ ** can't use strlen; can only look for the
+ ** NUL in the first `prec' characters, and
+ ** strlen() will go further.
+ */
+
+ char *p = memchr(cp, 0, prec);
+
+ if (p != NULL)
+ {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ }
+ else
+ size = prec;
+ }
+ else
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ _uquad = UARG();
+ base = DEC;
+ goto nosign;
+ case 'X':
+ xdigs = "0123456789ABCDEF";
+ goto hex;
+ case 'x':
+ xdigs = "0123456789abcdef";
+hex: _uquad = UARG();
+ base = HEX;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT && _uquad != 0)
+ flags |= HEXPREFIX;
+
+ /* unsigned conversions */
+nosign: sign = '\0';
+
+ /*
+ ** ``... diouXx conversions ... if a precision is
+ ** specified, the 0 flag will be ignored.''
+ ** -- ANSI X3J11
+ */
+
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*
+ ** ``The result of converting a zero value with an
+ ** explicit precision of zero is no characters.''
+ ** -- ANSI X3J11
+ */
+
+ cp = buf + BUF;
+ if (_uquad != 0 || prec != 0)
+ {
+ /*
+ ** Unsigned mod is hard, and unsigned mod
+ ** by a constant is easier than that by
+ ** a variable; hence this switch.
+ */
+
+ switch (base)
+ {
+ case OCT:
+ do
+ {
+ *--cp = to_char(_uquad & 7);
+ _uquad >>= 3;
+ } while (_uquad);
+ /* handle octal leading 0 */
+ if (flags & ALT && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case DEC:
+ /* many numbers are 1 digit */
+ while (_uquad >= 10)
+ {
+ *--cp = to_char(_uquad % 10);
+ _uquad /= 10;
+ }
+ *--cp = to_char(_uquad);
+ break;
+
+ case HEX:
+ do
+ {
+ *--cp = xdigs[_uquad & 15];
+ _uquad >>= 4;
+ } while (_uquad);
+ break;
+
+ default:
+ cp = "bug in sm_io_vfprintf: bad base";
+ size = strlen(cp);
+ goto skipsize;
+ }
+ }
+ size = buf + BUF - cp;
+ skipsize:
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ ** All reasonable formats wind up here. At this point, `cp'
+ ** points to a string which (if not flags&LADJUST) should be
+ ** padded out to `width' places. If flags&ZEROPAD, it should
+ ** first be prefixed by any sign or other prefix; otherwise,
+ ** it should be blank padded before the prefix is emitted.
+ ** After any left-hand padding and prefixing, emit zeroes
+ ** required by a decimal [diouxX] precision, then print the
+ ** string proper, then emit zeroes required by any leftover
+ ** floating precision; finally, if LADJUST, pad with blanks.
+ **
+ ** Compute actual size, so we know how much to pad.
+ ** size excludes decimal prec; realsz includes it.
+ */
+
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ else if (flags & HEXPREFIX)
+ realsz+= 2;
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ {
+ PRINT(&sign, 1);
+ }
+ else if (flags & HEXPREFIX)
+ {
+ ox[0] = '0';
+ ox[1] = ch;
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+
+ /* the string or number proper */
+ PRINT(cp, size);
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += width > realsz ? width : realsz;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ if ((argtable != NULL) && (argtable != statargtable))
+ sm_free(argtable);
+ return sm_error(fp) ? SM_IO_EOF : ret;
+ /* NOTREACHED */
+}
+
+/* Type ids for argument type table. */
+#define T_UNUSED 0
+#define T_SHORT 1
+#define T_U_SHORT 2
+#define TP_SHORT 3
+#define T_INT 4
+#define T_U_INT 5
+#define TP_INT 6
+#define T_LONG 7
+#define T_U_LONG 8
+#define TP_LONG 9
+#define T_QUAD 10
+#define T_U_QUAD 11
+#define TP_QUAD 12
+#define T_DOUBLE 13
+#define TP_CHAR 15
+#define TP_VOID 16
+
+/*
+** SM_FIND_ARGUMENTS -- find all args when a positional parameter is found.
+**
+** Find all arguments when a positional parameter is encountered. Returns a
+** table, indexed by argument number, of pointers to each arguments. The
+** initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
+** It will be replaced with a malloc-ed one if it overflows.
+**
+** Parameters:
+** fmt0 -- formating directives
+** ap -- vector list of data unit for formating consumption
+** argtable -- an indexable table (returned) of 'ap'
+**
+** Results:
+** none.
+*/
+
+static void
+sm_find_arguments(fmt0, ap, argtable)
+ const char *fmt0;
+ SM_VA_LOCAL_DECL
+ va_list **argtable;
+{
+ register char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n, n2; /* handy integer (short term usage) */
+ register char *cp; /* handy char pointer (short term usage) */
+ register int flags; /* flags as above */
+ unsigned char *typetable; /* table of types */
+ unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
+ int tablesize; /* current size of type table */
+ int tablemax; /* largest used index in table */
+ int nextarg; /* 1-based argument index */
+
+ /* Add an argument type to the table, expanding if necessary. */
+#define ADDTYPE(type) \
+ ((nextarg >= tablesize) ? \
+ (sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \
+ typetable[nextarg++] = type, \
+ (nextarg > tablemax) ? tablemax = nextarg : 0)
+
+#define ADDSARG() \
+ ((flags & LONGINT) ? ADDTYPE(T_LONG) : \
+ ((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
+
+#define ADDUARG() \
+ ((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \
+ ((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
+
+ /* Add * arguments to the type array. */
+#define ADDASTER() \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) \
+ { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') \
+ { \
+ int hold = nextarg; \
+ nextarg = n2; \
+ ADDTYPE (T_INT); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } \
+ else \
+ { \
+ ADDTYPE (T_INT); \
+ }
+ fmt = (char *) fmt0;
+ typetable = stattypetable;
+ tablesize = STATIC_ARG_TBL_SIZE;
+ tablemax = 0;
+ nextarg = 1;
+ (void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
+
+ /* Scan the format for conversions (`%' character). */
+ for (;;)
+ {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch)
+ {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ ADDASTER();
+ goto rflag;
+ case '-':
+ case '+':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*')
+ {
+ ADDASTER();
+ goto rflag;
+ }
+ while (is_digit(ch))
+ {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$')
+ {
+ nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+ case 'c':
+ ADDTYPE(T_INT);
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if (flags & QUADINT)
+ {
+ ADDTYPE(T_QUAD);
+ }
+ else
+ {
+ ADDSARG();
+ }
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ ADDTYPE(T_DOUBLE);
+ break;
+ case 'n':
+ if (flags & QUADINT)
+ ADDTYPE(TP_QUAD);
+ else if (flags & LONGINT)
+ ADDTYPE(TP_LONG);
+ else if (flags & SHORTINT)
+ ADDTYPE(TP_SHORT);
+ else
+ ADDTYPE(TP_INT);
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ case 'p':
+ ADDTYPE(TP_VOID);
+ break;
+ case 's':
+ ADDTYPE(TP_CHAR);
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ case 'X':
+ case 'x':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ /* Build the argument table. */
+ if (tablemax >= STATIC_ARG_TBL_SIZE)
+ {
+ *argtable = (va_list *)
+ sm_malloc(sizeof(va_list) * (tablemax + 1));
+ }
+
+ for (n = 1; n <= tablemax; n++)
+ {
+ SM_VA_COPY((*argtable)[n], ap);
+ switch (typetable [n])
+ {
+ case T_UNUSED:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_SHORT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_U_SHORT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case TP_SHORT:
+ (void) SM_VA_ARG(ap, short *);
+ break;
+ case T_INT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_U_INT:
+ (void) SM_VA_ARG(ap, unsigned int);
+ break;
+ case TP_INT:
+ (void) SM_VA_ARG(ap, int *);
+ break;
+ case T_LONG:
+ (void) SM_VA_ARG(ap, long);
+ break;
+ case T_U_LONG:
+ (void) SM_VA_ARG(ap, unsigned long);
+ break;
+ case TP_LONG:
+ (void) SM_VA_ARG(ap, long *);
+ break;
+ case T_QUAD:
+ (void) SM_VA_ARG(ap, LONGLONG_T);
+ break;
+ case T_U_QUAD:
+ (void) SM_VA_ARG(ap, ULONGLONG_T);
+ break;
+ case TP_QUAD:
+ (void) SM_VA_ARG(ap, LONGLONG_T *);
+ break;
+ case T_DOUBLE:
+ (void) SM_VA_ARG(ap, double);
+ break;
+ case TP_CHAR:
+ (void) SM_VA_ARG(ap, char *);
+ break;
+ case TP_VOID:
+ (void) SM_VA_ARG(ap, void *);
+ break;
+ }
+ }
+
+ if ((typetable != NULL) && (typetable != stattypetable))
+ sm_free(typetable);
+}
+
+/*
+** SM_GROW_TYPE_TABLE -- Increase the size of the type table.
+**
+** Parameters:
+** tabletype -- type of table to grow
+** tablesize -- requested new table size
+**
+** Results:
+** Raises an exception if can't allocate memory.
+*/
+
+static void
+sm_grow_type_table_x(typetable, tablesize)
+ unsigned char **typetable;
+ int *tablesize;
+{
+ unsigned char *oldtable = *typetable;
+ int newsize = *tablesize * 2;
+
+ if (*tablesize == STATIC_ARG_TBL_SIZE)
+ {
+ *typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char)
+ * newsize);
+ (void) memmove(*typetable, oldtable, *tablesize);
+ }
+ else
+ {
+ *typetable = (unsigned char *) sm_realloc_x(typetable,
+ sizeof(unsigned char) * newsize);
+ }
+ (void) memset(&typetable [*tablesize], T_UNUSED,
+ (newsize - *tablesize));
+
+ *tablesize = newsize;
+}
diff --git a/contrib/sendmail/libsm/vfscanf.c b/contrib/sendmail/libsm/vfscanf.c
new file mode 100644
index 0000000..5a19733
--- /dev/null
+++ b/contrib/sendmail/libsm/vfscanf.c
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.51 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/varargs.h>
+#include <sm/config.h>
+#include <sm/io.h>
+#include <sm/signal.h>
+#include <sm/clock.h>
+#include <sm/string.h>
+#include "local.h"
+
+#define BUF 513 /* Maximum length of numeric string. */
+
+/* Flags used during conversion. */
+#define LONG 0x01 /* l: long or double */
+#define SHORT 0x04 /* h: short */
+#define QUAD 0x08 /* q: quad (same as ll) */
+#define SUPPRESS 0x10 /* suppress assignment */
+#define POINTER 0x20 /* weird %p pointer (`fake hex') */
+#define NOSKIP 0x40 /* do not skip blanks */
+
+/*
+** The following are used in numeric conversions only:
+** SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+** SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+*/
+
+#define SIGNOK 0x080 /* +/- is (still) legal */
+#define NDIGITS 0x100 /* no digits detected */
+
+#define DPTOK 0x200 /* (float) decimal point is still legal */
+#define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK 0x200 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x400 /* no zero digits detected */
+
+/* Conversion types. */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* integer, i.e., strtoll or strtoull */
+#define CT_FLOAT 4 /* floating, i.e., strtod */
+
+static unsigned char *sm_sccl __P((char *, unsigned char *));
+static jmp_buf ScanTimeOut;
+
+/*
+** SCANALRM -- handler when timeout activated for sm_io_vfscanf()
+**
+** Returns flow of control to where setjmp(ScanTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(ScanTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+scanalrm(sig)
+ int sig;
+{
+ longjmp(ScanTimeOut, 1);
+}
+
+/*
+** SM_VFSCANF -- convert input into data units
+**
+** Parameters:
+** fp -- file pointer for input data
+** timeout -- time intvl allowed to complete (milliseconds)
+** fmt0 -- format for finding data units
+** ap -- vectors for memory location for storing data units
+**
+** Results:
+** Success: number of data units assigned
+** Failure: SM_IO_EOF
+*/
+
+int
+sm_vfscanf(fp, timeout, fmt0, ap)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+ char const *fmt0;
+ va_list SM_NONVOLATILE ap;
+{
+ register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
+ register int c; /* character from format, or conversion */
+ register size_t width; /* field width, or 0 */
+ register char *p; /* points into all kinds of strings */
+ register int n; /* handy integer */
+ register int flags; /* flags as defined above */
+ register char *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to strtoll/strtoull */
+ ULONGLONG_T (*ccfn)(); /* conversion function (strtoll/strtoull) */
+ char ccltab[256]; /* character class table for %[...] */
+ char buf[BUF]; /* buffer for numeric conversions */
+ SM_EVENT *evt = NULL;
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(ScanTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ evt = sm_seteventm(timeout, scanalrm, 0);
+ }
+
+ nassigned = 0;
+ nread = 0;
+ base = 0; /* XXX just to keep gcc happy */
+ ccfn = NULL; /* XXX just to keep gcc happy */
+ for (;;)
+ {
+ c = *fmt++;
+ if (c == 0)
+ {
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned;
+ }
+ if (isspace(c))
+ {
+ while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
+ == 0) &&
+ isspace(*fp->f_p))
+ nread++, fp->f_r--, fp->f_p++;
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+
+ /*
+ ** switch on the format. continue if done;
+ ** break once format type is derived.
+ */
+
+again: c = *fmt++;
+ switch (c)
+ {
+ case '%':
+literal:
+ if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+ if (*fp->f_p != c)
+ goto match_failure;
+ fp->f_r--, fp->f_p++;
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'h':
+ flags |= SHORT;
+ goto again;
+ case 'l':
+ if (*fmt == 'l')
+ {
+ fmt++;
+ flags |= QUAD;
+ }
+ else
+ {
+ flags |= LONG;
+ }
+ goto again;
+ case 'q':
+ flags |= QUAD;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ ** Conversions.
+ ** Those marked `compat' are for 4.[123]BSD compatibility.
+ **
+ ** (According to ANSI, E and X formats are supposed
+ ** to the same as e and x. Sorry about that.)
+ */
+
+ case 'D': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'd':
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)())sm_strtoll;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)())sm_strtoll;
+ base = 0;
+ break;
+
+ case 'O': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'o':
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 10;
+ break;
+
+ case 'X':
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 16;
+ break;
+
+ case 'E':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'g':
+ c = CT_FLOAT;
+ break;
+
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ fmt = sm_sccl(ccltab, fmt);
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORT)
+ *SM_VA_ARG(ap, short *) = nread;
+ else if (flags & LONG)
+ *SM_VA_ARG(ap, long *) = nread;
+ else
+ *SM_VA_ARG(ap, int *) = nread;
+ continue;
+
+ /* Disgusting backwards compatibility hacks. XXX */
+ case '\0': /* compat */
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return SM_IO_EOF;
+
+ default: /* compat */
+ if (isupper(c))
+ flags |= LONG;
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)()) sm_strtoll;
+ base = 10;
+ break;
+ }
+
+ /* We have a conversion that requires input. */
+ if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+
+ /*
+ ** Consume leading white space, except for formats
+ ** that suppress this.
+ */
+
+ if ((flags & NOSKIP) == 0)
+ {
+ while (isspace(*fp->f_p))
+ {
+ nread++;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+ }
+ /*
+ ** Note that there is at least one character in
+ ** the buffer, so conversions that do not set NOSKIP
+ ** can no longer result in an input failure.
+ */
+ }
+
+ /* Do the conversion. */
+ switch (c)
+ {
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & SUPPRESS)
+ {
+ size_t sum = 0;
+ for (;;)
+ {
+ if ((size_t) (n = fp->f_r) < width)
+ {
+ sum += n;
+ width -= n;
+ fp->f_p += n;
+ if (sm_refill(fp,
+ SM_TIME_FOREVER))
+ {
+ if (sum == 0)
+ goto input_failure;
+ break;
+ }
+ }
+ else
+ {
+ sum += width;
+ fp->f_r -= width;
+ fp->f_p += width;
+ break;
+ }
+ }
+ nread += sum;
+ }
+ else
+ {
+ size_t r;
+
+ r = sm_io_read(fp, SM_TIME_FOREVER,
+ (void *) SM_VA_ARG(ap, char *),
+ width);
+ if (r == 0)
+ goto input_failure;
+ nread += r;
+ nassigned++;
+ }
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t)~0; /* `infinity' */
+
+ /* take only those things in the class */
+ if (flags & SUPPRESS)
+ {
+ n = 0;
+ while (ccltab[*fp->f_p] != '\0')
+ {
+ n++, fp->f_r--, fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ {
+ if (n == 0) /* XXX how? */
+ goto input_failure;
+ break;
+ }
+ }
+ if (n == 0)
+ goto match_failure;
+ }
+ else
+ {
+ p0 = p = SM_VA_ARG(ap, char *);
+ while (ccltab[*fp->f_p] != '\0')
+ {
+ fp->f_r--;
+ *p++ = *fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ {
+ if (p == p0)
+ goto input_failure;
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ }
+ nread += n;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & SUPPRESS)
+ {
+ n = 0;
+ while (!isspace(*fp->f_p))
+ {
+ n++, fp->f_r--, fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ break;
+ }
+ nread += n;
+ }
+ else
+ {
+ p0 = p = SM_VA_ARG(ap, char *);
+ while (!isspace(*fp->f_p))
+ {
+ fp->f_r--;
+ *p++ = *fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ break;
+ }
+ *p = 0;
+ nread += p - p0;
+ nassigned++;
+ }
+ continue;
+
+ case CT_INT:
+ /* scan an integer as if by strtoll/strtoull */
+#if SM_CONF_BROKEN_SIZE_T
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else /* SM_CONF_BROKEN_SIZE_T */
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif /* SM_CONF_BROKEN_SIZE_T */
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width > 0; width--)
+ {
+ c = *fp->f_p;
+
+ /*
+ ** Switch on the character; `goto ok'
+ ** if we accept it as a part of number.
+ */
+
+ switch (c)
+ {
+
+ /*
+ ** The digit 0 is always legal, but is
+ ** special. For %i conversions, if no
+ ** digits (zero or nonzero) have been
+ ** scanned (only signs), we will have
+ ** base==0. In that case, we should set
+ ** it to 8 and enable 0x prefixing.
+ ** Also, if we have not scanned zero digits
+ ** before this, do not turn off prefixing
+ ** (someone else will turn it off if we
+ ** have scanned any nonzero digits).
+ */
+
+ case '0':
+ if (base == 0)
+ {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ goto ok;
+ }
+ break;
+
+ /* x ok iff flag still set & 2nd char */
+ case 'x': case 'X':
+ if (flags & PFXOK && p == buf + 1)
+ {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ ** If we got here, c is not a legal character
+ ** for a number. Stop accumulating digits.
+ */
+
+ break;
+ ok:
+ /* c is legal: store it and look at the next. */
+ *p++ = c;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ break; /* SM_IO_EOF */
+ }
+
+ /*
+ ** If we had only a sign, it is no good; push
+ ** back the sign. If the number ends in `x',
+ ** it was [sign] '0' 'x', so push back the x
+ ** and treat it as [sign] '0'.
+ */
+
+ if (flags & NDIGITS)
+ {
+ if (p > buf)
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
+ *(unsigned char *)--p);
+ goto match_failure;
+ }
+ c = ((unsigned char *)p)[-1];
+ if (c == 'x' || c == 'X')
+ {
+ --p;
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ ULONGLONG_T res;
+
+ *p = 0;
+ res = (*ccfn)(buf, (char **)NULL, base);
+ if (flags & POINTER)
+ *SM_VA_ARG(ap, void **) =
+ (void *)(long) res;
+ else if (flags & QUAD)
+ *SM_VA_ARG(ap, LONGLONG_T *) = res;
+ else if (flags & LONG)
+ *SM_VA_ARG(ap, long *) = res;
+ else if (flags & SHORT)
+ *SM_VA_ARG(ap, short *) = res;
+ else
+ *SM_VA_ARG(ap, int *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+
+ case CT_FLOAT:
+ /* scan a floating point number as if by strtod */
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+ flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+ for (p = buf; width; width--)
+ {
+ c = *fp->f_p;
+
+ /*
+ ** This code mimicks the integer conversion
+ ** code, but is much simpler.
+ */
+
+ switch (c)
+ {
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ flags &= ~(SIGNOK | NDIGITS);
+ goto fok;
+
+ case '+': case '-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ goto fok;
+ }
+ break;
+ case '.':
+ if (flags & DPTOK)
+ {
+ flags &= ~(SIGNOK | DPTOK);
+ goto fok;
+ }
+ break;
+ case 'e': case 'E':
+
+ /* no exponent without some digits */
+ if ((flags&(NDIGITS|EXPOK)) == EXPOK)
+ {
+ flags =
+ (flags & ~(EXPOK|DPTOK)) |
+ SIGNOK | NDIGITS;
+ goto fok;
+ }
+ break;
+ }
+ break;
+ fok:
+ *p++ = c;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ break; /* SM_IO_EOF */
+ }
+
+ /*
+ ** If no digits, might be missing exponent digits
+ ** (just give back the exponent) or might be missing
+ ** regular digits, but had sign and/or decimal point.
+ */
+
+ if (flags & NDIGITS)
+ {
+ if (flags & EXPOK)
+ {
+ /* no digits at all */
+ while (p > buf)
+ (void) sm_io_ungetc(fp,
+ SM_TIME_DEFAULT,
+ *(unsigned char *)--p);
+ goto match_failure;
+ }
+
+ /* just a bad exponent (e and maybe sign) */
+ c = *(unsigned char *) --p;
+ if (c != 'e' && c != 'E')
+ {
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
+ c); /* sign */
+ c = *(unsigned char *)--p;
+ }
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ double res;
+
+ *p = 0;
+ res = strtod(buf, (char **) NULL);
+ if (flags & LONG)
+ *SM_VA_ARG(ap, double *) = res;
+ else
+ *SM_VA_ARG(ap, float *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+ }
+ }
+input_failure:
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned ? nassigned : -1;
+match_failure:
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned;
+}
+
+/*
+** SM_SCCL -- sequenced character comparison list
+**
+** Fill in the given table from the scanset at the given format
+** (just after `['). Return a pointer to the character past the
+** closing `]'. The table has a 1 wherever characters should be
+** considered part of the scanset.
+**
+** Parameters:
+** tab -- array flagging "active" char's to match (returned)
+** fmt -- character list (within "[]")
+**
+** Results:
+*/
+
+static unsigned char *
+sm_sccl(tab, fmt)
+ register char *tab;
+ register unsigned char *fmt;
+{
+ register int c, n, v;
+
+ /* first `clear' the whole table */
+ c = *fmt++; /* first char hat => negated scanset */
+ if (c == '^')
+ {
+ v = 1; /* default => accept */
+ c = *fmt++; /* get new first char */
+ }
+ else
+ v = 0; /* default => reject */
+
+ /* should probably use memset here */
+ for (n = 0; n < 256; n++)
+ tab[n] = v;
+ if (c == 0)
+ return fmt - 1; /* format ended before closing ] */
+
+ /*
+ ** Now set the entries corresponding to the actual scanset
+ ** to the opposite of the above.
+ **
+ ** The first character may be ']' (or '-') without being special;
+ ** the last character may be '-'.
+ */
+
+ v = 1 - v;
+ for (;;)
+ {
+ tab[c] = v; /* take character c */
+doswitch:
+ n = *fmt++; /* and examine the next */
+ switch (n)
+ {
+
+ case 0: /* format ended too soon */
+ return fmt - 1;
+
+ case '-':
+ /*
+ ** A scanset of the form
+ ** [01+-]
+ ** is defined as `the digit 0, the digit 1,
+ ** the character +, the character -', but
+ ** the effect of a scanset such as
+ ** [a-zA-Z0-9]
+ ** is implementation defined. The V7 Unix
+ ** scanf treats `a-z' as `the letters a through
+ ** z', but treats `a-a' as `the letter a, the
+ ** character -, and the letter a'.
+ **
+ ** For compatibility, the `-' is not considerd
+ ** to define a range if the character following
+ ** it is either a close bracket (required by ANSI)
+ ** or is not numerically greater than the character
+ ** we just stored in the table (c).
+ */
+
+ n = *fmt;
+ if (n == ']' || n < c)
+ {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ do
+ {
+ /* fill in the range */
+ tab[++c] = v;
+ } while (c < n);
+#if 1 /* XXX another disgusting compatibility hack */
+
+ /*
+ ** Alas, the V7 Unix scanf also treats formats
+ ** such as [a-c-e] as `the letters a through e'.
+ ** This too is permitted by the standard....
+ */
+
+ goto doswitch;
+#else
+ c = *fmt++;
+ if (c == 0)
+ return fmt - 1;
+ if (c == ']')
+ return fmt;
+ break;
+#endif
+
+ case ']': /* end of scanset */
+ return fmt;
+
+ default: /* just another character */
+ c = n;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
diff --git a/contrib/sendmail/libsm/vprintf.c b/contrib/sendmail/libsm/vprintf.c
new file mode 100644
index 0000000..6e310ef
--- /dev/null
+++ b/contrib/sendmail/libsm/vprintf.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: vprintf.c,v 1.14 2001/09/11 04:04:49 gshapiro Exp $")
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VPRINTF -- print to standard out with variable length args
+**
+** Parameters:
+** timeout -- length of time allow to do the print
+** fmt -- the format of the output
+** ap -- the variable number of args to be used for output
+**
+** Returns:
+** as sm_io_vfprintf() does.
+*/
+
+int
+sm_vprintf(timeout, fmt, ap)
+ int timeout;
+ char const *fmt;
+ SM_VA_LOCAL_DECL
+{
+ return sm_io_vfprintf(smiostdout, timeout, fmt, ap);
+}
diff --git a/contrib/sendmail/libsm/vsnprintf.c b/contrib/sendmail/libsm/vsnprintf.c
new file mode 100644
index 0000000..18a4635
--- /dev/null
+++ b/contrib/sendmail/libsm/vsnprintf.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: vsnprintf.c,v 1.23 2001/09/11 04:04:49 gshapiro Exp $")
+#include <limits.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VSNPRINTF -- format data for "output" into a string
+**
+** Assigned 'str' to a "fake" file pointer. This allows common
+** o/p formatting function sm_vprintf() to be used.
+**
+** Parameters:
+** str -- location for output
+** n -- maximum size for o/p
+** fmt -- format directives
+** ap -- data unit vectors for use by 'fmt'
+**
+** Results:
+** result from sm_io_vfprintf()
+**
+** Side Effects:
+** Limits the size ('n') to INT_MAX.
+*/
+
+int
+sm_vsnprintf(str, n, fmt, ap)
+ char *str;
+ size_t n;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ char dummy;
+ SM_FILE_T fake;
+
+ /* While snprintf(3) specifies size_t stdio uses an int internally */
+ if (n > INT_MAX)
+ n = INT_MAX;
+
+ /* Stdio internals do not deal correctly with zero length buffer */
+ if (n == 0)
+ {
+ str = &dummy;
+ n = 1;
+ }
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = n - 1;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsnprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ *fake.f_p = 0;
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/vsprintf.c b/contrib/sendmail/libsm/vsprintf.c
new file mode 100644
index 0000000..827fcec
--- /dev/null
+++ b/contrib/sendmail/libsm/vsprintf.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: vsprintf.c,v 1.21 2001/09/11 04:04:49 gshapiro Exp $")
+#include <limits.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VSPRINTF -- format data for "output" into a string
+**
+** Assigned 'str' to a "fake" file pointer. This allows common
+** o/p formatting function sm_vprintf() to be used.
+**
+** Parameters:
+** str -- location for output
+** fmt -- format directives
+** ap -- data unit vectors for use by 'fmt'
+**
+** Results:
+** result from sm_io_vfprintf()
+**
+** Side Effects:
+** Quietly limits the size to INT_MAX though this may
+** not prevent SEGV's.
+*/
+
+int
+sm_vsprintf(str, fmt, ap)
+ char *str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = INT_MAX;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ *fake.f_p = '\0';
+ return ret;
+}
diff --git a/contrib/sendmail/libsm/vsscanf.c b/contrib/sendmail/libsm/vsscanf.c
new file mode 100644
index 0000000..3de2224
--- /dev/null
+++ b/contrib/sendmail/libsm/vsscanf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: vsscanf.c,v 1.22 2001/09/11 04:04:49 gshapiro Exp $")
+#include <string.h>
+#include <sm/io.h>
+
+/*
+** SM_EOFREAD -- dummy read function for faked file below
+**
+** Parameters:
+** fp -- file pointer
+** buf -- location to place read data
+** len -- number of bytes to read
+**
+** Returns:
+** 0 (zero) always
+*/
+
+/* type declaration for later use */
+static ssize_t sm_eofread __P((SM_FILE_T *, char *, size_t));
+
+/* ARGSUSED0 */
+static ssize_t
+sm_eofread(fp, buf, len)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t len;
+{
+ return 0;
+}
+
+/*
+** SM_VSSCANF -- scan a string to find data units
+**
+** Parameters:
+** str -- strings containing data
+** fmt -- format directive for finding data units
+** ap -- memory locations to place format found data units
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: number of data units found
+**
+** Side Effects:
+** Attempts to strlen() 'str'; if not a '\0' terminated string
+** then the call may SEGV/fail.
+** Faking the string 'str' as a file.
+*/
+
+int
+sm_vsscanf(str, fmt, ap)
+ const char *str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ SM_FILE_T fake;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMRD;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_r = strlen(str);
+ fake.f_read = sm_eofread;
+ fake.f_ub.smb_base = NULL;
+ fake.f_lb.smb_base = NULL;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsscanf:fake";
+ return sm_vfscanf(&fake, SM_TIME_FOREVER, fmt, ap);
+}
diff --git a/contrib/sendmail/libsm/wbuf.c b/contrib/sendmail/libsm/wbuf.c
new file mode 100644
index 0000000..8385535
--- /dev/null
+++ b/contrib/sendmail/libsm/wbuf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: wbuf.c,v 1.21 2001/09/11 04:04:49 gshapiro Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+
+/* Note: This function is called from a macro located in <sm/io.h> */
+
+/*
+** SM_WBUF -- write character to and flush (likely now full) buffer
+**
+** Write the given character into the (probably full) buffer for
+** the given file. Flush the buffer out if it is or becomes full,
+** or if c=='\n' and the file is line buffered.
+**
+** Parameters:
+** fp -- the file pointer
+** timeout -- time to complete operation (milliseconds)
+** c -- int representation of the character to add
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: int value of 'c'
+*/
+
+int
+sm_wbuf(fp, timeout, c)
+ register SM_FILE_T *fp;
+ int timeout;
+ register int c;
+{
+ register int n;
+
+ /*
+ ** In case we cannot write, or longjmp takes us out early,
+ ** make sure w is 0 (if fully- or un-buffered) or -bf.smb_size
+ ** (if line buffered) so that we will get called again.
+ ** If we did not do this, a sufficient number of sm_io_putc()
+ ** calls might wrap w from negative to positive.
+ */
+
+ fp->f_w = fp->f_lbfsize;
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ c = (unsigned char)c;
+
+ /*
+ ** If it is completely full, flush it out. Then, in any case,
+ ** stuff c into the buffer. If this causes the buffer to fill
+ ** completely, or if c is '\n' and the file is line buffered,
+ ** flush it (perhaps a second time). The second flush will always
+ ** happen on unbuffered streams, where bf.smb_size==1; sm_io_flush()
+ ** guarantees that sm_io_putc() will always call sm_wbuf() by setting
+ ** w to 0, so we need not do anything else.
+ ** Note for the timeout, only one of the sm_io_flush's will get called.
+ */
+
+ n = fp->f_p - fp->f_bf.smb_base;
+ if (n >= fp->f_bf.smb_size)
+ {
+ if (sm_io_flush(fp, timeout))
+ return SM_IO_EOF; /* sm_io_flush() sets errno */
+ n = 0;
+ }
+ fp->f_w--;
+ *fp->f_p++ = c;
+ if (++n == fp->f_bf.smb_size || (fp->f_flags & SMLBF && c == '\n'))
+ if (sm_io_flush(fp, timeout))
+ return SM_IO_EOF; /* sm_io_flush() sets errno */
+ return c;
+}
diff --git a/contrib/sendmail/libsm/wsetup.c b/contrib/sendmail/libsm/wsetup.c
new file mode 100644
index 0000000..16b1b0e
--- /dev/null
+++ b/contrib/sendmail/libsm/wsetup.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: wsetup.c,v 1.19 2001/09/11 04:04:49 gshapiro Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_WSETUP -- check writting is safe
+**
+** Various output routines call wsetup to be sure it is safe to write,
+** because either flags does not include SMMWR, or buf is NULL.
+** Used in the macro "cantwrite" found in "local.h".
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Results:
+** Failure: SM_IO_EOF and sets errno
+** Success: 0 (zero)
+*/
+
+int
+sm_wsetup(fp)
+ register SM_FILE_T *fp;
+{
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ /* If we are not writing, we had better be reading and writing. */
+ if ((fp->f_flags & SMWR) == 0)
+ {
+ if ((fp->f_flags & SMRW) == 0)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ if (fp->f_flags & SMRD)
+ {
+ /* clobber any ungetc data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~(SMRD|SMFEOF);
+ fp->f_r = 0;
+ fp->f_p = fp->f_bf.smb_base;
+ }
+ fp->f_flags |= SMWR;
+ }
+
+ /* Make a buffer if necessary, then set w. */
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+ if (fp->f_flags & SMLBF)
+ {
+ /*
+ ** It is line buffered, so make lbfsize be -bufsize
+ ** for the sm_putc() macro. We will change lbfsize back
+ ** to 0 whenever we turn off SMWR.
+ */
+
+ fp->f_w = 0;
+ fp->f_lbfsize = -fp->f_bf.smb_size;
+ }
+ else
+ fp->f_w = fp->f_flags & SMNBF ? 0 : fp->f_bf.smb_size;
+ return 0;
+}
diff --git a/contrib/sendmail/libsm/xtrap.c b/contrib/sendmail/libsm/xtrap.c
new file mode 100644
index 0000000..7495e09
--- /dev/null
+++ b/contrib/sendmail/libsm/xtrap.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: xtrap.c,v 1.5 2001/09/11 04:04:49 gshapiro Exp $")
+
+#include <sm/xtrap.h>
+
+SM_ATOMIC_UINT_T SmXtrapCount;
+
+SM_DEBUG_T SmXtrapDebug = SM_DEBUG_INITIALIZER("sm_xtrap",
+ "@(#)$Debug: sm_xtrap - raise exception at N'th xtrap point $");
+
+SM_DEBUG_T SmXtrapReport = SM_DEBUG_INITIALIZER("sm_xtrap_report",
+ "@(#)$Debug: sm_xtrap_report - report xtrap count on exit $");
diff --git a/contrib/sendmail/libsmdb/Makefile.m4 b/contrib/sendmail/libsmdb/Makefile.m4
index f24c0a0..90cecfe 100644
--- a/contrib/sendmail/libsmdb/Makefile.m4
+++ b/contrib/sendmail/libsmdb/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
diff --git a/contrib/sendmail/libsmdb/smdb.c b/contrib/sendmail/libsmdb/smdb.c
index 597cbff..e4bc341 100644
--- a/contrib/sendmail/libsmdb/smdb.c
+++ b/contrib/sendmail/libsmdb/smdb.c
@@ -1,5 +1,5 @@
/*
-** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
** All rights reserved.
**
** By using this file, you agree to the terms and conditions set
@@ -7,9 +7,8 @@
** the sendmail distribution.
*/
-#ifndef lint
-static char id[] = "@(#)$Id: smdb.c,v 8.37.4.2 2000/08/24 17:08:00 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: smdb.c,v 8.53 2001/11/19 19:31:14 gshapiro Exp $")
#include <fcntl.h>
#include <stdlib.h>
@@ -19,7 +18,7 @@ static char id[] = "@(#)$Id: smdb.c,v 8.37.4.2 2000/08/24 17:08:00 gshapiro Exp
#include <sendmail/sendmail.h>
#include <libsmdb/smdb.h>
- /*
+/*
** SMDB_MALLOC_DATABASE -- Allocates a database structure.
**
** Parameters:
@@ -38,13 +37,13 @@ smdb_malloc_database()
db = (SMDB_DATABASE *) malloc(sizeof(SMDB_DATABASE));
if (db != NULL)
- memset(db, '\0', sizeof(SMDB_DATABASE));
+ (void) memset(db, '\0', sizeof(SMDB_DATABASE));
return db;
}
- /*
+/*
** SMDB_FREE_DATABASE -- Unallocates a database structure.
**
** Parameters:
@@ -61,8 +60,7 @@ smdb_free_database(database)
if (database != NULL)
free(database);
}
-
- /*
+/*
** SMDB_LOCKFILE -- lock a file using flock or (shudder) fcntl locking
**
** Parameters:
@@ -72,8 +70,8 @@ smdb_free_database(database)
** LOCK_NB -- non-blocking.
**
** Returns:
-** TRUE if the lock was acquired.
-** FALSE otherwise.
+** true if the lock was acquired.
+** false otherwise.
*/
static bool
@@ -87,7 +85,7 @@ smdb_lockfile(fd, type)
int action;
struct flock lfd;
- memset(&lfd, '\0', sizeof lfd);
+ (void) memset(&lfd, '\0', sizeof lfd);
if (bitset(LOCK_UN, type))
lfd.l_type = F_UNLCK;
else if (bitset(LOCK_EX, type))
@@ -103,9 +101,7 @@ smdb_lockfile(fd, type)
while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
continue;
if (i >= 0)
- {
- return TRUE;
- }
+ return true;
save_errno = errno;
/*
@@ -118,9 +114,7 @@ smdb_lockfile(fd, type)
*/
if (save_errno == EINVAL)
- {
- return TRUE;
- }
+ return true;
if (!bitset(LOCK_NB, type) ||
(save_errno != EACCES && save_errno != EAGAIN))
@@ -132,18 +126,16 @@ smdb_lockfile(fd, type)
# endif /* F_GETFL */
# if 0
syslog(LOG_ERR, "cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
- filename, ext, fd, type, omode, geteuid());
+ filename, ext, fd, type, omode, (int) geteuid());
# endif /* 0 */
- return FALSE;
+ return false;
}
#else /* !HASFLOCK */
while ((i = flock(fd, type)) < 0 && errno == EINTR)
continue;
if (i >= 0)
- {
- return TRUE;
- }
+ return true;
save_errno = errno;
if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
@@ -155,16 +147,15 @@ smdb_lockfile(fd, type)
# endif /* F_GETFL */
# if 0
syslog(LOG_ERR, "cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
- filename, ext, fd, type, omode, geteuid());
+ filename, ext, fd, type, omode, (int) geteuid());
# endif /* 0 */
- return FALSE;
+ return false;
}
#endif /* !HASFLOCK */
errno = save_errno;
- return FALSE;
+ return false;
}
-
- /*
+/*
** SMDB_OPEN_DATABASE -- Opens a database.
**
** This opens a database. If type is SMDB_DEFAULT it tries to
@@ -207,12 +198,11 @@ smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
SMDB_USER_INFO *user_info;
SMDB_DBPARAMS *params;
{
- int result;
- bool type_was_default = FALSE;
+ bool type_was_default = false;
if (type == SMDB_TYPE_DEFAULT)
{
- type_was_default = TRUE;
+ type_was_default = true;
#ifdef NEWDB
type = SMDB_TYPE_HASH;
#else /* NEWDB */
@@ -229,6 +219,8 @@ smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
(strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0))
{
#ifdef NEWDB
+ int result;
+
result = smdb_db_open(database, db_name, mode, mode_mask, sff,
type, user_info, params);
# ifdef NDBM
@@ -245,6 +237,8 @@ smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
if (strncmp(type, SMDB_TYPE_NDBM, SMDB_TYPE_NDBM_LEN) == 0)
{
#ifdef NDBM
+ int result;
+
result = smdb_ndbm_open(database, db_name, mode, mode_mask,
sff, type, user_info, params);
return result;
@@ -255,8 +249,7 @@ smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
return SMDBE_UNKNOWN_DB_TYPE;
}
-
- /*
+/*
** SMDB_ADD_EXTENSION -- Adds an extension to a file name.
**
** Just adds a . followed by a string to a db_name if there
@@ -296,15 +289,14 @@ smdb_add_extension(full_name, max_full_name_len, db_name, extension)
if (db_name_len < extension_len + 1 ||
db_name[db_name_len - extension_len - 1] != '.' ||
strcmp(&db_name[db_name_len - extension_len], extension) != 0)
- snprintf(full_name, max_full_name_len, "%s.%s", db_name,
- extension);
+ (void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
+ db_name, extension);
else
- (void) strlcpy(full_name, db_name, max_full_name_len);
+ (void) sm_strlcpy(full_name, db_name, max_full_name_len);
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_LOCK_FILE -- Locks the database file.
**
** Locks the actual database file.
@@ -342,8 +334,7 @@ smdb_lock_file(lock_fd, db_name, mode, sff, extension)
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_UNLOCK_FILE -- Unlocks a file
**
** Unlocks a file.
@@ -367,8 +358,7 @@ smdb_unlock_file(lock_fd)
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_LOCK_MAP -- Locks a database.
**
** Parameters:
@@ -395,8 +385,7 @@ smdb_lock_map(database, type)
return SMDBE_LOCK_NOT_GRANTED;
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_UNLOCK_MAP -- Unlocks a database
**
** Parameters:
@@ -419,9 +408,7 @@ smdb_unlock_map(database)
return SMDBE_LOCK_NOT_HELD;
return SMDBE_OK;
}
-
-
- /*
+/*
** SMDB_SETUP_FILE -- Gets db file ready for use.
**
** Makes sure permissions on file are safe and creates it if it
@@ -465,8 +452,7 @@ smdb_setup_file(db_name, extension, mode_mask, sff, user_info, stat_info)
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_FILECHANGED -- Checks to see if a file changed.
**
** Compares the passed in stat_info with a current stat on
@@ -496,12 +482,9 @@ smdb_filechanged(db_name, extension, db_fd, stat_info)
extension);
if (result != SMDBE_OK)
return result;
-
- result = filechanged(db_file_name, db_fd, stat_info);
-
- return result;
+ return filechanged(db_file_name, db_fd, stat_info);
}
- /*
+/*
** SMDB_PRINT_AVAILABLE_TYPES -- Prints the names of the available types.
**
** Parameters:
@@ -522,7 +505,7 @@ smdb_print_available_types()
printf("btree\n");
#endif /* NEWDB */
}
- /*
+/*
** SMDB_DB_DEFINITION -- Given a database type, return database definition
**
** Reads though a structure making an association with the database
diff --git a/contrib/sendmail/libsmdb/smdb1.c b/contrib/sendmail/libsmdb/smdb1.c
index 797bf2f..f9dad9f 100644
--- a/contrib/sendmail/libsmdb/smdb1.c
+++ b/contrib/sendmail/libsmdb/smdb1.c
@@ -1,5 +1,5 @@
/*
-** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
** All rights reserved.
**
** By using this file, you agree to the terms and conditions set
@@ -7,9 +7,8 @@
** the sendmail distribution.
*/
-#ifndef lint
-static char id[] = "@(#)$Id: smdb1.c,v 8.43.4.3 2000/10/05 23:06:30 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: smdb1.c,v 8.55 2001/09/12 21:19:12 gshapiro Exp $")
#include <unistd.h>
#include <stdlib.h>
@@ -36,7 +35,7 @@ struct smdb_db1_cursor
};
typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
- /*
+/*
** SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type.
**
** Parameters:
@@ -64,9 +63,7 @@ smdb_type_to_db1_type(type)
/* Should never get here thanks to test in smdb_db_open() */
return DB_HASH;
}
-
-
- /*
+/*
** SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags.
**
** Parameters:
@@ -80,7 +77,7 @@ smdb_type_to_db1_type(type)
**
*/
-u_int
+unsigned int
smdb_put_flags_to_db1_flags(flags)
SMDB_FLAG flags;
{
@@ -93,8 +90,7 @@ smdb_put_flags_to_db1_flags(flags)
return return_flags;
}
-
- /*
+/*
** SMDB_CURSOR_GET_FLAGS_TO_SMDB1
**
** Parameters:
@@ -131,6 +127,10 @@ smdb_cursor_get_flags_to_smdb1(flags)
}
}
+/*
+** The rest of these functions correspond to the interface laid out in smdb.h.
+*/
+
SMDB_DB1_DATABASE *
smdb1_malloc_database()
{
@@ -141,43 +141,40 @@ smdb1_malloc_database()
if (db1 != NULL)
{
db1->smdb1_lock_fd = -1;
- db1->smdb1_cursor_in_use = FALSE;
+ db1->smdb1_cursor_in_use = false;
}
return db1;
}
-/*
-** The rest of these function correspond to the interface laid out
-** in smdb.h.
-*/
-
int
smdb1_close(database)
SMDB_DATABASE *database;
{
+ int result;
SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
+ result = db->close(db);
if (db1->smdb1_lock_fd != -1)
(void) close(db1->smdb1_lock_fd);
free(db1);
database->smdb_impl = NULL;
- return db->close(db);
+ return result;
}
int
smdb1_del(database, key, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
DBT dbkey;
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
return db->del(db, &dbkey, flags);
@@ -212,14 +209,14 @@ smdb1_get(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
int result;
DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
@@ -240,13 +237,13 @@ smdb1_put(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
dbdata.data = data->data;
@@ -282,7 +279,7 @@ smdb1_set_owner(database, uid, gid)
int
smdb1_sync(database, flags)
SMDB_DATABASE *database;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
@@ -299,7 +296,7 @@ smdb1_cursor_close(cursor)
if (!db1->smdb1_cursor_in_use)
return SMDBE_NOT_A_VALID_CURSOR;
- db1->smdb1_cursor_in_use = FALSE;
+ db1->smdb1_cursor_in_use = false;
free(cursor);
return SMDBE_OK;
@@ -308,7 +305,7 @@ smdb1_cursor_close(cursor)
int
smdb1_cursor_del(cursor, flags)
SMDB_CURSOR *cursor;
- u_int flags;
+ unsigned int flags;
{
SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
SMDB_DB1_DATABASE *db1 = db1_cursor->db;
@@ -331,8 +328,8 @@ smdb1_cursor_get(cursor, key, value, flags)
DB *db = db1->smdb1_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
db1_flags = smdb_cursor_get_flags_to_smdb1(flags);
result = db->seq(db, &dbkey, &dbdata, db1_flags);
@@ -359,8 +356,8 @@ smdb1_cursor_put(cursor, key, value, flags)
DB *db = db1->smdb1_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
dbdata.data = value->data;
@@ -373,7 +370,7 @@ int
smdb1_cursor(database, cursor, flags)
SMDB_DATABASE *database;
SMDB_CURSOR **cursor;
- u_int flags;
+ unsigned int flags;
{
SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
SMDB_CURSOR *cur;
@@ -382,7 +379,7 @@ smdb1_cursor(database, cursor, flags)
if (db1->smdb1_cursor_in_use)
return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
- db1->smdb1_cursor_in_use = TRUE;
+ db1->smdb1_cursor_in_use = true;
db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR));
db1_cursor->db = db1;
@@ -400,8 +397,7 @@ smdb1_cursor(database, cursor, flags)
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_DB_OPEN -- Opens a db1 database.
**
** Parameters:
@@ -488,7 +484,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
if (db_params != NULL &&
(strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0))
{
- memset(&hash_info, '\0', sizeof hash_info);
+ (void) memset(&hash_info, '\0', sizeof hash_info);
hash_info.nelem = db_params->smdbp_num_elements;
hash_info.cachesize = db_params->smdbp_cache_size;
params = &hash_info;
@@ -497,7 +493,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
if (db_params != NULL &&
(strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0))
{
- memset(&btree_info, '\0', sizeof btree_info);
+ (void) memset(&btree_info, '\0', sizeof btree_info);
btree_info.cachesize = db_params->smdbp_cache_size;
if (db_params->smdbp_allow_dup)
btree_info.flags |= R_DUP;
diff --git a/contrib/sendmail/libsmdb/smdb2.c b/contrib/sendmail/libsmdb/smdb2.c
index af56fe9..89a57de 100644
--- a/contrib/sendmail/libsmdb/smdb2.c
+++ b/contrib/sendmail/libsmdb/smdb2.c
@@ -7,9 +7,8 @@
** the sendmail distribution.
*/
-#ifndef lint
-static char id[] = "@(#)$Id: smdb2.c,v 8.53.2.1.2.7 2001/02/14 04:07:24 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: smdb2.c,v 8.69 2001/09/12 21:19:12 gshapiro Exp $")
#include <fcntl.h>
#include <stdlib.h>
@@ -30,7 +29,7 @@ struct smdb_db2_database
};
typedef struct smdb_db2_database SMDB_DB2_DATABASE;
- /*
+/*
** SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
**
** Parameters:
@@ -57,9 +56,7 @@ smdb_type_to_db2_type(type)
return DB_UNKNOWN;
}
-
-
- /*
+/*
** DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
**
** Parameters:
@@ -142,8 +139,7 @@ db2_error_to_smdb(error)
}
return result;
}
-
- /*
+/*
** SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
**
** Parameters:
@@ -157,7 +153,7 @@ db2_error_to_smdb(error)
**
*/
-u_int
+unsigned int
smdb_put_flags_to_db2_flags(flags)
SMDB_FLAG flags;
{
@@ -170,8 +166,7 @@ smdb_put_flags_to_db2_flags(flags)
return return_flags;
}
-
- /*
+/*
** SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
** getflags.
**
@@ -209,6 +204,11 @@ smdb_cursor_get_flags_to_db2(flags)
}
}
+/*
+** Except for smdb_db_open, the rest of these functions correspond to the
+** interface laid out in smdb.h.
+*/
+
SMDB_DB2_DATABASE *
smdb2_malloc_database()
{
@@ -221,38 +221,34 @@ smdb2_malloc_database()
return db2;
}
-
-/*
-** Except for smdb_db_open, the rest of these function correspond to the
-** interface laid out in smdb.h.
-*/
-
int
smdb2_close(database)
SMDB_DATABASE *database;
{
+ int result;
SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
+ result = db2_error_to_smdb(db->close(db, 0));
if (db2->smdb2_lock_fd != -1)
close(db2->smdb2_lock_fd);
free(db2);
database->smdb_impl = NULL;
- return db2_error_to_smdb(db->close(db, 0));
+ return result;
}
int
smdb2_del(database, key, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
DBT dbkey;
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
@@ -277,20 +273,19 @@ smdb2_lockfd(database)
return db2->smdb2_lock_fd;
}
-
int
smdb2_get(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
int result;
DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
@@ -305,13 +300,13 @@ smdb2_put(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
dbdata.data = data->data;
@@ -348,7 +343,7 @@ smdb2_set_owner(database, uid, gid)
int
smdb2_sync(database, flags)
SMDB_DATABASE *database;
- u_int flags;
+ unsigned int flags;
{
DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
@@ -389,8 +384,8 @@ smdb2_cursor_get(cursor, key, value, flags)
DBC *dbc = (DBC *) cursor->smdbc_impl;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
db2_flags = smdb_cursor_get_flags_to_db2(flags);
result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
@@ -413,8 +408,8 @@ smdb2_cursor_put(cursor, key, value, flags)
DBC *dbc = (DBC *) cursor->smdbc_impl;
DBT dbkey, dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.data = key->data;
dbkey.size = key->size;
dbdata.data = value->data;
@@ -467,7 +462,7 @@ smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
DB_INFO db_info;
params = NULL;
- memset(&db_info, '\0', sizeof db_info);
+ (void) memset(&db_info, '\0', sizeof db_info);
if (db_params != NULL)
{
db_info.db_cachesize = db_params->smdbp_cache_size;
@@ -537,7 +532,7 @@ smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
return db2_error_to_smdb(result);
}
# endif /* DB_VERSION_MAJOR > 2 */
- /*
+/*
** SMDB_DB_OPEN -- Opens a db database.
**
** Parameters:
@@ -576,7 +571,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params
SMDB_USER_INFO *user_info;
SMDB_DBPARAMS *db_params;
{
- bool lockcreated = FALSE;
+ bool lockcreated = false;
int result;
int db_flags;
int lock_fd;
@@ -604,7 +599,7 @@ smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params
if (stat_info.st_mode == ST_MODE_NOFILE &&
bitset(mode, O_CREAT))
- lockcreated = TRUE;
+ lockcreated = true;
result = smdb_lock_file(&lock_fd, db_name, mode, sff,
SMDB2_FILE_EXTENSION);
diff --git a/contrib/sendmail/libsmdb/smndbm.c b/contrib/sendmail/libsmdb/smndbm.c
index 47e5cb5..421b4bc 100644
--- a/contrib/sendmail/libsmdb/smndbm.c
+++ b/contrib/sendmail/libsmdb/smndbm.c
@@ -1,5 +1,5 @@
/*
-** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+** Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
** All rights reserved.
**
** By using this file, you agree to the terms and conditions set
@@ -7,9 +7,8 @@
** the sendmail distribution.
*/
-#ifndef lint
-static char id[] = "@(#)$Id: smndbm.c,v 8.40.4.3 2000/10/05 22:27:50 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: smndbm.c,v 8.50 2001/09/11 04:04:53 gshapiro Exp $")
#include <fcntl.h>
#include <stdlib.h>
@@ -38,7 +37,7 @@ struct smdb_dbm_cursor_struct
};
typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR;
- /*
+/*
** SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
**
** Parameters:
@@ -67,15 +66,9 @@ smdb_put_flags_to_ndbm_flags(flags)
return return_flags;
}
- /*
-** smdbm_malloc_database -- Create and initialize SMDB_DBM_DATABASE
-**
-** Parameters:
-** None
-**
-** Returns:
-** A pointer to an allocated SMDB_DBM_DATABASE or NULL
-**
+/*
+** Except for smdb_ndbm_open, the rest of these function correspond to the
+** interface laid out in smdb.h.
*/
SMDB_DBM_DATABASE *
@@ -88,17 +81,12 @@ smdbm_malloc_database()
{
db->smndbm_dbm = NULL;
db->smndbm_lock_fd = -1;
- db->smndbm_cursor_in_use = FALSE;
+ db->smndbm_cursor_in_use = false;
}
return db;
}
-/*
-** Except for smdb_ndbm_open, the rest of these function correspond to the
-** interface laid out in smdb.h.
-*/
-
int
smdbm_close(database)
SMDB_DATABASE *database;
@@ -120,13 +108,13 @@ int
smdbm_del(database, key, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
- u_int flags;
+ unsigned int flags;
{
int result;
DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
datum dbkey;
- memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
dbkey.dptr = key->data;
dbkey.dsize = key->size;
@@ -175,13 +163,13 @@ smdbm_get(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
datum dbkey, dbdata;
- memset(&dbkey, '\0', sizeof dbkey);
- memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
dbkey.dptr = key->data;
dbkey.dsize = key->size;
@@ -209,15 +197,15 @@ smdbm_put(database, key, data, flags)
SMDB_DATABASE *database;
SMDB_DBENT *key;
SMDB_DBENT *data;
- u_int flags;
+ unsigned int flags;
{
int result;
int save_errno;
DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
datum dbkey, dbdata;
- memset(&dbkey, '\0', sizeof dbkey);
- memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
dbkey.dptr = key->data;
dbkey.dsize = key->size;
dbdata.dptr = data->data;
@@ -282,7 +270,7 @@ smndbm_set_owner(database, uid, gid)
int
smdbm_sync(database, flags)
SMDB_DATABASE *database;
- u_int flags;
+ unsigned int flags;
{
return SMDBE_UNSUPPORTED;
}
@@ -297,7 +285,7 @@ smdbm_cursor_close(cursor)
if (!db->smndbm_cursor_in_use)
return SMDBE_NOT_A_VALID_CURSOR;
- db->smndbm_cursor_in_use = FALSE;
+ db->smndbm_cursor_in_use = false;
free(dbm_cursor);
free(cursor);
@@ -307,7 +295,7 @@ smdbm_cursor_close(cursor)
int
smdbm_cursor_del(cursor, flags)
SMDB_CURSOR *cursor;
- u_int flags;
+ unsigned int flags;
{
int result;
SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
@@ -343,8 +331,8 @@ smdbm_cursor_get(cursor, key, value, flags)
DBM *dbm = db->smndbm_dbm;
datum dbkey, dbdata;
- memset(&dbkey, '\0', sizeof dbkey);
- memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbkey, '\0', sizeof dbkey);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
if (flags == SMDB_CURSOR_GET_RANGE)
return SMDBE_UNSUPPORTED;
@@ -406,7 +394,7 @@ smdbm_cursor_put(cursor, key, value, flags)
DBM *dbm = db->smndbm_dbm;
datum dbdata;
- memset(&dbdata, '\0', sizeof dbdata);
+ (void) memset(&dbdata, '\0', sizeof dbdata);
dbdata.dptr = value->data;
dbdata.dsize = value->size;
@@ -448,7 +436,7 @@ smdbm_cursor(database, cursor, flags)
if (db->smndbm_cursor_in_use)
return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
- db->smndbm_cursor_in_use = TRUE;
+ db->smndbm_cursor_in_use = true;
dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR));
dbm_cursor->smndbmc_db = db;
dbm_cursor->smndbmc_current_key.dptr = NULL;
@@ -467,8 +455,7 @@ smdbm_cursor(database, cursor, flags)
return SMDBE_OK;
}
-
- /*
+/*
** SMDB_NDBM_OPEN -- Opens a ndbm database.
**
** Parameters:
@@ -481,8 +468,7 @@ smdbm_cursor(database, cursor, flags)
** Only SMDB_NDBM is supported.
** user_info -- Information on the user to use for file
** permissions.
-** db_params --
-** No params are supported.
+** db_params -- No params are supported.
**
** Returns:
** SMDBE_OK -- Success, otherwise errno:
diff --git a/contrib/sendmail/libsmutil/Makefile.m4 b/contrib/sendmail/libsmutil/Makefile.m4
index 93a344c..5348e33 100644
--- a/contrib/sendmail/libsmutil/Makefile.m4
+++ b/contrib/sendmail/libsmutil/Makefile.m4
@@ -1,12 +1,13 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`library', `libsmutil')
-define(`bldSOURCES', `debug.c errstring.c lockfile.c safefile.c snprintf.c strl.c ')
+define(`bldSOURCES', `debug.c err.c lockfile.c safefile.c snprintf.c cf.c ')
APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
bldPRODUCT_END
diff --git a/contrib/sendmail/libsmutil/cf.c b/contrib/sendmail/libsmutil/cf.c
new file mode 100644
index 0000000..a1f6ba4
--- /dev/null
+++ b/contrib/sendmail/libsmutil/cf.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sendmail.h>
+SM_RCSID("@(#)$Id: cf.c,v 8.16 2001/09/11 04:04:55 gshapiro Exp $")
+#include <sendmail/pathnames.h>
+
+/*
+** GETCFNAME -- return the name of the .cf file to use.
+**
+** Some systems (e.g., NeXT) determine this dynamically.
+**
+** For others: returns submit.cf or sendmail.cf depending
+** on the modes.
+**
+** Parameters:
+** opmode -- operation mode.
+** submitmode -- submit mode.
+** cftype -- may request a certain cf file.
+** conffile -- if set, return it.
+**
+** Returns:
+** name of .cf file.
+*/
+
+char *
+getcfname(opmode, submitmode, cftype, conffile)
+ int opmode;
+ int submitmode;
+ int cftype;
+ char *conffile;
+{
+
+ if (conffile != NULL)
+ return conffile;
+
+#if NETINFO
+ {
+ char *cflocation;
+
+ cflocation = ni_propval("/locations", NULL, "sendmail",
+ "sendmail.cf", '\0');
+ if (cflocation != NULL)
+ return cflocation;
+ }
+#endif /* NETINFO */
+
+ if (cftype == SM_GET_SUBMIT_CF ||
+ ((submitmode != SUBMIT_UNKNOWN ||
+ opmode == MD_DELIVER ||
+ opmode == MD_ARPAFTP ||
+ opmode == MD_SMTP) &&
+ cftype != SM_GET_SENDMAIL_CF))
+ {
+ struct stat sbuf;
+ static char cf[PATH_MAX];
+
+ (void) sm_strlcpyn(cf, sizeof cf, 2, _DIR_SENDMAILCF,
+ "submit.cf");
+ if (cftype == SM_GET_SUBMIT_CF || stat(cf, &sbuf) == 0)
+ return cf;
+ }
+ return _PATH_SENDMAILCF;
+}
diff --git a/contrib/sendmail/libsmutil/debug.c b/contrib/sendmail/libsmutil/debug.c
index bc32b66..2c3b328 100644
--- a/contrib/sendmail/libsmutil/debug.c
+++ b/contrib/sendmail/libsmutil/debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,33 +8,8 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: debug.c,v 8.2 1999/07/26 04:04:09 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-u_char tTdvect[100]; /* trace vector */
-
-#if _FFR_DPRINTF_
-void
-/*VARARGS1*/
-#ifdef __STDC__
-dprintf(const char *fmt, ...)
-#else /* __STDC__ */
-dprintf(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif /* __STDC__ */
-{
- VA_LOCAL_DECL;
-
- (void) vfprintf(stdout, fmt, ap);
-}
+SM_RCSID("@(#)$Id: debug.c,v 8.9 2001/09/11 04:04:55 gshapiro Exp $")
-int
-dflush()
-{
- return fflush(stdout);
-}
-#endif /* _FFR_DPRINTF_ */
+unsigned char tTdvect[100]; /* trace vector */
diff --git a/contrib/sendmail/libsmutil/err.c b/contrib/sendmail/libsmutil/err.c
new file mode 100644
index 0000000..0ad52a4
--- /dev/null
+++ b/contrib/sendmail/libsmutil/err.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sendmail.h>
+
+SM_RCSID("@(#)$Id: err.c,v 8.5 2001/09/11 04:04:55 gshapiro Exp $")
+
+#include <ctype.h>
+
+/*VARARGS1*/
+void
+#ifdef __STDC__
+message(const char *msg, ...)
+#else /* __STDC__ */
+message(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif /* __STDC__ */
+{
+ const char *m;
+ SM_VA_LOCAL_DECL
+
+ m = msg;
+ if (isascii(m[0]) && isdigit(m[0]) &&
+ isascii(m[1]) && isdigit(m[1]) &&
+ isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
+ m += 4;
+ SM_VA_START(ap, msg);
+ (void) vfprintf(stderr, m, ap);
+ SM_VA_END(ap);
+ (void) fprintf(stderr, "\n");
+}
+
+/*VARARGS1*/
+void
+#ifdef __STDC__
+syserr(const char *msg, ...)
+#else /* __STDC__ */
+syserr(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif /* __STDC__ */
+{
+ const char *m;
+ SM_VA_LOCAL_DECL
+
+ m = msg;
+ if (isascii(m[0]) && isdigit(m[0]) &&
+ isascii(m[1]) && isdigit(m[1]) &&
+ isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
+ m += 4;
+ SM_VA_START(ap, msg);
+ (void) vfprintf(stderr, m, ap);
+ SM_VA_END(ap);
+ (void) fprintf(stderr, "\n");
+}
diff --git a/contrib/sendmail/libsmutil/lockfile.c b/contrib/sendmail/libsmutil/lockfile.c
index 8c2dc6e..5eca360 100644
--- a/contrib/sendmail/libsmutil/lockfile.c
+++ b/contrib/sendmail/libsmutil/lockfile.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,13 +11,12 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: lockfile.c,v 8.3.16.11 2000/11/16 02:54:28 geir Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
- /*
+SM_RCSID("@(#)$Id: lockfile.c,v 8.19 2001/09/11 04:04:55 gshapiro Exp $")
+
+
+/*
** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
**
** Parameters:
@@ -30,8 +29,8 @@ static char id[] = "@(#)$Id: lockfile.c,v 8.3.16.11 2000/11/16 02:54:28 geir Exp
** LOCK_UN -- unlock.
**
** Returns:
-** TRUE if the lock was acquired.
-** FALSE otherwise.
+** true if the lock was acquired.
+** false otherwise.
*/
bool
@@ -59,7 +58,7 @@ lockfile(fd, filename, ext, type)
action = F_SETLKW;
if (fcntl(fd, action, &lfd) >= 0)
- return TRUE;
+ return true;
/*
** On SunOS, if you are testing using -oQ/tmp/mqueue or
@@ -71,14 +70,14 @@ lockfile(fd, filename, ext, type)
*/
if (errno == EINVAL)
- return TRUE;
+ return true;
#else /* !HASFLOCK */
if (flock(fd, type) >= 0)
- return TRUE;
+ return true;
#endif /* !HASFLOCK */
- return FALSE;
+ return false;
}
diff --git a/contrib/sendmail/libsmutil/safefile.c b/contrib/sendmail/libsmutil/safefile.c
index 3a757f3..c2e2102 100644
--- a/contrib/sendmail/libsmutil/safefile.c
+++ b/contrib/sendmail/libsmutil/safefile.c
@@ -11,14 +11,14 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: safefile.c,v 8.81.4.10 2001/07/20 04:19:36 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+#include <sm/io.h>
+#include <sm/errstring.h>
+
+SM_RCSID("@(#)$Id: safefile.c,v 8.121 2001/10/11 21:46:13 gshapiro Exp $")
- /*
+/*
** SAFEFILE -- return 0 if a file exists and is safe for a user.
**
** Parameters:
@@ -61,18 +61,18 @@ safefile(fn, uid, gid, user, flags, mode, st)
char fbuf[MAXPATHLEN + 1];
if (tTd(44, 4))
- dprintf("safefile(%s, uid=%d, gid=%d, flags=%lx, mode=%o):\n",
+ sm_dprintf("safefile(%s, uid=%d, gid=%d, flags=%lx, mode=%o):\n",
fn, (int) uid, (int) gid, flags, mode);
errno = 0;
- if (st == NULL)
- st = &fstbuf;
- if (strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf)
+ if (sm_strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf)
{
if (tTd(44, 4))
- dprintf("\tpathname too long\n");
+ sm_dprintf("\tpathname too long\n");
return ENAMETOOLONG;
}
fn = fbuf;
+ if (st == NULL)
+ st = &fstbuf;
/* ignore SFF_SAFEDIRPATH if we are debugging */
if (RealUid != 0 && RunAsUid == RealUid)
@@ -93,7 +93,7 @@ safefile(fn, uid, gid, user, flags, mode, st)
S_ISREG(st->st_mode))
{
/*
- ** If final file is setuid, run as the owner of that
+ ** If final file is set-user-ID, run as the owner of that
** file. Gotta be careful not to reveal anything too
** soon here!
*/
@@ -139,7 +139,7 @@ safefile(fn, uid, gid, user, flags, mode, st)
if (ret == 0)
{
/* directory is safe */
- checkpath = FALSE;
+ checkpath = false;
}
else
{
@@ -149,7 +149,7 @@ safefile(fn, uid, gid, user, flags, mode, st)
{
ret = errno;
if (tTd(44, 4))
- dprintf("\t%s\n", errstring(ret));
+ sm_dprintf("\t%s\n", sm_errstring(ret));
return ret;
}
# endif /* HASLSTAT */
@@ -188,7 +188,7 @@ safefile(fn, uid, gid, user, flags, mode, st)
char *dir = fn;
if (tTd(44, 4))
- dprintf("\t%s\n", errstring(ret));
+ sm_dprintf("\t%s\n", sm_errstring(ret));
errno = 0;
if (!bitset(SFF_CREAT, flags) || file_errno != ENOENT)
@@ -206,6 +206,7 @@ safefile(fn, uid, gid, user, flags, mode, st)
{
int md = S_IWRITE|S_IEXEC;
+ ret = 0;
if (stbuf.st_uid == uid)
/* EMPTY */
;
@@ -237,13 +238,15 @@ safefile(fn, uid, gid, user, flags, mode, st)
md >>= 3;
}
if ((stbuf.st_mode & md) != md)
- errno = EACCES;
+ ret = errno = EACCES;
}
- ret = errno;
+ else
+ ret = errno;
if (tTd(44, 4))
- dprintf("\t[final dir %s uid %d mode %lo] %s\n",
- dir, (int) stbuf.st_uid, (u_long) stbuf.st_mode,
- errstring(ret));
+ sm_dprintf("\t[final dir %s uid %d mode %lo] %s\n",
+ dir, (int) stbuf.st_uid,
+ (unsigned long) stbuf.st_mode,
+ sm_errstring(ret));
if (p != NULL)
*p = '/';
st->st_mode = ST_MODE_NOFILE;
@@ -254,46 +257,46 @@ safefile(fn, uid, gid, user, flags, mode, st)
if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n",
+ (unsigned long) st->st_mode);
return E_SM_NOSLINK;
}
# endif /* S_ISLNK */
if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n",
+ (unsigned long) st->st_mode);
return E_SM_REGONLY;
}
if (bitset(SFF_NOGWFILES, flags) &&
bitset(S_IWGRP, st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[write bits %lo]\tE_SM_GWFILE\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[write bits %lo]\tE_SM_GWFILE\n",
+ (unsigned long) st->st_mode);
return E_SM_GWFILE;
}
if (bitset(SFF_NOWWFILES, flags) &&
bitset(S_IWOTH, st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[write bits %lo]\tE_SM_WWFILE\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[write bits %lo]\tE_SM_WWFILE\n",
+ (unsigned long) st->st_mode);
return E_SM_WWFILE;
}
if (bitset(SFF_NOGRFILES, flags) && bitset(S_IRGRP, st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[read bits %lo]\tE_SM_GRFILE\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[read bits %lo]\tE_SM_GRFILE\n",
+ (unsigned long) st->st_mode);
return E_SM_GRFILE;
}
if (bitset(SFF_NOWRFILES, flags) && bitset(S_IROTH, st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[read bits %lo]\tE_SM_WRFILE\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[read bits %lo]\tE_SM_WRFILE\n",
+ (unsigned long) st->st_mode);
return E_SM_WRFILE;
}
if (!bitset(SFF_EXECOK, flags) &&
@@ -301,14 +304,14 @@ safefile(fn, uid, gid, user, flags, mode, st)
bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode))
{
if (tTd(44, 4))
- dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n",
- (u_long) st->st_mode);
+ sm_dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n",
+ (unsigned long) st->st_mode);
return E_SM_ISEXEC;
}
if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1)
{
if (tTd(44, 4))
- dprintf("\t[link count %d]\tE_SM_NOHLINK\n",
+ sm_dprintf("\t[link count %d]\tE_SM_NOHLINK\n",
(int) st->st_nlink);
return E_SM_NOHLINK;
}
@@ -348,23 +351,23 @@ safefile(fn, uid, gid, user, flags, mode, st)
mode >>= 3;
}
if (tTd(44, 4))
- dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ",
+ sm_dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ",
(int) st->st_uid, (int) st->st_nlink,
- (u_long) st->st_mode, (u_long) mode);
+ (unsigned long) st->st_mode, (unsigned long) mode);
if ((st->st_uid == uid || st->st_uid == 0 ||
st->st_uid == TrustedUid ||
!bitset(SFF_MUSTOWN, flags)) &&
(st->st_mode & mode) == mode)
{
if (tTd(44, 4))
- dprintf("\tOK\n");
+ sm_dprintf("\tOK\n");
return 0;
}
if (tTd(44, 4))
- dprintf("\tEACCES\n");
+ sm_dprintf("\tEACCES\n");
return EACCES;
}
- /*
+/*
** SAFEDIRPATH -- check to make sure a path to a directory is safe
**
** Safe means not writable and owned by the right folks.
@@ -410,19 +413,22 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
if (level > MAXSYMLINKS)
return ELOOP;
+ if (level < 0 || offset < 0 || offset > strlen(fn))
+ return EINVAL;
+
/* special case root directory */
if (*fn == '\0')
fn = "/";
if (tTd(44, 4))
- dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n",
+ sm_dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n",
fn, (long) uid, (long) gid, flags, level, offset);
if (!bitnset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail))
mode |= S_IWGRP;
/* Make a modifiable copy of the filename */
- if (strlcpy(s, fn, sizeof s) >= sizeof s)
+ if (sm_strlcpy(s, fn, sizeof s) >= sizeof s)
return EINVAL;
p = s + offset;
@@ -463,7 +469,7 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
continue;
if (tTd(44, 20))
- dprintf("\t[dir %s]\n", s);
+ sm_dprintf("\t[dir %s]\n", s);
# if HASLSTAT
ret = lstat(s, &stbuf);
@@ -537,25 +543,28 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
{
*sptr = '\0';
offset = sptr + 1 - s;
- if ((strlen(s) + 1 +
- strlen(buf) + 1) > sizeof fullbuf)
+ if (sm_strlcpyn(fullbuf,
+ sizeof fullbuf, 2,
+ s, "/") >=
+ sizeof fullbuf ||
+ sm_strlcat(fullbuf, buf,
+ sizeof fullbuf) >=
+ sizeof fullbuf)
{
ret = EINVAL;
break;
}
- snprintf(fullbuf, sizeof fullbuf,
- "%s/%s", s, buf);
*sptr = '/';
}
else
{
- if (strlen(buf) + 1 > sizeof fullbuf)
+ if (sm_strlcpy(fullbuf, buf,
+ sizeof fullbuf) >=
+ sizeof fullbuf)
{
ret = EINVAL;
break;
}
- (void) strlcpy(fullbuf, buf,
- sizeof fullbuf);
}
target = fullbuf;
}
@@ -577,8 +586,8 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
bitset(mode, stbuf.st_mode))
{
if (tTd(44, 4))
- dprintf("\t[dir %s] mode %lo ",
- s, (u_long) stbuf.st_mode);
+ sm_dprintf("\t[dir %s] mode %lo ",
+ s, (unsigned long) stbuf.st_mode);
if (bitset(SFF_SAFEDIRPATH, flags))
{
if (bitset(S_IWOTH, stbuf.st_mode))
@@ -586,11 +595,11 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
else
ret = E_SM_GWDIR;
if (tTd(44, 4))
- dprintf("FATAL\n");
+ sm_dprintf("FATAL\n");
break;
}
if (tTd(44, 4))
- dprintf("WARNING\n");
+ sm_dprintf("WARNING\n");
if (Verbose > 1)
message("051 WARNING: %s writable directory %s",
bitset(S_IWOTH, stbuf.st_mode)
@@ -643,11 +652,11 @@ safedirpath(fn, uid, gid, user, flags, level, offset)
}
}
if (tTd(44, 4))
- dprintf("\t[dir %s] %s\n", fn,
- ret == 0 ? "OK" : errstring(ret));
+ sm_dprintf("\t[dir %s] %s\n", fn,
+ ret == 0 ? "OK" : sm_errstring(ret));
return ret;
}
- /*
+/*
** SAFEOPEN -- do a file open with extra checking
**
** Parameters:
@@ -673,8 +682,8 @@ safeopen(fn, omode, cmode, sff)
struct stat stb;
if (tTd(44, 10))
- printf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n",
- fn, omode, cmode, sff);
+ sm_dprintf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n",
+ fn, omode, cmode, sff);
if (bitset(O_CREAT, omode))
sff |= SFF_CREAT;
@@ -730,7 +739,83 @@ safeopen(fn, omode, cmode, sff)
}
return fd;
}
- /*
+/*
+** SAFEFOPEN -- do a file open with extra checking
+**
+** Parameters:
+** fn -- the file name to open.
+** omode -- the open-style mode flags.
+** cmode -- the create-style mode flags.
+** sff -- safefile flags.
+**
+** Returns:
+** Same as fopen.
+*/
+
+SM_FILE_T *
+safefopen(fn, omode, cmode, sff)
+ char *fn;
+ int omode;
+ int cmode;
+ long sff;
+{
+ int fd;
+ int save_errno;
+ SM_FILE_T *fp;
+ int fmode;
+
+ switch (omode & O_ACCMODE)
+ {
+ case O_RDONLY:
+ fmode = SM_IO_RDONLY;
+ break;
+
+ case O_WRONLY:
+ if (bitset(O_APPEND, omode))
+ fmode = SM_IO_APPEND;
+ else
+ fmode = SM_IO_WRONLY;
+ break;
+
+ case O_RDWR:
+ if (bitset(O_TRUNC, omode))
+ fmode = SM_IO_RDWRTR;
+ else if (bitset(O_APPEND, omode))
+ fmode = SM_IO_APPENDRW;
+ else
+ fmode = SM_IO_RDWR;
+ break;
+
+ default:
+ syserr("554 5.3.5 safefopen: unknown omode %o", omode);
+ fmode = 0;
+ }
+ fd = safeopen(fn, omode, cmode, sff);
+ if (fd < 0)
+ {
+ save_errno = errno;
+ if (tTd(44, 10))
+ sm_dprintf("safefopen: safeopen failed: %s\n",
+ sm_errstring(errno));
+ errno = save_errno;
+ return NULL;
+ }
+ fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &fd, fmode, NULL);
+ if (fp != NULL)
+ return fp;
+
+ save_errno = errno;
+ if (tTd(44, 10))
+ {
+ sm_dprintf("safefopen: fdopen(%s, %d) failed: omode=%x, sff=%lx, err=%s\n",
+ fn, fmode, omode, sff, sm_errstring(errno));
+ }
+ (void) close(fd);
+ errno = save_errno;
+ return NULL;
+}
+/*
** FILECHANGED -- check to see if file changed after being opened
**
** Parameters:
@@ -739,8 +824,8 @@ safeopen(fn, omode, cmode, sff)
** stb -- stat structure from before open.
**
** Returns:
-** TRUE -- if a problem was detected.
-** FALSE -- if this file is still the same.
+** true -- if a problem was detected.
+** false -- if this file is still the same.
*/
bool
@@ -756,13 +841,13 @@ filechanged(fn, fd, stb)
# if HASLSTAT && BOGUS_O_EXCL
/* only necessary if exclusive open follows symbolic links */
if (lstat(fn, stb) < 0 || stb->st_nlink != 1)
- return TRUE;
+ return true;
# else /* HASLSTAT && BOGUS_O_EXCL */
- return FALSE;
+ return false;
# endif /* HASLSTAT && BOGUS_O_EXCL */
}
if (fstat(fd, &sta) < 0)
- return TRUE;
+ return true;
if (sta.st_nlink != stb->st_nlink ||
sta.st_dev != stb->st_dev ||
@@ -775,37 +860,29 @@ filechanged(fn, fd, stb)
{
if (tTd(44, 8))
{
- dprintf("File changed after opening:\n");
- dprintf(" nlink = %ld/%ld\n",
+ sm_dprintf("File changed after opening:\n");
+ sm_dprintf(" nlink = %ld/%ld\n",
(long) stb->st_nlink, (long) sta.st_nlink);
- dprintf(" dev = %ld/%ld\n",
+ sm_dprintf(" dev = %ld/%ld\n",
(long) stb->st_dev, (long) sta.st_dev);
- if (sizeof sta.st_ino > sizeof (long))
- {
- dprintf(" ino = %s/",
- quad_to_string(stb->st_ino));
- dprintf("%s\n",
- quad_to_string(sta.st_ino));
- }
- else
- dprintf(" ino = %lu/%lu\n",
- (unsigned long) stb->st_ino,
- (unsigned long) sta.st_ino);
+ sm_dprintf(" ino = %llu/%llu\n",
+ (ULONGLONG_T) stb->st_ino,
+ (ULONGLONG_T) sta.st_ino);
# if HAS_ST_GEN
- dprintf(" gen = %ld/%ld\n",
+ sm_dprintf(" gen = %ld/%ld\n",
(long) stb->st_gen, (long) sta.st_gen);
# endif /* HAS_ST_GEN */
- dprintf(" uid = %ld/%ld\n",
+ sm_dprintf(" uid = %ld/%ld\n",
(long) stb->st_uid, (long) sta.st_uid);
- dprintf(" gid = %ld/%ld\n",
+ sm_dprintf(" gid = %ld/%ld\n",
(long) stb->st_gid, (long) sta.st_gid);
}
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- /*
+/*
** DFOPEN -- determined file open
**
** This routine has the semantics of open, except that it will
diff --git a/contrib/sendmail/libsmutil/snprintf.c b/contrib/sendmail/libsmutil/snprintf.c
index 7a2aabc..ff3aa3b 100644
--- a/contrib/sendmail/libsmutil/snprintf.c
+++ b/contrib/sendmail/libsmutil/snprintf.c
@@ -11,380 +11,11 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: snprintf.c,v 8.27.16.4 2001/07/20 04:19:37 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
- /*
-** SNPRINTF, VSNPRINT -- counted versions of printf
-**
-** These versions have been grabbed off the net. They have been
-** cleaned up to compile properly and support for .precision and
-** %lx has been added.
-*/
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (sm_dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- **************************************************************/
-
-/*static char _id[] = "$OrigId: snprintf.c,v 1.2 1995/10/09 11:19:47 roberto Exp $";*/
-void sm_dopr();
-char *DoprEnd;
-int SnprfOverflow;
-
-#if !HASSNPRINTF && !SNPRINTF_IS_BROKEN
-# define sm_snprintf snprintf
-# ifndef luna2
-# define sm_vsnprintf vsnprintf
-extern int vsnprintf __P((char *, size_t, const char *, va_list));
-# endif /* ! luna2 */
-#endif /* !HASSNPRINTF && !SNPRINTF_IS_BROKEN */
-
-/* VARARGS3 */
-int
-# ifdef __STDC__
-sm_snprintf(char *str, size_t count, const char *fmt, ...)
-# else /* __STDC__ */
-sm_snprintf(str, count, fmt, va_alist)
- char *str;
- size_t count;
- const char *fmt;
- va_dcl
-# endif /* __STDC__ */
-{
- int len;
- VA_LOCAL_DECL
-
- VA_START(fmt);
- len = sm_vsnprintf(str, count, fmt, ap);
- VA_END;
- return len;
-}
-
-int
-sm_vsnprintf(str, count, fmt, args)
- char *str;
- size_t count;
- const char *fmt;
- va_list args;
-{
- str[0] = 0;
- DoprEnd = str + count - 1;
- SnprfOverflow = 0;
- sm_dopr( str, fmt, args );
- if (count > 0)
- DoprEnd[0] = 0;
- if (SnprfOverflow > 0 && tTd(57, 2))
- dprintf("\nvsnprintf overflow, len = %ld, str = %s",
- (long) count, shortenstring(str, MAXSHORTSTR));
- return strlen(str) + SnprfOverflow;
-}
+SM_RCSID("@(#)$Id: snprintf.c,v 8.44 2001/09/11 04:04:56 gshapiro Exp $")
/*
- * sm_dopr(): poor man's version of doprintf
- */
-
-void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
-void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
-void dostr __P(( char * , int ));
-char *output;
-void dopr_outch __P(( int c ));
-int SyslogErrno;
-
-void
-sm_dopr( buffer, format, args )
- char *buffer;
- const char *format;
- va_list args;
-{
- int ch;
- long value;
- int longflag = 0;
- int pointflag = 0;
- int maxwidth = 0;
- char *strvalue;
- int ljust;
- int len;
- int zpad;
-#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
- extern char *sys_errlist[];
- extern int sys_nerr;
-#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
-
-
- output = buffer;
- while( (ch = *format++) != '\0' ){
- switch( ch ){
- case '%':
- ljust = len = zpad = maxwidth = 0;
- longflag = pointflag = 0;
- nextch:
- ch = *format++;
- switch( ch ){
- case 0:
- dostr( "**end of format**" , 0);
- return;
- case '-': ljust = 1; goto nextch;
- case '0': /* set zero padding if len not set */
- if(len==0 && !pointflag) zpad = '0';
- /* FALLTHROUGH */
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9':
- if (pointflag)
- maxwidth = maxwidth*10 + ch - '0';
- else
- len = len*10 + ch - '0';
- goto nextch;
- case '*':
- if (pointflag)
- maxwidth = va_arg( args, int );
- else
- len = va_arg( args, int );
- goto nextch;
- case '.': pointflag = 1; goto nextch;
- case 'l': longflag = 1; goto nextch;
- case 'u': case 'U':
- /*fmtnum(value,base,dosign,ljust,len,zpad) */
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 10,0, ljust, len, zpad ); break;
- case 'o': case 'O':
- /*fmtnum(value,base,dosign,ljust,len,zpad) */
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 8,0, ljust, len, zpad ); break;
- case 'd': case 'D':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 10,1, ljust, len, zpad ); break;
- case 'x':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 16,0, ljust, len, zpad ); break;
- case 'X':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value,-16,0, ljust, len, zpad ); break;
- case 's':
- strvalue = va_arg( args, char *);
- if (maxwidth > 0 || !pointflag) {
- if (pointflag && len > maxwidth)
- len = maxwidth; /* Adjust padding */
- fmtstr( strvalue,ljust,len,zpad, maxwidth);
- }
- break;
- case 'c':
- ch = va_arg( args, int );
- dopr_outch( ch ); break;
- case 'm':
-#if HASSTRERROR
- dostr(strerror(SyslogErrno), 0);
-#else /* HASSTRERROR */
- if (SyslogErrno < 0 || SyslogErrno >= sys_nerr)
- {
- dostr("Error ", 0);
- fmtnum(SyslogErrno, 10, 0, 0, 0, 0);
- }
- else
- dostr((char *)sys_errlist[SyslogErrno], 0);
-#endif /* HASSTRERROR */
- break;
-
- case '%': dopr_outch( ch ); continue;
- default:
- dostr( "???????" , 0);
- }
- break;
- default:
- dopr_outch( ch );
- break;
- }
- }
- *output = 0;
-}
-
-void
-fmtstr( value, ljust, len, zpad, maxwidth )
- char *value;
- int ljust, len, zpad, maxwidth;
-{
- int padlen, strleng; /* amount to pad */
-
- if( value == 0 ){
- value = "<NULL>";
- }
- for( strleng = 0; value[strleng]; ++ strleng ); /* strlen */
- if (strleng > maxwidth && maxwidth)
- strleng = maxwidth;
- padlen = len - strleng;
- if( padlen < 0 ) padlen = 0;
- if( ljust ) padlen = -padlen;
- while( padlen > 0 ) {
- dopr_outch( ' ' );
- --padlen;
- }
- dostr( value, maxwidth );
- while( padlen < 0 ) {
- dopr_outch( ' ' );
- ++padlen;
- }
-}
-
-void
-fmtnum( value, base, dosign, ljust, len, zpad )
- long value;
- int base, dosign, ljust, len, zpad;
-{
- int signvalue = 0;
- unsigned long uvalue;
- char convert[20];
- int place = 0;
- int padlen = 0; /* amount to pad */
- int caps = 0;
-
- /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
- value, base, dosign, ljust, len, zpad )); */
- uvalue = value;
- if( dosign ){
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- }
- }
- if( base < 0 ){
- caps = 1;
- base = -base;
- }
- do{
- convert[place++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")
- [uvalue % (unsigned)base ];
- uvalue = (uvalue / (unsigned)base );
- }while(uvalue);
- convert[place] = 0;
- padlen = len - place;
- if( padlen < 0 ) padlen = 0;
- if( ljust ) padlen = -padlen;
- /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
- convert,place,signvalue,padlen)); */
- if( zpad && padlen > 0 ){
- if( signvalue ){
- dopr_outch( signvalue );
- --padlen;
- signvalue = 0;
- }
- while( padlen > 0 ){
- dopr_outch( zpad );
- --padlen;
- }
- }
- while( padlen > 0 ) {
- dopr_outch( ' ' );
- --padlen;
- }
- if( signvalue ) dopr_outch( signvalue );
- while( place > 0 ) dopr_outch( convert[--place] );
- while( padlen < 0 ){
- dopr_outch( ' ' );
- ++padlen;
- }
-}
-
-void
-dostr( str , cut)
- char *str;
- int cut;
-{
- if (cut) {
- while(*str && cut-- > 0) dopr_outch(*str++);
- } else {
- while(*str) dopr_outch(*str++);
- }
-}
-
-void
-dopr_outch( c )
- int c;
-{
-#if 0
- if( iscntrl(c) && c != '\n' && c != '\t' ){
- c = '@' + (c & 0x1F);
- if( DoprEnd == 0 || output < DoprEnd )
- *output++ = '^';
- }
-#endif /* 0 */
- if( DoprEnd == 0 || output < DoprEnd )
- *output++ = c;
- else
- SnprfOverflow++;
-}
-
- /*
-** QUAD_TO_STRING -- Convert a quad type to a string.
-**
-** Convert a quad type to a string. This must be done
-** separately as %lld/%qd are not supported by snprint()
-** and adding support would slow down systems which only
-** emulate the data type.
-**
-** Parameters:
-** value -- number to convert to a string.
-**
-** Returns:
-** pointer to a string.
-*/
-
-char *
-quad_to_string(value)
- QUAD_T value;
-{
- char *formatstr;
- static char buf[64];
-
- /*
- ** Use sprintf() instead of snprintf() since snprintf()
- ** does not support %qu or %llu. The buffer is large enough
- ** to hold the string so there is no danger of buffer
- ** overflow.
- */
-
-#if NEED_PERCENTQ
- formatstr = "%qu";
-#else /* NEED_PERCENTQ */
- formatstr = "%llu";
-#endif /* NEED_PERCENTQ */
- sprintf(buf, formatstr, value);
- return buf;
-}
- /*
** SHORTENSTRING -- return short version of a string
**
** If the string is already short, just return it. If it is too
@@ -401,9 +32,9 @@ quad_to_string(value)
char *
shortenstring(s, m)
register const char *s;
- int m;
+ size_t m;
{
- int l;
+ size_t l;
static char buf[MAXSHORTSTR + 1];
l = strlen(s);
@@ -415,16 +46,15 @@ shortenstring(s, m)
{
if (m < 5)
{
- (void) strlcpy(buf, s, m + 1);
+ (void) sm_strlcpy(buf, s, m + 1);
return buf;
}
- (void) strlcpy(buf, s, m - 2);
- (void) strlcat(buf, "...", sizeof buf);
+ (void) sm_strlcpy(buf, s, m - 2);
+ (void) sm_strlcat(buf, "...", sizeof buf);
return buf;
}
m = (m - 3) / 2;
- (void) strlcpy(buf, s, m + 1);
- (void) strlcat(buf, "...", sizeof buf);
- (void) strlcat(buf, s + l - m, sizeof buf);
+ (void) sm_strlcpy(buf, s, m + 1);
+ (void) sm_strlcat2(buf, "...", s + l - m, sizeof buf);
return buf;
}
diff --git a/contrib/sendmail/mail.local/Makefile.m4 b/contrib/sendmail/mail.local/Makefile.m4
index 516850f..63a81a2 100644
--- a/contrib/sendmail/mail.local/Makefile.m4
+++ b/contrib/sendmail/mail.local/Makefile.m4
@@ -1,14 +1,15 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `mail.local')
-define(`bldNO_INSTALL')
+define(`bldNO_INSTALL', `true')
define(`bldSOURCES', `mail.local.c ')
-bldPUSH_SMLIB(`smutil')
+bldPUSH_SMLIB(`sm')
bldPRODUCT_END
bldPRODUCT_START(`manpage', `mail.local')
diff --git a/contrib/sendmail/mail.local/README b/contrib/sendmail/mail.local/README
index 56dac40..651de4b 100644
--- a/contrib/sendmail/mail.local/README
+++ b/contrib/sendmail/mail.local/README
@@ -2,8 +2,8 @@ This directory contains the source files for mail.local.
This is not intended to be used on *stock* System V derived systems such as
Solaris or HP-UX, since they use a totally different approach to mailboxes
-(essentially, they have a setgid program rather than setuid, and they rely
-on the ability to "give away" files to do their work).
+(essentially, they have a set-group-ID program rather than set-user-ID, and
+they rely on the ability to "give away" files to do their work).
If you choose to run *this* mail.local on these systems then you may also
need to replace the existing MUAs, as well as IMAP and POP servers, with
@@ -29,11 +29,11 @@ your site.config.m4 file with:
APPENDDEF(`conf_mail_local_ENVDEF', `-DMAILGID=6')
-mail.local will not be installed setuid root. To use it as local
+mail.local will not be installed set-user-ID root. To use it as local
delivery agent without LMTP mode, use:
MODIFY_MAILER_FLAGS(`LOCAL', `+S')
in the .mc file.
-$Revision: 8.8 $, Last updated $Date: 1999/09/10 01:49:41 $
+$Revision: 8.10 $, Last updated $Date: 2001/09/08 01:21:04 $
diff --git a/contrib/sendmail/mail.local/mail.local.8 b/contrib/sendmail/mail.local/mail.local.8
index 939d772..5cd1c13 100644
--- a/contrib/sendmail/mail.local/mail.local.8
+++ b/contrib/sendmail/mail.local/mail.local.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -8,18 +8,22 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: mail.local.8,v 8.14.14.5 2000/12/29 18:12:16 gshapiro Exp $
+.\" $Id: mail.local.8,v 8.23 2001/04/05 23:27:35 gshapiro Exp $
.\"
-.TH MAIL.LOCAL 8 "$Date: 2000/12/29 18:12:16 $"
+.TH MAIL.LOCAL 8 "$Date: 2001/04/05 23:27:35 $"
.SH NAME
mail.local
\- store mail in a mailbox
.SH SYNOPSIS
.B mail.local
-.RB [ \-7 "] [" \-b "] [" \-d "] [" \-l "] [" \-f
-.IR from "] "
-.RB [ \-r
-.IR from "] " "user ..."
+.RB [ \-7 "] [" \-b "] [" \-d "] [" \-D
+.IR mbdb ]
+.RB [ \-l "] [" \-f
+\fIfrom\fR|\fB\-r\fR
+.IR from ]
+.RB [ \-h
+\fIfilename\fR ]
+.I "user ..."
.SH DESCRIPTION
.B Mail.local
reads the standard input up to an end-of-file and appends it to each
@@ -40,6 +44,12 @@ if a mailbox exceeds quota.
.TP
.B \-d
Specify this is a delivery (for backward compatibility).
+This option has no effect.
+.TP
+.BI \-D " mbdb"
+Specify the name of the mailbox database
+which is used to look up local recipient names.
+This option defaults to "pw", which means use getpwnam().
.TP
.BI \-f " from"
Specify the sender's name.
@@ -49,6 +59,11 @@ Turn on LMTP mode.
.TP
.BI \-r " from"
Specify the sender's name (for backward compatibility).
+Same as \-f.
+.TP
+.BI \-h " filename"
+Store incoming mail in \fIfilename\fR in the user's home directory instead
+of a system mail spool directory.
.PP
Individual mail messages in the mailbox are delimited by an empty
line followed by a line beginning with the string ``From ''.
@@ -86,10 +101,10 @@ Used to set the appropriate time zone on the timestamp.
temporary files
.TP
/var/mail/user
-user's mailbox directory
+user's default mailbox directory
.TP
/var/mail/user.lock
-lock file for a user's mailbox
+lock file for a user's default mailbox
.PD
.SH SEE ALSO
mail(1),
diff --git a/contrib/sendmail/mail.local/mail.local.c b/contrib/sendmail/mail.local/mail.local.c
index cd96c5e..8a93f01 100644
--- a/contrib/sendmail/mail.local/mail.local.c
+++ b/contrib/sendmail/mail.local/mail.local.c
@@ -10,232 +10,111 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1990, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
+
+SM_IDSTR(id, "@(#)$Id: mail.local.c,v 8.235 2001/12/30 04:59:39 gshapiro Exp $")
-#ifndef lint
-static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.58 2001/06/01 05:33:31 gshapiro Exp $";
-#endif /* ! lint */
+#include <stdlib.h>
+#include <sm/errstring.h>
+#include <sm/io.h>
+#include <sm/limits.h>
+# include <unistd.h>
+# ifdef EX_OK
+# undef EX_OK /* unistd.h may have another use for this */
+# endif /* EX_OK */
+#include <sm/mbdb.h>
+#include <sm/sysexits.h>
/*
** This is not intended to work on System V derived systems
** such as Solaris or HP-UX, since they use a totally different
-** approach to mailboxes (essentially, they have a setgid program
-** rather than setuid, and they rely on the ability to "give away"
+** approach to mailboxes (essentially, they have a set-group-ID program
+** rather than set-user-ID, and they rely on the ability to "give away"
** files to do their work). IT IS NOT A BUG that this doesn't
** work on such architectures.
*/
-/* additional mode for open() */
-# define EXTRA_MODE 0
-
-# include <sys/types.h>
-# include <sys/param.h>
-# include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <stdlib.h>
# include <sys/socket.h>
# include <sys/file.h>
-
# include <netinet/in.h>
# include <arpa/nameser.h>
-
-# include <fcntl.h>
# include <netdb.h>
-# include <pwd.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <string.h>
-# include <syslog.h>
-# include <time.h>
-# include <unistd.h>
-# ifdef EX_OK
-# undef EX_OK /* unistd.h may have another use for this */
-# endif /* EX_OK */
-# include <sysexits.h>
-# include <ctype.h>
+# include <pwd.h>
-# ifndef __P
-# include "sendmail/cdefs.h"
-# endif /* ! __P */
-# include "sendmail/useful.h"
-
-extern size_t strlcpy __P((char *, const char *, size_t));
-extern size_t strlcat __P((char *, const char *, size_t));
-
-# if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# ifndef HASSTRERROR
-# define HASSTRERROR 1
-# endif /* ! HASSTRERROR */
-# endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
-
-# include "sendmail/errstring.h"
-
-# ifndef LOCKTO_RM
-# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
-# endif /* ! LOCKTO_RM */
-# ifndef LOCKTO_GLOB
-# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
-# endif /* ! LOCKTO_GLOB */
-
-# ifdef __STDC__
-# include <stdarg.h>
-# define REALLOC(ptr, size) realloc(ptr, size)
-# else /* __STDC__ */
-# include <varargs.h>
-/* define a realloc() which works for NULL pointers */
-# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
-# endif /* __STDC__ */
-
-# if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
-# define USE_LOCKF 1
-# define USE_SETEUID 1
-# define _PATH_MAILDIR "/var/mail"
-# endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
-
-# ifdef NCR_MP_RAS3
-# define USE_LOCKF 1
-# define HASSNPRINTF 1
-# define _PATH_MAILDIR "/var/mail"
-# endif /* NCR_MP_RAS3 */
-
-# if defined(_AIX)
-# define USE_LOCKF 1
-# define USE_SETEUID 1
-# endif /* defined(_AIX) */
-
-# if defined(__hpux)
-# define USE_LOCKF 1
-# define USE_SETRESUID 1
-# endif /* defined(__hpux) */
-
-# ifdef DGUX
-# define HASSNPRINTF 1
-# define USE_LOCKF 1
-# endif /* DGUX */
-
-# if defined(_CRAY)
-# if !defined(MAXPATHLEN)
-# define MAXPATHLEN PATHSIZE
-# endif /* !defined(MAXPATHLEN) */
-# define _PATH_MAILDIR "/usr/spool/mail"
-# endif /* defined(_CRAY) */
-
-# if defined(NeXT) && !defined(__APPLE__)
-# include <libc.h>
-# define _PATH_MAILDIR "/usr/spool/mail"
-# define S_IRUSR S_IREAD
-# define S_IWUSR S_IWRITE
-# endif /* defined(NeXT) && !defined(__APPLE__) */
-
-# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# include <paths.h>
-# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
+#include <sm/string.h>
+#include <syslog.h>
+#include <ctype.h>
-/*
- * If you don't have flock, you could try using lockf instead.
- */
+#include <sm/conf.h>
+#include <sendmail/pathnames.h>
-# ifdef USE_LOCKF
-# define flock(a, b) lockf(a, b, 0)
-# ifdef LOCK_EX
-# undef LOCK_EX
-# endif /* LOCK_EX */
-# define LOCK_EX F_LOCK
-# endif /* USE_LOCKF */
-
-# ifndef LOCK_EX
-# include <sys/file.h>
-# endif /* ! LOCK_EX */
-
-# if defined(BSD4_4) || defined(__GLIBC__)
-# include <paths.h>
-# define _PATH_LOCTMP "/tmp/local.XXXXXX"
-# endif /* defined(BSD4_4) || defined(__GLIBC__) */
-
-# ifdef BSD4_4
-# define HAS_ST_GEN 1
-# else /* BSD4_4 */
-# ifndef _BSD_VA_LIST_
-# define _BSD_VA_LIST_ va_list
-# endif /* ! _BSD_VA_LIST_ */
-# endif /* BSD4_4 */
-
-# if defined(BSD4_4) || defined(linux)
-# define HASSNPRINTF 1
-# else /* defined(BSD4_4) || defined(linux) */
-# ifndef ultrix
-extern FILE *fdopen __P((int, const char *));
-# endif /* ! ultrix */
-# endif /* defined(BSD4_4) || defined(linux) */
-
-# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
-# define CONTENTLENGTH 1 /* Needs the Content-Length header */
-# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
-
-# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
-# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
-
-# ifdef HPUX11
-# define HASSNPRINTF 1 /* has snprintf starting in 11.X */
-# endif /* HPUX11 */
-
-# if _AIX4 >= 40300
-# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
-# endif /* _AIX4 >= 40300 */
-
-# if !HASSNPRINTF && !SFIO
-extern int snprintf __P((char *, size_t, const char *, ...));
-# ifndef _CRAY
-extern int vsnprintf __P((char *, size_t, const char *, ...));
-# endif /* ! _CRAY */
-# endif /* !HASSNPRINTF && !SFIO */
-/*
-** If you don't have setreuid, and you have saved uids, and you have
-** a seteuid() call that doesn't try to emulate using setuid(), then
-** you can try defining USE_SETEUID.
-*/
+/* additional mode for open() */
+# define EXTRA_MODE 0
+
-# ifdef USE_SETEUID
-# define setreuid(r, e) seteuid(e)
-# endif /* USE_SETEUID */
+#ifndef LOCKTO_RM
+# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
+#endif /* ! LOCKTO_RM */
+#ifndef LOCKTO_GLOB
+# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
+#endif /* ! LOCKTO_GLOB */
+
+/* define a realloc() which works for NULL pointers */
+#define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
/*
-** And of course on hpux you have setresuid()
+** If you don't have flock, you could try using lockf instead.
*/
-# ifdef USE_SETRESUID
-# define setreuid(r, e) setresuid(-1, e, -1)
-# endif /* USE_SETRESUID */
+#ifdef LDA_USE_LOCKF
+# define flock(a, b) lockf(a, b, 0)
+# ifdef LOCK_EX
+# undef LOCK_EX
+# endif /* LOCK_EX */
+# define LOCK_EX F_LOCK
+#endif /* LDA_USE_LOCKF */
-# ifndef _PATH_LOCTMP
-# define _PATH_LOCTMP "/tmp/local.XXXXXX"
-# endif /* ! _PATH_LOCTMP */
-# ifndef _PATH_MAILDIR
-# define _PATH_MAILDIR "/var/spool/mail"
-# endif /* ! _PATH_MAILDIR */
+#ifndef LOCK_EX
+# include <sys/file.h>
+#endif /* ! LOCK_EX */
-# ifndef S_ISREG
-# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
-# endif /* ! S_ISREG */
+/*
+** If you don't have setreuid, and you have saved uids, and you have
+** a seteuid() call that doesn't try to emulate using setuid(), then
+** you can try defining LDA_USE_SETEUID.
+*/
-# ifdef MAILLOCK
-# include <maillock.h>
-# endif /* MAILLOCK */
+#ifdef LDA_USE_SETEUID
+# define setreuid(r, e) seteuid(e)
+#endif /* LDA_USE_SETEUID */
-# define U_UID pw->pw_uid
-# define U_GID pw->pw_gid
+#ifdef LDA_CONTENTLENGTH
+# define CONTENTLENGTH 1
+#endif /* LDA_CONTENTLENGTH */
#ifndef INADDRSZ
# define INADDRSZ 4 /* size of an IPv4 address in bytes */
#endif /* ! INADDRSZ */
+#ifdef MAILLOCK
+# include <maillock.h>
+#endif /* MAILLOCK */
+
#ifndef MAILER_DAEMON
# define MAILER_DAEMON "MAILER-DAEMON"
#endif /* ! MAILER_DAEMON */
@@ -246,17 +125,18 @@ off_t HeaderLength;
off_t BodyLength;
#endif /* CONTENTLENGTH */
-bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */
+bool EightBitMime = true; /* advertise 8BITMIME in LMTP */
char ErrBuf[10240]; /* error buffer */
int ExitVal = EX_OK; /* sysexits.h error value. */
-bool HoldErrs = FALSE; /* Hold errors in ErrBuf */
-bool LMTPMode = FALSE;
-bool BounceQuota = FALSE; /* permanent error when over quota */
+bool HoldErrs = false; /* Hold errors in ErrBuf */
+bool LMTPMode = false;
+bool BounceQuota = false; /* permanent error when over quota */
+char *HomeMailFile = NULL; /* store mail in homedir */
void deliver __P((int, char *));
int e_to_sys __P((int));
void notifybiff __P((char *));
-int store __P((char *, int, bool *));
+int store __P((char *, bool *));
void usage __P((void));
int lockmbox __P((char *));
void unlockmbox __P((void));
@@ -273,6 +153,8 @@ main(argc, argv)
int ch, fd;
uid_t uid;
char *from;
+ char *mbdbname = "pw";
+ int err;
extern char *optarg;
extern int optind;
@@ -291,21 +173,25 @@ main(argc, argv)
# endif /* LOG_MAIL */
from = NULL;
- while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1)
+ while ((ch = getopt(argc, argv, "7bdD:f:h:r:l")) != -1)
{
switch(ch)
{
case '7': /* Do not advertise 8BITMIME */
- EightBitMime = FALSE;
+ EightBitMime = false;
break;
case 'b': /* bounce mail when over quota. */
- BounceQuota = TRUE;
+ BounceQuota = true;
break;
case 'd': /* Backward compatible. */
break;
+ case 'D': /* mailbox database type */
+ mbdbname = optarg;
+ break;
+
case 'f':
case 'r': /* Backward compatible. */
if (from != NULL)
@@ -316,8 +202,18 @@ main(argc, argv)
from = optarg;
break;
+ case 'h':
+ if (optarg != NULL || *optarg != '\0')
+ HomeMailFile = optarg;
+ else
+ {
+ mailerr(NULL, "-h: missing filename");
+ usage();
+ }
+ break;
+
case 'l':
- LMTPMode = TRUE;
+ LMTPMode = true;
break;
case '?':
@@ -331,6 +227,19 @@ main(argc, argv)
/* initialize biff structures */
notifybiff(NULL);
+ err = sm_mbdb_initialize(mbdbname);
+ if (err != EX_OK)
+ {
+ char *errcode = "521";
+
+ if (err == EX_TEMPFAIL)
+ errcode = "421";
+
+ mailerr(errcode, "Can not open mailbox database %s: %s",
+ mbdbname, sm_strexit(err));
+ exit(err);
+ }
+
if (LMTPMode)
{
extern void dolmtp __P((void));
@@ -357,7 +266,6 @@ main(argc, argv)
*/
uid = getuid();
-
if (from == NULL && ((from = getlogin()) == NULL ||
(pw = getpwnam(from)) == NULL ||
pw->pw_uid != uid))
@@ -373,9 +281,9 @@ main(argc, argv)
** at the expense of repeated failures and multiple deliveries.
*/
- HoldErrs = TRUE;
- fd = store(from, 0, NULL);
- HoldErrs = FALSE;
+ HoldErrs = true;
+ fd = store(from, NULL);
+ HoldErrs = false;
if (fd < 0)
{
flush_error();
@@ -467,6 +375,8 @@ parseaddr(s, rcpt)
s = MAILER_DAEMON;
l = strlen(s) + 1;
+ if (l < 0)
+ return NULL;
p = malloc(l);
if (p == NULL)
{
@@ -474,7 +384,7 @@ parseaddr(s, rcpt)
exit(EX_TEMPFAIL);
}
- (void) strlcpy(p, s, l);
+ (void) sm_strlcpy(p, s, l);
return p;
}
@@ -482,9 +392,22 @@ char *
process_recipient(addr)
char *addr;
{
- if (getpwnam(addr) == NULL)
+ SM_MBDB_T user;
+
+ switch (sm_mbdb_lookup(addr, &user))
+ {
+ case EX_OK:
+ return NULL;
+
+ case EX_NOUSER:
return "550 5.1.1 User unknown";
- return NULL;
+
+ case EX_TEMPFAIL:
+ return "451 4.3.0 User database failure; retry later";
+
+ default:
+ return "550 5.3.0 User database failure";
+ }
}
#define RCPT_GROW 30
@@ -496,7 +419,7 @@ dolmtp()
char **rcpt_addr = NULL;
int rcpt_num = 0;
int rcpt_alloc = 0;
- bool gotlhlo = FALSE;
+ bool gotlhlo = false;
char *err;
int msgfd;
char *p;
@@ -507,7 +430,7 @@ dolmtp()
memset(myhostname, '\0', sizeof myhostname);
(void) gethostname(myhostname, sizeof myhostname - 1);
if (myhostname[0] == '\0')
- strlcpy(myhostname, "localhost", sizeof myhostname);
+ sm_strlcpy(myhostname, "localhost", sizeof myhostname);
printf("220 %s LMTP ready\r\n", myhostname);
for (;;)
@@ -525,18 +448,18 @@ dolmtp()
{
case 'd':
case 'D':
- if (strcasecmp(buf, "data") == 0)
+ if (sm_strcasecmp(buf, "data") == 0)
{
- bool inbody = FALSE;
+ bool inbody = false;
if (rcpt_num == 0)
{
mailerr("503 5.5.1", "No recipients");
continue;
}
- HoldErrs = TRUE;
- msgfd = store(return_path, rcpt_num, &inbody);
- HoldErrs = FALSE;
+ HoldErrs = true;
+ msgfd = store(return_path, &inbody);
+ HoldErrs = false;
if (msgfd < 0 && !inbody)
{
flush_error();
@@ -566,7 +489,7 @@ dolmtp()
case 'l':
case 'L':
- if (strncasecmp(buf, "lhlo ", 5) == 0)
+ if (sm_strncasecmp(buf, "lhlo ", 5) == 0)
{
/* check for duplicate per RFC 1651 4.2 */
if (gotlhlo)
@@ -575,7 +498,7 @@ dolmtp()
myhostname);
continue;
}
- gotlhlo = TRUE;
+ gotlhlo = true;
printf("250-%s\r\n", myhostname);
if (EightBitMime)
printf("250-8BITMIME\r\n");
@@ -589,7 +512,7 @@ dolmtp()
case 'm':
case 'M':
- if (strncasecmp(buf, "mail ", 5) == 0)
+ if (sm_strncasecmp(buf, "mail ", 5) == 0)
{
if (return_path != NULL)
{
@@ -597,9 +520,9 @@ dolmtp()
"Nested MAIL command");
continue;
}
- if (strncasecmp(buf+5, "from:", 5) != 0 ||
+ if (sm_strncasecmp(buf+5, "from:", 5) != 0 ||
((return_path = parseaddr(buf + 10,
- FALSE)) == NULL))
+ false)) == NULL))
{
mailerr("501 5.5.4",
"Syntax error in parameters");
@@ -614,7 +537,7 @@ dolmtp()
case 'n':
case 'N':
- if (strcasecmp(buf, "noop") == 0)
+ if (sm_strcasecmp(buf, "noop") == 0)
{
printf("250 2.0.0 Ok\r\n");
continue;
@@ -625,7 +548,7 @@ dolmtp()
case 'q':
case 'Q':
- if (strcasecmp(buf, "quit") == 0)
+ if (sm_strcasecmp(buf, "quit") == 0)
{
printf("221 2.0.0 Bye\r\n");
exit(EX_OK);
@@ -636,7 +559,7 @@ dolmtp()
case 'r':
case 'R':
- if (strncasecmp(buf, "rcpt ", 5) == 0)
+ if (sm_strncasecmp(buf, "rcpt ", 5) == 0)
{
if (return_path == NULL)
{
@@ -658,9 +581,9 @@ dolmtp()
exit(EX_TEMPFAIL);
}
}
- if (strncasecmp(buf + 5, "to:", 3) != 0 ||
+ if (sm_strncasecmp(buf + 5, "to:", 3) != 0 ||
((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
- TRUE)) == NULL))
+ true)) == NULL))
{
mailerr("501 5.5.4",
"Syntax error in parameters");
@@ -676,7 +599,7 @@ dolmtp()
printf("250 2.1.5 Ok\r\n");
continue;
}
- else if (strcasecmp(buf, "rset") == 0)
+ else if (sm_strcasecmp(buf, "rset") == 0)
{
printf("250 2.0.0 Ok\r\n");
@@ -694,7 +617,7 @@ rset:
case 'v':
case 'V':
- if (strncasecmp(buf, "vrfy ", 5) == 0)
+ if (sm_strncasecmp(buf, "vrfy ", 5) == 0)
{
printf("252 2.3.3 Try RCPT to attempt delivery\r\n");
continue;
@@ -714,25 +637,24 @@ rset:
}
int
-store(from, lmtprcpts, inbody)
+store(from, inbody)
char *from;
- int lmtprcpts;
bool *inbody;
{
FILE *fp = NULL;
time_t tval;
- bool eline;
- bool fullline = TRUE; /* current line is terminated */
+ bool eline; /* previous line was empty */
+ bool fullline = true; /* current line is terminated */
bool prevfl; /* previous line was terminated */
char line[2048];
int fd;
char tmpbuf[sizeof _PATH_LOCTMP + 1];
if (inbody != NULL)
- *inbody = FALSE;
+ *inbody = false;
(void) umask(0077);
- (void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
+ (void) sm_strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL)
{
mailerr("451 4.3.0", "Unable to open temporary file");
@@ -746,7 +668,7 @@ store(from, lmtprcpts, inbody)
(void) fflush(stdout);
}
if (inbody != NULL)
- *inbody = TRUE;
+ *inbody = true;
(void) time(&tval);
(void) fprintf(fp, "From %s %s", from, ctime(&tval));
@@ -757,7 +679,7 @@ store(from, lmtprcpts, inbody)
#endif /* CONTENTLENGTH */
line[0] = '\0';
- eline = TRUE;
+ eline = true;
while (fgets(line, sizeof(line), stdin) != (char *) NULL)
{
size_t line_len = 0;
@@ -779,7 +701,7 @@ store(from, lmtprcpts, inbody)
}
/* Check to see if we have the full line from fgets() */
- fullline = FALSE;
+ fullline = false;
if (line_len > 0)
{
if (line[line_len - 1] == '\n')
@@ -791,7 +713,7 @@ store(from, lmtprcpts, inbody)
line[line_len - 1] = '\0';
line_len--;
}
- fullline = TRUE;
+ fullline = true;
}
else if (line[line_len - 1] == '\r')
{
@@ -800,19 +722,19 @@ store(from, lmtprcpts, inbody)
if (peek == '\n')
{
line[line_len - 1] = '\n';
- fullline = TRUE;
+ fullline = true;
}
else
(void) ungetc(peek, stdin);
}
}
else
- fullline = TRUE;
+ fullline = true;
#ifdef CONTENTLENGTH
if (prevfl && line[0] == '\n' && HeaderLength == 0)
{
- eline = FALSE;
+ eline = false;
if (fp != NULL)
HeaderLength = ftell(fp);
if (HeaderLength <= 0)
@@ -827,7 +749,7 @@ store(from, lmtprcpts, inbody)
}
#else /* CONTENTLENGTH */
if (prevfl && line[0] == '\n')
- eline = TRUE;
+ eline = true;
#endif /* CONTENTLENGTH */
else
{
@@ -835,12 +757,12 @@ store(from, lmtprcpts, inbody)
fp != NULL &&
!memcmp(line, "From ", 5))
(void) putc('>', fp);
- eline = FALSE;
+ eline = false;
#ifdef CONTENTLENGTH
/* discard existing "Content-Length:" headers */
if (prevfl && HeaderLength == 0 &&
(line[0] == 'C' || line[0] == 'c') &&
- strncasecmp(line, ContentHdr, 15) == 0)
+ sm_strncasecmp(line, ContentHdr, 15) == 0)
{
/*
** be paranoid: clear the line
@@ -895,15 +817,10 @@ store(from, lmtprcpts, inbody)
if (HeaderLength > 0 && BodyLength >= 0)
{
- extern char *quad_to_string();
-
- if (sizeof BodyLength > sizeof(long))
- snprintf(line, sizeof line, "%s\n",
- quad_to_string(BodyLength));
- else
- snprintf(line, sizeof line, "%ld\n",
- (long) BodyLength);
- strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16);
+ (void) sm_snprintf(line, sizeof line, "%lld\n",
+ (LONGLONG_T) BodyLength);
+ (void) sm_strlcpy(&ContentHdr[16], line,
+ sizeof(ContentHdr) - 16);
}
else
BodyLength = -1; /* Something is wrong here */
@@ -930,9 +847,9 @@ deliver(fd, name)
{
struct stat fsb;
struct stat sb;
- struct passwd *pw;
char path[MAXPATHLEN];
int mbfd = -1, nr = 0, nw, off;
+ int exitval;
char *p;
char *errcode;
off_t curoff;
@@ -941,26 +858,42 @@ deliver(fd, name)
int readamount;
#endif /* CONTENTLENGTH */
char biffmsg[100], buf[8*1024];
- extern char *quad_to_string();
-
+ SM_MBDB_T user;
/*
** Disallow delivery to unknown names -- special mailboxes can be
** handled in the sendmail aliases file.
*/
- if ((pw = getpwnam(name)) == NULL)
+ exitval = sm_mbdb_lookup(name, &user);
+ switch (exitval)
{
- if (ExitVal == EX_TEMPFAIL)
- errcode = "451 4.3.0";
- else
- {
- ExitVal = EX_UNAVAILABLE;
- errcode = "550 5.1.1";
- }
- mailerr(errcode, "Unknown name: %s", name);
+ case EX_OK:
+ break;
+
+ case EX_NOUSER:
+ exitval = EX_UNAVAILABLE;
+ mailerr("550 5.1.1", "%s: User unknown", name);
+ break;
+
+ case EX_TEMPFAIL:
+ mailerr("451 4.3.0", "%s: User database failure; retry later",
+ name);
+ break;
+
+ default:
+ exitval = EX_UNAVAILABLE;
+ mailerr("550 5.3.0", "%s: User database failure", name);
+ break;
+ }
+
+ if (exitval != EX_OK)
+ {
+ if (ExitVal != EX_TEMPFAIL)
+ ExitVal = exitval;
return;
}
+
endpwent();
/*
@@ -982,7 +915,29 @@ deliver(fd, name)
}
- (void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
+ if (HomeMailFile == NULL)
+ {
+ if (sm_snprintf(path, sizeof(path), "%s/%s",
+ _PATH_MAILDIR, name) >= sizeof(path))
+ {
+ exitval = EX_UNAVAILABLE;
+ mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
+ return;
+ }
+ }
+ else if (*user.mbdb_homedir == '\0')
+ {
+ exitval = EX_UNAVAILABLE;
+ mailerr("550 5.1.1", "%s: User missing home directory", name);
+ return;
+ }
+ else if (sm_snprintf(path, sizeof(path), "%s/%s",
+ user.mbdb_homedir, HomeMailFile) >= sizeof(path))
+ {
+ exitval = EX_UNAVAILABLE;
+ mailerr("550 5.1.1", "%s: Invalid mailbox path", name);
+ return;
+ }
/*
@@ -1024,7 +979,7 @@ tryagain:
errcode = "551 5.3.0";
mailerr(errcode, "lockmailbox %s failed; error code %d %s",
- p, off, errno > 0 ? errstring(errno) : "");
+ p, off, errno > 0 ? sm_errstring(errno) : "");
return;
}
@@ -1032,7 +987,7 @@ tryagain:
{
int save_errno;
int mode = S_IRUSR|S_IWUSR;
- gid_t gid = U_GID;
+ gid_t gid = user.mbdb_gid;
#ifdef MAILGID
(void) umask(0007);
@@ -1058,13 +1013,13 @@ tryagain:
/* open failed, don't try again */
mailerr("450 4.2.0", "%s: %s", path,
- errstring(save_errno));
+ sm_errstring(save_errno));
goto err0;
}
- else if (fchown(mbfd, U_UID, gid) < 0)
+ else if (fchown(mbfd, user.mbdb_uid, gid) < 0)
{
mailerr("451 4.3.0", "chown %u.%u: %s",
- U_UID, gid, name);
+ user.mbdb_uid, gid, name);
goto err1;
}
else
@@ -1076,7 +1031,7 @@ tryagain:
** is no longer valid; better safe than sorry.
*/
- sb.st_uid = U_UID;
+ sb.st_uid = user.mbdb_uid;
(void) close(mbfd);
mbfd = -1;
}
@@ -1086,28 +1041,29 @@ tryagain:
mailerr("550 5.2.0", "%s: irregular file", path);
goto err0;
}
- else if (sb.st_uid != U_UID)
+ else if (sb.st_uid != user.mbdb_uid)
{
ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0", "%s: wrong ownership (%d)",
- path, sb.st_uid);
+ path, (int) sb.st_uid);
goto err0;
}
/* change UID for quota checks */
- if (setreuid(0, U_UID) < 0)
+ if (setreuid(0, user.mbdb_uid) < 0)
{
mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
- U_UID, errstring(errno), getuid(), geteuid());
+ (int) user.mbdb_uid, sm_errstring(errno),
+ (int) getuid(), (int) geteuid());
goto err1;
}
#ifdef DEBUG
- fprintf(stderr, "new euid = %d\n", geteuid());
+ fprintf(stderr, "new euid = %d\n", (int) geteuid());
#endif /* DEBUG */
mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0);
if (mbfd < 0)
{
- mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
+ mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
goto err0;
}
else if (fstat(mbfd, &fsb) < 0 ||
@@ -1127,32 +1083,65 @@ tryagain:
goto err1;
}
+#if 0
+ /*
+ ** This code could be reused if we decide to add a
+ ** per-user quota field to the sm_mbdb interface.
+ */
+
+ /*
+ ** Fail if the user has a quota specified, and delivery of this
+ ** message would exceed that quota. We bounce such failures using
+ ** EX_UNAVAILABLE, unless there were internal problems, since
+ ** storing immense messages for later retries can cause queueing
+ ** issues.
+ */
+
+ if (ui.quota > 0)
+ {
+ struct stat dsb;
+
+ if (fstat(fd, &dsb) < 0)
+ {
+ ExitVal = EX_TEMPFAIL;
+ mailerr("451 4.3.0",
+ "%s: fstat: can't stat temporary storage: %s",
+ ui.mailspool, sm_errstring(errno));
+ goto err1;
+ }
+
+ if (dsb.st_size + sb.st_size + 1 > ui.quota)
+ {
+ ExitVal = EX_UNAVAILABLE;
+ mailerr("551 5.2.2",
+ "%s: Mailbox full or quota exceeded",
+ ui.mailspool);
+ goto err1;
+ }
+ }
+#endif /* 0 */
/* Wait until we can get a lock on the file. */
if (flock(mbfd, LOCK_EX) < 0)
{
- mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
+ mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
goto err1;
}
/* Get the starting offset of the new message for biff. */
curoff = lseek(mbfd, (off_t) 0, SEEK_END);
- if (sizeof curoff > sizeof(long))
- (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
- name, quad_to_string(curoff));
- else
- (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
- name, (long) curoff);
+ (void) sm_snprintf(biffmsg, sizeof(biffmsg), "%s@%lld\n",
+ name, (LONGLONG_T) curoff);
/* Copy the message into the file. */
if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1)
{
mailerr("450 4.2.0", "Temporary file: %s",
- errstring(errno));
+ sm_errstring(errno));
goto err1;
}
#ifdef DEBUG
- fprintf(stderr, "before writing: euid = %d\n", geteuid());
+ fprintf(stderr, "before writing: euid = %d\n", (int) geteuid());
#endif /* DEBUG */
#ifdef CONTENTLENGTH
headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ;
@@ -1160,7 +1149,7 @@ tryagain:
{
if (headerbytes == 0)
{
- snprintf(buf, sizeof buf, "%s", ContentHdr);
+ (void) sm_snprintf(buf, sizeof buf, "%s", ContentHdr);
nr = strlen(buf);
headerbytes = -1;
readamount = 0;
@@ -1190,7 +1179,7 @@ tryagain:
errcode = "552 5.2.2";
#endif /* EDQUOT */
mailerr(errcode, "%s: %s",
- path, errstring(errno));
+ path, sm_errstring(errno));
goto err3;
}
}
@@ -1198,18 +1187,18 @@ tryagain:
if (nr < 0)
{
mailerr("450 4.2.0", "Temporary file: %s",
- errstring(errno));
+ sm_errstring(errno));
goto err3;
}
/* Flush to disk, don't wait for update. */
if (fsync(mbfd) < 0)
{
- mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
+ mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno));
err3:
(void) setreuid(0, 0);
#ifdef DEBUG
- fprintf(stderr, "reset euid = %d\n", geteuid());
+ fprintf(stderr, "reset euid = %d\n", (int) geteuid());
#endif /* DEBUG */
(void) ftruncate(mbfd, curoff);
err1: if (mbfd >= 0)
@@ -1226,7 +1215,7 @@ err0: unlockmbox();
if (errno == EDQUOT && BounceQuota)
errcode = "552 5.2.2";
#endif /* EDQUOT */
- mailerr(errcode, "%s: %s", path, errstring(errno));
+ mailerr(errcode, "%s: %s", path, sm_errstring(errno));
(void) truncate(path, curoff);
}
else
@@ -1235,11 +1224,11 @@ err0: unlockmbox();
if (setreuid(0, 0) < 0)
{
mailerr("450 4.2.0", "setreuid(0, 0): %s",
- errstring(errno));
+ sm_errstring(errno));
goto err0;
}
#ifdef DEBUG
- fprintf(stderr, "reset euid = %d\n", geteuid());
+ fprintf(stderr, "reset euid = %d\n", (int) geteuid());
#endif /* DEBUG */
unlockmbox();
if (LMTPMode)
@@ -1253,7 +1242,7 @@ err0: unlockmbox();
** EPA 11/94.
*/
-bool Locked = FALSE;
+bool Locked = false;
#ifdef MAILLOCK
int
@@ -1266,7 +1255,7 @@ lockmbox(name)
return 0;
if ((r = maillock(name, 15)) == L_SUCCESS)
{
- Locked = TRUE;
+ Locked = true;
return 0;
}
switch (r)
@@ -1293,7 +1282,7 @@ unlockmbox()
{
if (Locked)
mailunlock();
- Locked = FALSE;
+ Locked = false;
}
#else /* MAILLOCK */
@@ -1310,7 +1299,7 @@ lockmbox(path)
return 0;
if (strlen(path) + 6 > sizeof LockName)
return EX_SOFTWARE;
- (void) snprintf(LockName, sizeof LockName, "%s.lock", path);
+ (void) sm_snprintf(LockName, sizeof LockName, "%s.lock", path);
(void) time(&start);
for (; ; sleep(5))
{
@@ -1330,7 +1319,7 @@ lockmbox(path)
{
/* defeat lock checking programs which test pid */
(void) write(fd, "0", 2);
- Locked = TRUE;
+ Locked = true;
(void) close(fd);
return 0;
}
@@ -1360,7 +1349,7 @@ unlockmbox()
if (!Locked)
return;
(void) unlink(LockName);
- Locked = FALSE;
+ Locked = false;
}
#endif /* MAILLOCK */
@@ -1368,7 +1357,7 @@ void
notifybiff(msg)
char *msg;
{
- static bool initialized = FALSE;
+ static bool initialized = false;
static int f = -1;
struct hostent *hp;
struct servent *sp;
@@ -1377,7 +1366,7 @@ notifybiff(msg)
if (!initialized)
{
- initialized = TRUE;
+ initialized = true;
/* Be silent if biff service not available. */
if ((sp = getservbyname("biff", "udp")) == NULL ||
@@ -1408,11 +1397,12 @@ void
usage()
{
ExitVal = EX_USAGE;
- mailerr(NULL, "usage: mail.local [-7] [-b] [-l] [-f from] user ...");
+ mailerr(NULL, "usage: mail.local [-7] [-b] [-d] [-l] [-f from|-r from] [-h filename] user ...");
exit(ExitVal);
}
void
+/*VARARGS2*/
#ifdef __STDC__
mailerr(const char *hdr, const char *fmt, ...)
#else /* __STDC__ */
@@ -1423,25 +1413,19 @@ mailerr(hdr, fmt, va_alist)
#endif /* __STDC__ */
{
size_t len = 0;
- va_list ap;
+ SM_VA_LOCAL_DECL
(void) e_to_sys(errno);
-#ifdef __STDC__
- va_start(ap, fmt);
-#else /* __STDC__ */
- va_start(ap);
-#endif /* __STDC__ */
+ SM_VA_START(ap, fmt);
- if (LMTPMode)
+ if (LMTPMode && hdr != NULL)
{
- if (hdr != NULL)
- {
- snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr);
- len = strlen(ErrBuf);
- }
+ sm_snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr);
+ len = strlen(ErrBuf);
}
- (void) vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap);
+ (void) sm_vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap);
+ SM_VA_END(ap);
if (!HoldErrs)
flush_error();
@@ -1630,7 +1614,7 @@ _gettemp(path, doopen)
extern int errno;
register char *start, *trv;
struct stat sbuf;
- u_int pid;
+ unsigned int pid;
pid = getpid();
for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
diff --git a/contrib/sendmail/mailstats/Makefile.m4 b/contrib/sendmail/mailstats/Makefile.m4
index 5a9259d..02dc956 100644
--- a/contrib/sendmail/mailstats/Makefile.m4
+++ b/contrib/sendmail/mailstats/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
@@ -8,6 +9,7 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `mailstats')
define(`bldINSTALL_DIR', `S')
define(`bldSOURCES', `mailstats.c ')
+bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
bldPRODUCT_END
diff --git a/contrib/sendmail/mailstats/mailstats.8 b/contrib/sendmail/mailstats/mailstats.8
index 5ecde7c..fe8e861 100644
--- a/contrib/sendmail/mailstats/mailstats.8
+++ b/contrib/sendmail/mailstats/mailstats.8
@@ -6,15 +6,15 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: mailstats.8,v 8.17.4.6 2001/05/07 22:06:38 gshapiro Exp $
+.\" $Id: mailstats.8,v 8.26 2001/10/21 19:12:10 gshapiro Exp $
.\"
-.TH MAILSTATS 8 "$Date: 2001/05/07 22:06:38 $"
+.TH MAILSTATS 8 "$Date: 2001/10/21 19:12:10 $"
.SH NAME
mailstats
\- display mail statistics
.SH SYNOPSIS
.B mailstats
-.RB [ \-o "] [" \-p ]
+.RB [ \-o "] [" \-p "] [" \-P ]
.RB [ \-C
.IR cffile ]
.RB [ \-f
@@ -50,10 +50,10 @@ Number of messages to the mailer.
Kbytes to the mailer.
.TP
.B msgsrej
-Number of messages rejected.
+Number of messages rejected (by check_* rulesets).
.TP
.B msgsdis
-Number of messages discarded.
+Number of messages discarded (by check_* rulesets).
.TP
.B Mailer
The name of the mailer.
@@ -80,6 +80,9 @@ specified in the
.B sendmail
configuration file.
.TP
+.B \-P
+Output information in program-readable mode without clearing statistics.
+.TP
.B \-p
Output information in program-readable mode and clear statistics.
.TP
diff --git a/contrib/sendmail/mailstats/mailstats.c b/contrib/sendmail/mailstats/mailstats.c
index 635b4e3..4dd078f 100644
--- a/contrib/sendmail/mailstats/mailstats.c
+++ b/contrib/sendmail/mailstats/mailstats.c
@@ -12,17 +12,15 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: mailstats.c,v 8.53.16.13 2001/05/07 22:06:38 gshapiro Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: mailstats.c,v 8.95 2001/12/30 04:59:40 gshapiro Exp $")
#include <unistd.h>
#include <stddef.h>
@@ -35,6 +33,8 @@ static char id[] = "@(#)$Id: mailstats.c,v 8.53.16.13 2001/05/07 22:06:38 gshapi
#endif /* EX_OK */
#include <sysexits.h>
+#include <sm/errstring.h>
+#include <sm/limits.h>
#include <sendmail/sendmail.h>
#include <sendmail/mailstats.h>
#include <sendmail/pathnames.h>
@@ -42,7 +42,6 @@ static char id[] = "@(#)$Id: mailstats.c,v 8.53.16.13 2001/05/07 22:06:38 gshapi
#define MNAMELEN 20 /* max length of mailer name */
-
int
main(argc, argv)
int argc;
@@ -54,11 +53,15 @@ main(argc, argv)
int ch, fd;
char *sfile;
char *cfile;
- FILE *cfp;
+ SM_FILE_T *cfp;
bool mnames;
bool progmode;
+ bool trunc;
long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0;
long dismsgs = 0;
+#if _FFR_QUARANTINE
+ long quarmsgs = 0;
+#endif /* _FFR_QUARANTINE */
time_t now;
char mtable[MAXMAILERS][MNAMELEN + 1];
char sfilebuf[MAXLINE];
@@ -68,15 +71,19 @@ main(argc, argv)
extern char *optarg;
extern int optind;
-
- cfile = _PATH_SENDMAILCF;
+ cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
sfile = NULL;
- mnames = TRUE;
- progmode = FALSE;
- while ((ch = getopt(argc, argv, "C:f:op")) != -1)
+ mnames = true;
+ progmode = false;
+ trunc = false;
+ while ((ch = getopt(argc, argv, "cC:f:opP")) != -1)
{
switch (ch)
{
+ case 'c':
+ cfile = getcfname(0, 0, SM_GET_SUBMIT_CF, NULL);
+ break;
+
case 'C':
cfile = optarg;
break;
@@ -86,18 +93,22 @@ main(argc, argv)
break;
case 'o':
- mnames = FALSE;
+ mnames = false;
break;
case 'p':
- progmode = TRUE;
+ trunc = true;
+ /* FALLTHROUGH */
+
+ case 'P':
+ progmode = true;
break;
case '?':
default:
usage:
- (void) fputs("usage: mailstats [-C cffile] [-f stfile] [-o] [-p]\n",
- stderr);
+ (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT,
+ "usage: mailstats [-C cffile] [-P] [-f stfile] [-o] [-p]\n");
exit(EX_USAGE);
}
}
@@ -107,21 +118,22 @@ main(argc, argv)
if (argc != 0)
goto usage;
- if ((cfp = fopen(cfile, "r")) == NULL)
+ if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
+ NULL)) == NULL)
{
save_errno = errno;
- fprintf(stderr, "mailstats: ");
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "mailstats: ");
errno = save_errno;
- perror(cfile);
+ sm_perror(cfile);
exit(EX_NOINPUT);
}
mno = 0;
- (void) strlcpy(mtable[mno++], "prog", MNAMELEN + 1);
- (void) strlcpy(mtable[mno++], "*file*", MNAMELEN + 1);
- (void) strlcpy(mtable[mno++], "*include*", MNAMELEN + 1);
+ (void) sm_strlcpy(mtable[mno++], "prog", MNAMELEN + 1);
+ (void) sm_strlcpy(mtable[mno++], "*file*", MNAMELEN + 1);
+ (void) sm_strlcpy(mtable[mno++], "*include*", MNAMELEN + 1);
- while (fgets(buf, sizeof(buf), cfp) != NULL)
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
{
register char *b;
char *s;
@@ -134,7 +146,7 @@ main(argc, argv)
break;
case 'O': /* option -- see if .st file */
- if (strncasecmp(b, " StatusFile", 11) == 0 &&
+ if (sm_strncasecmp(b, " StatusFile", 11) == 0 &&
!(isascii(b[11]) && isalnum(b[11])))
{
/* new form -- find value */
@@ -151,12 +163,12 @@ main(argc, argv)
}
/* this is the S or StatusFile option -- save it */
- if (strlcpy(sfilebuf, b, sizeof sfilebuf) >=
+ if (sm_strlcpy(sfilebuf, b, sizeof sfilebuf) >=
sizeof sfilebuf)
{
- fprintf(stderr,
- "StatusFile filename too long: %.30s...\n",
- b);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "StatusFile filename too long: %.30s...\n",
+ b);
exit(EX_CONFIG);
}
b = strchr(sfilebuf, '#');
@@ -176,9 +188,9 @@ main(argc, argv)
if (mno >= MAXMAILERS)
{
- fprintf(stderr,
- "Too many mailers defined, %d max.\n",
- MAXMAILERS);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Too many mailers defined, %d max.\n",
+ MAXMAILERS);
exit(EX_SOFTWARE);
}
m = mtable[mno];
@@ -195,13 +207,14 @@ main(argc, argv)
if (i == mno)
mno++;
}
- (void) fclose(cfp);
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
for (; mno < MAXMAILERS; mno++)
- mtable[mno][0]='\0';
+ mtable[mno][0] = '\0';
if (sfile == NULL)
{
- fprintf(stderr, "mailstats: no statistics file located\n");
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "mailstats: no statistics file located\n");
exit (EX_OSFILE);
}
@@ -209,9 +222,9 @@ main(argc, argv)
if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0)
{
save_errno = errno;
- (void) fputs("mailstats: ", stderr);
+ (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, "mailstats: ");
errno = save_errno;
- perror(sfile);
+ sm_perror(sfile);
exit(EX_NOINPUT);
}
if (i == 0)
@@ -220,9 +233,10 @@ main(argc, argv)
if ((i = read(fd, &stats, sizeof stats)) < 0)
{
save_errno = errno;
- (void) fputs("mailstats: ", stderr);
+ (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT,
+ "mailstats: ");
errno = save_errno;
- perror(sfile);
+ sm_perror(sfile);
exit(EX_NOINPUT);
}
else if (i == 0)
@@ -235,21 +249,24 @@ main(argc, argv)
{
if (stats.stat_magic != STAT_MAGIC)
{
- fprintf(stderr,
- "mailstats: incorrect magic number in %s\n",
- sfile);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "mailstats: incorrect magic number in %s\n",
+ sfile);
exit(EX_OSERR);
}
else if (stats.stat_version != STAT_VERSION)
{
- fprintf(stderr,
- "mailstats version (%d) incompatible with %s version (%d)\n",
- STAT_VERSION, sfile, stats.stat_version);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "mailstats version (%d) incompatible with %s version (%d)\n",
+ STAT_VERSION, sfile,
+ stats.stat_version);
+
exit(EX_OSERR);
}
else if (i != sizeof stats || stats.stat_size != sizeof(stats))
{
- (void) fputs("mailstats: file size changed.\n", stderr);
+ (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT,
+ "mailstats: file size changed.\n");
exit(EX_OSERR);
}
}
@@ -257,17 +274,28 @@ main(argc, argv)
if (progmode)
{
(void) time(&now);
- printf("%ld %ld\n", (long) stats.stat_itime, (long) now);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%ld %ld\n",
+ (long) stats.stat_itime, (long) now);
}
else
{
- printf("Statistics from %s", ctime(&stats.stat_itime));
- printf(" M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis%s\n",
- mnames ? " Mailer" : "");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Statistics from %s",
+ ctime(&stats.stat_itime));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis");
+#if _FFR_QUARANTINE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " msgsqur");
+#endif /* _FFR_QUARANTINE */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n",
+ mnames ? " Mailer" : "");
}
for (i = 0; i < MAXMAILERS; i++)
{
if (stats.stat_nf[i] || stats.stat_nt[i] ||
+#if _FFR_QUARANTINE
+ stats.stat_nq[i] ||
+#endif /* _FFR_QUARANTINE */
stats.stat_nr[i] || stats.stat_nd[i])
{
char *format;
@@ -276,39 +304,78 @@ main(argc, argv)
format = "%2d %8ld %10ld %8ld %10ld %6ld %6ld";
else
format = "%2d %8ld %10ldK %8ld %10ldK %6ld %6ld";
- printf(format, i,
- stats.stat_nf[i], stats.stat_bf[i],
- stats.stat_nt[i], stats.stat_bt[i],
- stats.stat_nr[i], stats.stat_nd[i]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ format, i,
+ stats.stat_nf[i],
+ stats.stat_bf[i],
+ stats.stat_nt[i],
+ stats.stat_bt[i],
+ stats.stat_nr[i],
+ stats.stat_nd[i]);
+#if _FFR_QUARANTINE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " %6ld", stats.stat_nq[i]);
+#endif /* _FFR_QUARANTINE */
if (mnames)
- printf(" %s", mtable[i]);
- printf("\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " %s",
+ mtable[i]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
frmsgs += stats.stat_nf[i];
frbytes += stats.stat_bf[i];
tomsgs += stats.stat_nt[i];
tobytes += stats.stat_bt[i];
rejmsgs += stats.stat_nr[i];
dismsgs += stats.stat_nd[i];
+#if _FFR_QUARANTINE
+ quarmsgs += stats.stat_nq[i];
+#endif /* _FFR_QUARANTINE */
}
}
if (progmode)
{
- printf(" T %8ld %10ld %8ld %10ld %6ld %6ld\n",
- frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
- printf(" C %8ld %8ld %6ld\n",
- stats.stat_cf, stats.stat_ct, stats.stat_cr);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " T %8ld %10ld %8ld %10ld %6ld %6ld",
+ frmsgs, frbytes, tomsgs, tobytes, rejmsgs,
+ dismsgs);
+#if _FFR_QUARANTINE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " %6ld", quarmsgs);
+#endif /* _FFR_QUARANTINE */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " C %8ld %8ld %6ld\n",
+ stats.stat_cf, stats.stat_ct,
+ stats.stat_cr);
(void) close(fd);
- fd = open(sfile, O_RDWR | O_TRUNC);
- if (fd >= 0)
- (void) close(fd);
+ if (trunc)
+ {
+ fd = open(sfile, O_RDWR | O_TRUNC);
+ if (fd >= 0)
+ (void) close(fd);
+ }
}
else
{
- printf("=============================================================\n");
- printf(" T %8ld %10ldK %8ld %10ldK %6ld %6ld\n",
- frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
- printf(" C %8ld %10s %8ld %10s %6ld\n",
- stats.stat_cf, "", stats.stat_ct, "", stats.stat_cr);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "=============================================================");
+#if _FFR_QUARANTINE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "========");
+#endif /* _FFR_QUARANTINE */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " T %8ld %10ldK %8ld %10ldK %6ld %6ld",
+ frmsgs, frbytes, tomsgs, tobytes, rejmsgs,
+ dismsgs);
+#if _FFR_QUARANTINE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " %6ld", quarmsgs);
+#endif /* _FFR_QUARANTINE */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " C %8ld %10s %8ld %10s %6ld\n",
+ stats.stat_cf, "", stats.stat_ct, "",
+ stats.stat_cr);
}
exit(EX_OK);
/* NOTREACHED */
diff --git a/contrib/sendmail/makemap/Makefile.m4 b/contrib/sendmail/makemap/Makefile.m4
index 4077239..171a548 100644
--- a/contrib/sendmail/makemap/Makefile.m4
+++ b/contrib/sendmail/makemap/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
@@ -8,6 +9,7 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `makemap')
define(`bldSOURCES', `makemap.c ')
define(`bldINSTALL_DIR', `S')
+bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
bldPUSH_SMLIB(`smdb')
APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
diff --git a/contrib/sendmail/makemap/makemap.8 b/contrib/sendmail/makemap/makemap.8
index 375d1ec..9faaef7 100644
--- a/contrib/sendmail/makemap/makemap.8
+++ b/contrib/sendmail/makemap/makemap.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -8,9 +8,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: makemap.8,v 8.21.16.5 2000/12/29 18:12:20 gshapiro Exp $
+.\" $Id: makemap.8,v 8.29 2001/10/10 03:23:02 ca Exp $
.\"
-.TH MAKEMAP 8 "$Date: 2000/12/29 18:12:20 $"
+.TH MAKEMAP 8 "$Date: 2001/10/10 03:23:02 $"
.SH NAME
makemap
\- create database maps for sendmail
@@ -28,6 +28,8 @@ makemap
.RB [ \-o ]
.RB [ \-r ]
.RB [ \-s ]
+.RB [ \-t
+.IR delim ]
.RB [ \-u ]
.RB [ \-v ]
.I
@@ -77,6 +79,15 @@ Literal percents should be doubled
(``%%'').
Blank lines and lines beginning with ``#'' are ignored.
.PP
+Notice: do
+.B not
+use
+.B makemap
+to create the aliases data base, but
+.B newaliases
+which puts a special token into the data base that is required by
+.B sendmail.
+.PP
If the
.I TrustedUser
option is set in the sendmail configuration file and
@@ -138,13 +149,16 @@ Ignore safety checks on maps being created.
This includes checking for hard or symbolic
links in world writable directories.
.TP
+.B \-t
+Use the specified delimiter instead of white space.
+.TP
.B \-u
dump (unmap) the content of the database to standard output.
.TP
.B \-v
Verbosely print what it is doing.
.SH SEE ALSO
-sendmail(8)
+sendmail(8), newaliases(1)
.SH HISTORY
The
.B makemap
diff --git a/contrib/sendmail/makemap/makemap.c b/contrib/sendmail/makemap/makemap.c
index cabb18a..59c28f6 100644
--- a/contrib/sendmail/makemap/makemap.c
+++ b/contrib/sendmail/makemap/makemap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1992 Eric P. Allman. All rights reserved.
* Copyright (c) 1992, 1993
@@ -11,18 +11,16 @@
*
*/
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
+"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1992, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: makemap.c,v 8.135.4.13 2000/10/05 23:00:50 gshapiro Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.175 2001/12/28 22:44:01 ca Exp $")
#include <sys/types.h>
@@ -47,31 +45,24 @@ uid_t RunAsUid;
uid_t RunAsGid;
char *RunAsUserName;
int Verbose = 2;
-bool DontInitGroups = FALSE;
+bool DontInitGroups = false;
uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
#define BUFSIZE 1024
-#if _FFR_DELIM
-# define ISSEP(c) ((sep == '\0' && isascii(c) && isspace(c)) || (c) == sep)
-#else /* _FFR_DELIM */
-# define ISSEP(c) (isascii(c) && isspace(c))
-#endif /* _FFR_DELIM */
-
+#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
static void
usage(progname)
char *progname;
{
- fprintf(stderr,
- "Usage: %s [-C cffile] [-N] [-c cachesize] [-d] [-e] [-f] [-l] [-o] [-r] [-s] %s[-u] [-v] type mapname\n",
- progname,
-#if _FFR_DELIM
- "[-t delimiter] "
-#else /* _FFR_DELIM */
- ""
-#endif /* _FFR_DELIM */
- );
+ /* XXX break the usage output into multiple lines? it's too long */
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Usage: %s [-C cffile] [-N] [-c cachesize] [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter] [-u] [-v] type mapname\n",
+ progname);
+#if _FFR_COMMENT_CHAR
+ /* add -D comment-char */
+#endif /* _FFR_COMMENT_CHAR */
exit(EX_USAGE);
}
@@ -82,21 +73,20 @@ main(argc, argv)
{
char *progname;
char *cfile;
- bool inclnull = FALSE;
- bool notrunc = FALSE;
- bool allowreplace = FALSE;
- bool allowempty = FALSE;
- bool verbose = FALSE;
- bool foldcase = TRUE;
- bool unmake = FALSE;
-#if _FFR_DELIM
+ bool inclnull = false;
+ bool notrunc = false;
+ bool allowreplace = false;
+ bool allowempty = false;
+ bool verbose = false;
+ bool foldcase = true;
+ bool unmake = false;
char sep = '\0';
-#endif /* _FFR_DELIM */
+ char comment = '#';
int exitstat;
int opt;
char *typename = NULL;
char *mapname = NULL;
- int lineno;
+ unsigned int lineno;
int st;
int mode;
int smode;
@@ -110,7 +100,7 @@ main(argc, argv)
SMDB_USER_INFO user_info;
char ibuf[BUFSIZE];
#if HASFCHOWN
- FILE *cfp;
+ SM_FILE_T *cfp;
char buf[MAXLINE];
#endif /* HASFCHOWN */
static char rnamebuf[MAXNAME]; /* holds RealUserName */
@@ -125,25 +115,24 @@ main(argc, argv)
progname++;
else
progname = argv[0];
- cfile = _PATH_SENDMAILCF;
+ cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
clrbitmap(DontBlameSendmail);
RunAsUid = RealUid = getuid();
RunAsGid = RealGid = getgid();
pw = getpwuid(RealUid);
if (pw != NULL)
- (void) strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
+ (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
else
- (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
- (int) RealUid);
+ (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
+ "Unknown UID %d", (int) RealUid);
RunAsUserName = RealUserName = rnamebuf;
user_info.smdbu_id = RunAsUid;
user_info.smdbu_group_id = RunAsGid;
- (void) strlcpy(user_info.smdbu_name, RunAsUserName,
+ (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
SMDB_MAX_USER_NAME_LEN);
-
-#define OPTIONS "C:Nc:t:deflorsuv"
+#define OPTIONS "C:D:Nc:deflorst:uv"
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
@@ -153,7 +142,7 @@ main(argc, argv)
break;
case 'N':
- inclnull = TRUE;
+ inclnull = true;
break;
case 'c':
@@ -161,28 +150,34 @@ main(argc, argv)
break;
case 'd':
- params.smdbp_allow_dup = TRUE;
+ params.smdbp_allow_dup = true;
break;
case 'e':
- allowempty = TRUE;
+ allowempty = true;
break;
case 'f':
- foldcase = FALSE;
+ foldcase = false;
break;
+#if _FFR_COMMENT_CHAR
+ case 'D':
+ comment = *optarg;
+ break;
+#endif /* _FFR_COMMENT_CHAR */
+
case 'l':
smdb_print_available_types();
exit(EX_OK);
break;
case 'o':
- notrunc = TRUE;
+ notrunc = true;
break;
case 'r':
- allowreplace = TRUE;
+ allowreplace = true;
break;
case 's':
@@ -192,23 +187,22 @@ main(argc, argv)
setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
break;
-#if _FFR_DELIM
case 't':
if (optarg == NULL || *optarg == '\0')
{
- fprintf(stderr, "Invalid separator\n");
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Invalid separator\n");
break;
}
sep = *optarg;
break;
-#endif /* _FFR_DELIM */
case 'u':
- unmake = TRUE;
+ unmake = true;
break;
case 'v':
- verbose = TRUE;
+ verbose = true;
break;
default:
@@ -239,12 +233,14 @@ main(argc, argv)
#if HASFCHOWN
/* Find TrustedUser value in sendmail.cf */
- if ((cfp = fopen(cfile, "r")) == NULL)
+ if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
+ NULL)) == NULL)
{
- fprintf(stderr, "makemap: %s: %s", cfile, errstring(errno));
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s",
+ cfile, sm_errstring(errno));
exit(EX_NOINPUT);
}
- while (fgets(buf, sizeof(buf), cfp) != NULL)
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
{
register char *b;
@@ -270,8 +266,9 @@ main(argc, argv)
TrustedUid = 0;
pw = getpwnam(b);
if (pw == NULL)
- fprintf(stderr,
- "TrustedUser: unknown user %s\n", b);
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "TrustedUser: unknown user %s\n", b);
else
TrustedUid = pw->pw_uid;
}
@@ -279,8 +276,9 @@ main(argc, argv)
# ifdef UID_MAX
if (TrustedUid > UID_MAX)
{
- fprintf(stderr,
- "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
(long) TrustedUid,
(long) UID_MAX);
TrustedUid = 0;
@@ -294,7 +292,7 @@ main(argc, argv)
continue;
}
}
- (void) fclose(cfp);
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
#endif /* HASFCHOWN */
if (!params.smdbp_allow_dup && !allowreplace)
@@ -326,13 +324,14 @@ main(argc, argv)
if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
(hint = smdb_db_definition(typename)) != NULL)
- fprintf(stderr,
- "%s: Need to recompile with -D%s for %s support\n",
- progname, hint, typename);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: Need to recompile with -D%s for %s support\n",
+ progname, hint, typename);
else
- fprintf(stderr,
- "%s: error opening type %s map %s: %s\n",
- progname, typename, mapname, errstring(errno));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: error opening type %s map %s: %s\n",
+ progname, typename, mapname,
+ sm_errstring(errno));
exit(EX_CANTCREAT);
}
@@ -343,9 +342,9 @@ main(argc, argv)
errno = database->smdb_set_owner(database, TrustedUid, -1);
if (errno != SMDBE_OK)
{
- fprintf(stderr,
- "WARNING: ownership change on %s failed %s",
- mapname, errstring(errno));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "WARNING: ownership change on %s failed %s",
+ mapname, sm_errstring(errno));
}
}
@@ -360,9 +359,9 @@ main(argc, argv)
if (errno != SMDBE_OK)
{
- fprintf(stderr,
- "%s: cannot make cursor for type %s map %s\n",
- progname, typename, mapname);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: cannot make cursor for type %s map %s\n",
+ progname, typename, mapname);
exit(EX_SOFTWARE);
}
@@ -376,11 +375,12 @@ main(argc, argv)
if (errno != SMDBE_OK)
break;
- printf("%.*s\t%.*s\n",
- (int) db_key.size,
- (char *) db_key.data,
- (int) db_val.size,
- (char *)db_val.data);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%.*s\t%.*s\n",
+ (int) db_key.size,
+ (char *) db_key.data,
+ (int) db_val.size,
+ (char *)db_val.data);
}
(void) cursor->smdbc_close(cursor);
@@ -388,7 +388,8 @@ main(argc, argv)
else
{
lineno = 0;
- while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
+ while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
+ != NULL)
{
register char *p;
@@ -401,26 +402,23 @@ main(argc, argv)
p = strchr(ibuf, '\n');
if (p != NULL)
*p = '\0';
- else if (!feof(stdin))
+ else if (!sm_io_eof(smioin))
{
- fprintf(stderr,
- "%s: %s: line %d: line too long (%ld bytes max)\n",
- progname, mapname, lineno, (long) sizeof ibuf);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: line too long (%ld bytes max)\n",
+ progname, mapname, lineno,
+ (long) sizeof ibuf);
exitstat = EX_DATAERR;
continue;
}
- if (ibuf[0] == '\0' || ibuf[0] == '#')
+ if (ibuf[0] == '\0' || ibuf[0] == comment)
continue;
- if (
-#if _FFR_DELIM
- sep == '\0' &&
-#endif /* _FFR_DELIM */
- isascii(ibuf[0]) && isspace(ibuf[0]))
+ if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
{
- fprintf(stderr,
- "%s: %s: line %d: syntax error (leading space)\n",
- progname, mapname, lineno);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: syntax error (leading space)\n",
+ progname, mapname, lineno);
exitstat = EX_DATAERR;
continue;
}
@@ -440,14 +438,14 @@ main(argc, argv)
if (*p != '\0')
*p++ = '\0';
- while (ISSEP(*p))
+ while (*p != '\0' && ISSEP(*p))
p++;
if (!allowempty && *p == '\0')
{
- fprintf(stderr,
- "%s: %s: line %d: no RHS for LHS %s\n",
- progname, mapname, lineno,
- (char *) db_key.data);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: no RHS for LHS %s\n",
+ progname, mapname, lineno,
+ (char *) db_key.data);
exitstat = EX_DATAERR;
continue;
}
@@ -463,9 +461,10 @@ main(argc, argv)
if (verbose)
{
- printf("key=`%s', val=`%s'\n",
- (char *) db_key.data,
- (char *) db_val.data);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "key=`%s', val=`%s'\n",
+ (char *) db_key.data,
+ (char *) db_val.data);
}
errno = database->smdb_put(database, &db_key, &db_val,
@@ -487,19 +486,20 @@ main(argc, argv)
if (st < 0)
{
- fprintf(stderr,
- "%s: %s: line %d: key %s: put error: %s\n",
- progname, mapname, lineno,
- (char *) db_key.data,
- errstring(errno));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: key %s: put error: %s\n",
+ progname, mapname, lineno,
+ (char *) db_key.data,
+ sm_errstring(errno));
exitstat = EX_IOERR;
}
else if (st > 0)
{
- fprintf(stderr,
- "%s: %s: line %d: key %s: duplicate key\n",
- progname, mapname,
- lineno, (char *) db_key.data);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: key %s: duplicate key\n",
+ progname, mapname,
+ lineno,
+ (char *) db_key.data);
exitstat = EX_DATAERR;
}
}
@@ -512,61 +512,15 @@ main(argc, argv)
errno = database->smdb_close(database);
if (errno != SMDBE_OK)
{
- fprintf(stderr, "%s: close(%s): %s\n",
- progname, mapname, errstring(errno));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: close(%s): %s\n",
+ progname, mapname, sm_errstring(errno));
exitstat = EX_IOERR;
}
smdb_free_database(database);
exit(exitstat);
+
/* NOTREACHED */
return exitstat;
}
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-message(const char *msg, ...)
-#else /* __STDC__ */
-message(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-syserr(const char *msg, ...)
-#else /* __STDC__ */
-syserr(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
diff --git a/contrib/sendmail/praliases/Makefile.m4 b/contrib/sendmail/praliases/Makefile.m4
index 670c2cc..20509a6 100644
--- a/contrib/sendmail/praliases/Makefile.m4
+++ b/contrib/sendmail/praliases/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
@@ -8,6 +9,7 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `praliases')
define(`bldINSTALL_DIR', `S')
define(`bldSOURCES', `praliases.c ')
+bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
bldPUSH_SMLIB(`smdb')
APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
diff --git a/contrib/sendmail/praliases/praliases.8 b/contrib/sendmail/praliases/praliases.8
index 91d4498..2c78cac 100644
--- a/contrib/sendmail/praliases/praliases.8
+++ b/contrib/sendmail/praliases/praliases.8
@@ -6,9 +6,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: praliases.8,v 8.15.4.2 2000/12/15 19:50:45 gshapiro Exp $
+.\" $Id: praliases.8,v 8.17 2000/12/15 19:53:45 gshapiro Exp $
.\"
-.TH PRALIASES 8 "$Date: 2000/12/15 19:50:45 $"
+.TH PRALIASES 8 "$Date: 2000/12/15 19:53:45 $"
.SH NAME
praliases
\- display system mail aliases
diff --git a/contrib/sendmail/praliases/praliases.c b/contrib/sendmail/praliases/praliases.c
index f7880ef..720fa6d 100644
--- a/contrib/sendmail/praliases/praliases.c
+++ b/contrib/sendmail/praliases/praliases.c
@@ -11,18 +11,16 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: praliases.c,v 8.59.4.19 2001/02/28 02:37:57 ca Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.93 2001/09/11 04:05:07 gshapiro Exp $")
#include <sys/types.h>
#include <ctype.h>
@@ -50,12 +48,10 @@ uid_t RunAsUid;
uid_t RunAsGid;
char *RunAsUserName;
int Verbose = 2;
-bool DontInitGroups = FALSE;
+bool DontInitGroups = false;
uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
-extern void syserr __P((const char *, ...));
-
# define DELIMITERS " ,/"
# define PATH_SEPARATOR ':'
@@ -66,7 +62,7 @@ main(argc, argv)
{
char *cfile;
char *filename = NULL;
- FILE *cfp;
+ SM_FILE_T *cfp;
int ch;
char afilebuf[MAXLINE];
char buf[MAXLINE];
@@ -75,7 +71,6 @@ main(argc, argv)
extern char *optarg;
extern int optind;
-
clrbitmap(DontBlameSendmail);
RunAsUid = RealUid = getuid();
RunAsGid = RealGid = getgid();
@@ -84,14 +79,14 @@ main(argc, argv)
{
if (strlen(pw->pw_name) > MAXNAME - 1)
pw->pw_name[MAXNAME] = 0;
- snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
+ sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
}
else
- (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
- (int) RealUid);
+ (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
+ "Unknown UID %d", (int) RealUid);
RunAsUserName = RealUserName = rnamebuf;
- cfile = _PATH_SENDMAILCF;
+ cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
while ((ch = getopt(argc, argv, "C:f:")) != -1)
{
switch ((char)ch) {
@@ -103,8 +98,8 @@ main(argc, argv)
break;
case '?':
default:
- (void)fprintf(stderr,
- "usage: praliases [-C cffile] [-f aliasfile]\n");
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "usage: praliases [-C cffile] [-f aliasfile]\n");
exit(EX_USAGE);
}
}
@@ -117,14 +112,16 @@ main(argc, argv)
exit(EX_OK);
}
- if ((cfp = fopen(cfile, "r")) == NULL)
+ if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
+ NULL)) == NULL)
{
- fprintf(stderr, "praliases: %s: %s\n",
- cfile, errstring(errno));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: %s: %s\n", cfile,
+ sm_errstring(errno));
exit(EX_NOINPUT);
}
- while (fgets(buf, sizeof(buf), cfp) != NULL)
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
{
register char *b, *p;
@@ -136,7 +133,7 @@ main(argc, argv)
switch (*b++)
{
case 'O': /* option -- see if alias file */
- if (strncasecmp(b, " AliasFile", 10) == 0 &&
+ if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
!(isascii(b[10]) && isalnum(b[10])))
{
/* new form -- find value */
@@ -153,13 +150,13 @@ main(argc, argv)
}
/* this is the A or AliasFile option -- save it */
- if (strlcpy(afilebuf, b, sizeof afilebuf) >=
+ if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
sizeof afilebuf)
{
- fprintf(stderr,
- "praliases: AliasFile filename too long: %.30s\n",
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: AliasFile filename too long: %.30s\n",
b);
- (void) fclose(cfp);
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
exit(EX_CONFIG);
}
b = afilebuf;
@@ -177,7 +174,7 @@ main(argc, argv)
/* find end of spec */
if (p != NULL)
{
- bool quoted = FALSE;
+ bool quoted = false;
for (; *p != '\0'; p++)
{
@@ -224,7 +221,7 @@ main(argc, argv)
continue;
}
}
- (void) fclose(cfp);
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
exit(EX_OK);
/* NOTREACHED */
return EX_OK;
@@ -280,8 +277,8 @@ praliases(filename, argc, argv)
strcmp(db_type, "btree") != 0 &&
strcmp(db_type, "dbm") != 0)
{
- fprintf(stderr,
- "praliases: Skipping non-file based alias type %s\n",
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: Skipping non-file based alias type %s\n",
db_type);
return;
}
@@ -291,8 +288,8 @@ praliases(filename, argc, argv)
{
if (colon != NULL)
*colon = ':';
- fprintf(stderr, "praliases: illegal alias specification: %s\n",
- filename);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: illegal alias specification: %s\n", filename);
goto fatal;
}
@@ -301,14 +298,16 @@ praliases(filename, argc, argv)
user_info.smdbu_id = RunAsUid;
user_info.smdbu_group_id = RunAsGid;
- strlcpy(user_info.smdbu_name, RunAsUserName, SMDB_MAX_USER_NAME_LEN);
+ (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
+ SMDB_MAX_USER_NAME_LEN);
result = smdb_open_database(&database, db_name, O_RDONLY, 0,
SFF_ROOTOK, db_type, &user_info, &params);
if (result != SMDBE_OK)
{
- fprintf(stderr, "praliases: %s: open: %s\n",
- db_name, errstring(result));
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: %s: open: %s\n",
+ db_name, sm_errstring(result));
goto fatal;
}
@@ -320,8 +319,9 @@ praliases(filename, argc, argv)
result = database->smdb_cursor(database, &cursor, 0);
if (result != SMDBE_OK)
{
- fprintf(stderr, "praliases: %s: set cursor: %s\n",
- db_name, errstring(result));
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "praliases: %s: set cursor: %s\n", db_name,
+ sm_errstring(result));
goto fatal;
}
@@ -340,18 +340,19 @@ praliases(filename, argc, argv)
continue;
#endif /* 0 */
- printf("%.*s:%.*s\n",
- (int) db_key.size,
- (char *) db_key.data,
- (int) db_value.size,
- (char *) db_value.data);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%.*s:%.*s\n",
+ (int) db_key.size,
+ (char *) db_key.data,
+ (int) db_value.size,
+ (char *) db_value.data);
}
if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
{
- fprintf(stderr,
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
"praliases: %s: get value at cursor: %s\n",
- db_name, errstring(result));
+ db_name, sm_errstring(result));
goto fatal;
}
}
@@ -372,14 +373,17 @@ praliases(filename, argc, argv)
}
if (get_res == SMDBE_OK)
{
- printf("%.*s:%.*s\n",
- (int) db_key.size,
- (char *) db_key.data,
- (int) db_value.size,
- (char *) db_value.data);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%.*s:%.*s\n",
+ (int) db_key.size,
+ (char *) db_key.data,
+ (int) db_value.size,
+ (char *) db_value.data);
}
else
- printf("%s: No such key\n", (char *) db_key.data);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s: No such key\n",
+ (char *)db_key.data);
}
fatal:
@@ -391,51 +395,3 @@ praliases(filename, argc, argv)
*colon = ':';
return;
}
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-message(const char *msg, ...)
-#else /* __STDC__ */
-message(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-syserr(const char *msg, ...)
-#else /* __STDC__ */
-syserr(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
diff --git a/contrib/sendmail/rmail/Makefile.m4 b/contrib/sendmail/rmail/Makefile.m4
index deed449..c78b6ca 100644
--- a/contrib/sendmail/rmail/Makefile.m4
+++ b/contrib/sendmail/rmail/Makefile.m4
@@ -1,14 +1,15 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `rmail')
-define(`bldNO_INSTALL')
+define(`bldNO_INSTALL', `true')
define(`bldSOURCES', `rmail.c ')
-bldPUSH_SMLIB(`smutil')
+bldPUSH_SMLIB(`sm')
bldPRODUCT_END
bldPRODUCT_START(`manpage', `rmail')
diff --git a/contrib/sendmail/rmail/rmail.8 b/contrib/sendmail/rmail/rmail.8
index 993507b..41aa339 100644
--- a/contrib/sendmail/rmail/rmail.8
+++ b/contrib/sendmail/rmail/rmail.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1983, 1990
.\" The Regents of the University of California. All rights reserved.
@@ -8,9 +8,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: rmail.8,v 8.1.16.2 2000/12/29 18:12:22 gshapiro Exp $
+.\" $Id: rmail.8,v 8.4 2001/04/03 01:53:16 gshapiro Exp $
.\"
-.TH RMAIL 8 "$Date: 2000/12/29 18:12:22 $"
+.TH RMAIL 8 "$Date: 2001/04/03 01:53:16 $"
.SH NAME
rmail
\- handle remote mail received via uucp
diff --git a/contrib/sendmail/rmail/rmail.c b/contrib/sendmail/rmail/rmail.c
index e678422..cea291f 100644
--- a/contrib/sendmail/rmail/rmail.c
+++ b/contrib/sendmail/rmail/rmail.c
@@ -10,17 +10,15 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: rmail.c,v 8.39.4.12 2001/05/07 22:06:39 gshapiro Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: rmail.c,v 8.61 2001/09/18 21:45:29 gshapiro Exp $")
/*
* RMAIL -- UUCP mail server.
@@ -54,69 +52,18 @@ static char id[] = "@(#)$Id: rmail.c,v 8.39.4.12 2001/05/07 22:06:39 gshapiro Ex
#include <ctype.h>
#include <fcntl.h>
-#ifdef BSD4_4
-# define FORK vfork
-# include <paths.h>
-#else /* BSD4_4 */
-# define FORK fork
-# ifndef _PATH_SENDMAIL
-# define _PATH_SENDMAIL "/usr/lib/sendmail"
-# endif /* ! _PATH_SENDMAIL */
-#endif /* BSD4_4 */
-#include <stdio.h>
+#include <sm/io.h>
#include <stdlib.h>
-#include <string.h>
+#include <sm/string.h>
#include <unistd.h>
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
#endif /* EX_OK */
#include <sysexits.h>
-#ifndef MAX
-# define MAX(a, b) ((a) < (b) ? (b) : (a))
-#endif /* ! MAX */
-
-#ifndef __P
-# ifdef __STDC__
-# define __P(protos) protos
-# else /* __STDC__ */
-# define __P(protos) ()
-# define const
-# endif /* __STDC__ */
-#endif /* ! __P */
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif /* ! STDIN_FILENO */
-
-#if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11)
-# define HASSNPRINTF 1
-#endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 || defined(HPUX11) */
-
-#if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
-# define memmove(d, s, l) (bcopy((s), (d), (l)))
-#endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */
-
-#if !HASSNPRINTF && !SFIO
-extern int snprintf __P((char *, size_t, const char *, ...));
-#endif /* !HASSNPRINTF && !SFIO */
-
-#if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# ifndef HASSTRERROR
-# define HASSTRERROR 1
-# endif /* ! HASSTRERROR */
-#endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) ||
- defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
-
-#if defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__)
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define WIFEXITED(st) (((st) & 0377) == 0)
-# define WEXITSTATUS(st) (((st) >> 8) & 0377)
-#endif /* defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__) */
-
-
-#include "sendmail/errstring.h"
+#include <sm/conf.h>
+#include <sm/errstring.h>
+#include <sendmail/pathnames.h>
static void err __P((int, const char *, ...));
static void usage __P((void));
@@ -134,7 +81,7 @@ xalloc(sz)
if (sz <= 0)
sz = 1;
- p = malloc((unsigned) sz);
+ p = malloc(sz);
if (p == NULL)
err(EX_TEMPFAIL, "out of memory");
return (p);
@@ -148,7 +95,7 @@ main(argc, argv)
int ch, debug, i, pdes[2], pid, status;
size_t fplen = 0, fptlen = 0, len;
off_t offset;
- FILE *fp;
+ SM_FILE_T *fp;
char *addrp = NULL, *domain, *p, *t;
char *from_path, *from_sys, *from_user;
char **args, buf[2048], lbuf[2048];
@@ -186,8 +133,9 @@ main(argc, argv)
for (offset = 0; ; )
{
/* Get and nul-terminate the line. */
- if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
- exit(EX_DATAERR);
+ if (sm_io_fgets(smioin, SM_TIME_DEFAULT, lbuf,
+ sizeof(lbuf)) == NULL)
+ err(EX_DATAERR, "no data");
if ((p = strchr(lbuf, '\n')) == NULL)
err(EX_DATAERR, "line too long");
*p = '\0';
@@ -221,7 +169,10 @@ main(argc, argv)
}
*t = '\0';
if (debug)
- fprintf(stderr, "remote from: %s\n", p);
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "remote from: %s\n",
+ p);
break;
}
}
@@ -241,7 +192,9 @@ main(argc, argv)
err(EX_DATAERR,
"corrupted From line: %s", lbuf);
if (debug)
- fprintf(stderr, "bang: %s\n", p);
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "bang: %s\n", p);
}
}
@@ -261,8 +214,10 @@ main(argc, argv)
{
from_sys = newstr(p);
if (debug)
- fprintf(stderr, "from_sys: %s\n",
- from_sys);
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "from_sys: %s\n",
+ from_sys);
}
/* Concatenate to the path string. */
@@ -271,14 +226,14 @@ main(argc, argv)
{
fplen = 0;
if ((from_path = malloc(fptlen = 256)) == NULL)
- err(EX_TEMPFAIL, NULL);
+ err(EX_TEMPFAIL, "out of memory");
}
if (fplen + len + 2 > fptlen)
{
- fptlen += MAX(fplen + len + 2, 256);
+ fptlen += SM_MAX(fplen + len + 2, 256);
if ((from_path = realloc(from_path,
fptlen)) == NULL)
- err(EX_TEMPFAIL, NULL);
+ err(EX_TEMPFAIL, "out of memory");
}
memmove(from_path + fplen, p, len);
fplen += len;
@@ -302,36 +257,40 @@ main(argc, argv)
if (debug)
{
if (from_path != NULL)
- fprintf(stderr, "from_path: %s\n", from_path);
- fprintf(stderr, "from_user: %s\n", from_user);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "from_path: %s\n",
+ from_path);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "from_user: %s\n", from_user);
}
if (offset != -1)
- offset = (off_t)ftell(stdin);
+ offset = (off_t)sm_io_tell(smioin, SM_TIME_DEFAULT);
}
- /* Allocate args (with room for sendmail args as well as recipients) */
+ /* Allocate args (with room for sendmail args as well as recipients */
args = (char **)xalloc(sizeof(*args) * (10 + argc));
i = 0;
args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */
+ args[i++] = "-G"; /* relay submission */
args[i++] = "-oee"; /* No errors, just status. */
args[i++] = "-odq"; /* Queue it, don't try to deliver. */
args[i++] = "-oi"; /* Ignore '.' on a line by itself. */
/* set from system and protocol used */
if (from_sys == NULL)
- snprintf(buf, sizeof(buf), "-p%s", domain);
+ sm_snprintf(buf, sizeof(buf), "-p%s", domain);
else if (strchr(from_sys, '.') == NULL)
- snprintf(buf, sizeof(buf), "-p%s:%s.%s",
+ sm_snprintf(buf, sizeof(buf), "-p%s:%s.%s",
domain, from_sys, domain);
else
- snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
+ sm_snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
args[i++] = newstr(buf);
/* Set name of ``from'' person. */
- snprintf(buf, sizeof(buf), "-f%s%s",
+ sm_snprintf(buf, sizeof(buf), "-f%s%s",
from_path ? from_path : "", from_user);
args[i++] = newstr(buf);
@@ -354,7 +313,7 @@ main(argc, argv)
len = strlen(*argv) + 3;
if ((args[i] = malloc(len)) == NULL)
err(EX_TEMPFAIL, "Cannot malloc");
- snprintf(args[i++], len, "<%s>", *argv);
+ sm_snprintf(args[i++], len, "<%s>", *argv);
}
argv++;
argc--;
@@ -367,9 +326,11 @@ main(argc, argv)
if (debug)
{
- fprintf(stderr, "Sendmail arguments:\n");
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Sendmail arguments:\n");
for (i = 0; args[i] != NULL; i++)
- fprintf(stderr, "\t%s\n", args[i]);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "\t%s\n", args[i]);
}
/*
@@ -388,12 +349,12 @@ main(argc, argv)
}
if (pipe(pdes) < 0)
- err(EX_OSERR, NULL);
+ err(EX_OSERR, "pipe failed");
- switch (pid = FORK())
+ switch (pid = fork())
{
case -1: /* Err. */
- err(EX_OSERR, NULL);
+ err(EX_OSERR, "fork failed");
/* NOTREACHED */
case 0: /* Child. */
@@ -404,25 +365,27 @@ main(argc, argv)
}
(void) close(pdes[1]);
(void) execv(_PATH_SENDMAIL, args);
- _exit(127);
+ err(EX_UNAVAILABLE, "%s", _PATH_SENDMAIL);
/* NOTREACHED */
}
- if ((fp = fdopen(pdes[1], "w")) == NULL)
- err(EX_OSERR, NULL);
+ if ((fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &(pdes[1]),
+ SM_IO_WRONLY, NULL)) == NULL)
+ err(EX_OSERR, "sm_io_open failed");
(void) close(pdes[0]);
/* Copy the file down the pipe. */
do
{
- (void) fprintf(fp, "%s", lbuf);
- } while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", lbuf);
+ } while (sm_io_fgets(smioin, SM_TIME_DEFAULT, lbuf,
+ sizeof(lbuf)) != NULL);
- if (ferror(stdin))
- err(EX_TEMPFAIL, "stdin: %s", errstring(errno));
+ if (sm_io_error(smioin))
+ err(EX_TEMPFAIL, "stdin: %s", sm_errstring(errno));
- if (fclose(fp))
- err(EX_OSERR, NULL);
+ if (sm_io_close(fp, SM_TIME_DEFAULT))
+ err(EX_OSERR, "sm_io_close failed");
if ((waitpid(pid, &status, 0)) == -1)
err(EX_OSERR, "%s", _PATH_SENDMAIL);
@@ -441,16 +404,11 @@ main(argc, argv)
static void
usage()
{
- (void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "usage: rmail [-T] [-D domain] user ...\n");
exit(EX_USAGE);
}
-#ifdef __STDC__
-# include <stdarg.h>
-#else /* __STDC__ */
-# include <varargs.h>
-#endif /* __STDC__ */
-
static void
#ifdef __STDC__
err(int eval, const char *fmt, ...)
@@ -461,15 +419,15 @@ err(eval, fmt, va_alist)
va_dcl
#endif /* __STDC__ */
{
- va_list ap;
-#ifdef __STDC__
- va_start(ap, fmt);
-#else /* __STDC__ */
- va_start(ap);
-#endif /* __STDC__ */
- (void) fprintf(stderr, "rmail: ");
- (void) vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void) fprintf(stderr, "\n");
+ SM_VA_LOCAL_DECL
+
+ if (fmt != NULL)
+ {
+ SM_VA_START(ap, fmt);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "rmail: ");
+ (void) sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap);
+ SM_VA_END(ap);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\n");
+ }
exit(eval);
}
diff --git a/contrib/sendmail/smrsh/Makefile.m4 b/contrib/sendmail/smrsh/Makefile.m4
index 7e4718f..c9d1786 100644
--- a/contrib/sendmail/smrsh/Makefile.m4
+++ b/contrib/sendmail/smrsh/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
@@ -8,7 +9,7 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `smrsh')
define(`bldINSTALL_DIR', `E')
define(`bldSOURCES', `smrsh.c ')
-bldPUSH_SMLIB(`smutil')
+bldPUSH_SMLIB(`sm')
bldPRODUCT_END
bldPRODUCT_START(`manpage', `smrsh')
diff --git a/contrib/sendmail/smrsh/README b/contrib/sendmail/smrsh/README
index 8529463..7e22f86 100644
--- a/contrib/sendmail/smrsh/README
+++ b/contrib/sendmail/smrsh/README
@@ -75,7 +75,7 @@ You should NOT include interpreter programs such as sh(1), csh(1),
perl(1), uudecode(1) or the stream editor sed(1) in your list of
acceptable commands.
-If your platform doesn't have a default CMDDIR setting, you will
+If your platform doesn't have a default SMRSH_CMDDIR setting, you will
next need to create the directory /usr/adm/sm.bin and populate
it with the programs that your site feels are allowable for sendmail
to execute. This directory is explicitly specified in the source
@@ -153,4 +153,4 @@ a typical system follows:
host.domain# /usr/sbin/sendmail -bd -q30m
-$Revision: 8.6.16.1 $, Last updated $Date: 2000/10/09 20:39:55 $
+$Revision: 8.8 $, Last updated $Date: 2001/01/24 00:05:58 $
diff --git a/contrib/sendmail/smrsh/smrsh.8 b/contrib/sendmail/smrsh/smrsh.8
index 06a4bdb..f62454a 100644
--- a/contrib/sendmail/smrsh/smrsh.8
+++ b/contrib/sendmail/smrsh/smrsh.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1993 Eric P. Allman. All rights reserved.
.\" Copyright (c) 1993
@@ -9,9 +9,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: smrsh.8,v 8.11.16.2 2000/12/15 19:50:46 gshapiro Exp $
+.\" $Id: smrsh.8,v 8.15 2001/01/24 00:40:47 gshapiro Exp $
.\"
-.TH SMRSH 8 "$Date: 2000/12/15 19:50:46 $"
+.TH SMRSH 8 "$Date: 2001/01/24 00:40:47 $"
.SH NAME
smrsh \- restricted shell for sendmail
.SH SYNOPSIS
@@ -76,10 +76,10 @@ in the sm.bin directory (using the ``#!'' syntax);
it simply disallows execution of arbitrary programs.
.SH COMPILATION
Compilation should be trivial on most systems.
-You may need to use \-DPATH=\e"\fIpath\fP\e"
+You may need to use \-DSMRSH_PATH=\e"\fIpath\fP\e"
to adjust the default search path
(defaults to ``/bin:/usr/bin:/usr/ucb'')
-and/or \-DCMDBIN=\e"\fIdir\fP\e"
+and/or \-DSMRSH_CMDBIN=\e"\fIdir\fP\e"
to change the default program directory
(defaults to ``/usr/adm/sm.bin'').
.SH FILES
diff --git a/contrib/sendmail/smrsh/smrsh.c b/contrib/sendmail/smrsh/smrsh.c
index e21fee4..dfe38a6 100644
--- a/contrib/sendmail/smrsh/smrsh.c
+++ b/contrib/sendmail/smrsh/smrsh.c
@@ -11,18 +11,16 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* ! lint */
+ The Regents of the University of California. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.9 2001/04/24 04:11:51 ca Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.55 2001/09/11 04:05:22 gshapiro Exp $")
/*
** SMRSH -- sendmail restricted shell
@@ -55,7 +53,8 @@ static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.9 2001/04/24 04:11:51 ca Exp $";
*/
#include <unistd.h>
-#include <stdio.h>
+#include <sm/io.h>
+#include <sm/string.h>
#include <sys/file.h>
#include <string.h>
#include <ctype.h>
@@ -67,18 +66,16 @@ static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.9 2001/04/24 04:11:51 ca Exp $";
#include <syslog.h>
#include <stdlib.h>
-#ifndef TRUE
-# define TRUE 1
-# define FALSE 0
-#endif /* ! TRUE */
+#include <sm/conf.h>
+#include <sm/errstring.h>
/* directory in which all commands must reside */
#ifndef CMDDIR
-# if defined(HPUX10) || defined(HPUX11) || SOLARIS >= 20800
-# define CMDDIR "/var/adm/sm.bin"
-# else /* HPUX10 || HPUX11 || SOLARIS >= 20800 */
+# ifdef SMRSH_CMDDIR
+# define CMDDIR SMRSH_CMDDIR
+# else /* SMRSH_CMDDIR */
# define CMDDIR "/usr/adm/sm.bin"
-# endif /* HPUX10 || HPUX11 || SOLARIS >= 20800 */
+# endif /* SMRSH_CMDDIR */
#endif /* ! CMDDIR */
/* characters disallowed in the shell "-c" argument */
@@ -86,16 +83,13 @@ static char id[] = "@(#)$Id: smrsh.c,v 8.31.4.9 2001/04/24 04:11:51 ca Exp $";
/* default search path */
#ifndef PATH
-# define PATH "/bin:/usr/bin:/usr/ucb"
+# ifdef SMRSH_PATH
+# define PATH SMRSH_PATH
+# else /* SMRSH_PATH */
+# define PATH "/bin:/usr/bin:/usr/ucb"
+# endif /* SMRSH_PATH */
#endif /* ! PATH */
-#ifndef __P
-# include "sendmail/cdefs.h"
-#endif /* ! __P */
-
-extern size_t strlcpy __P((char *, const char *, size_t));
-extern size_t strlcat __P((char *, const char *, size_t));
-
char newcmdbuf[1000];
char *prg, *par;
@@ -115,8 +109,8 @@ char *prg, *par;
void
addcmd(s, cmd, len)
char *s;
- int cmd;
- int len;
+ bool cmd;
+ size_t len;
{
if (s == NULL || *s == '\0')
return;
@@ -124,7 +118,8 @@ addcmd(s, cmd, len)
if (sizeof newcmdbuf - strlen(newcmdbuf) <=
len + (cmd ? (strlen(CMDDIR) + 1) : 0))
{
- fprintf(stderr, "%s: command too long: %s\n", prg, par);
+ (void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: command too long: %s\n", prg, par);
#ifndef DEBUG
syslog(LOG_WARNING, "command too long: %.40s", par);
#endif /* ! DEBUG */
@@ -132,10 +127,10 @@ addcmd(s, cmd, len)
}
if (cmd)
{
- (void) strlcat(newcmdbuf, CMDDIR, sizeof newcmdbuf);
- (void) strlcat(newcmdbuf, "/", sizeof newcmdbuf);
+ (void) sm_strlcat(newcmdbuf, CMDDIR, sizeof newcmdbuf);
+ (void) sm_strlcat(newcmdbuf, "/", sizeof newcmdbuf);
}
- (void) strlcat(newcmdbuf, s, sizeof newcmdbuf);
+ (void) sm_strlcat(newcmdbuf, s, sizeof newcmdbuf);
}
int
@@ -147,7 +142,6 @@ main(argc, argv)
register char *q;
register char *r;
register char *cmd;
- int i;
int isexec;
int save_errno;
char *newenv[2];
@@ -163,8 +157,8 @@ main(argc, argv)
# endif /* ! LOG_MAIL */
#endif /* ! DEBUG */
- (void) strlcpy(pathbuf, "PATH=", sizeof pathbuf);
- (void) strlcat(pathbuf, PATH, sizeof pathbuf);
+ (void) sm_strlcpy(pathbuf, "PATH=", sizeof pathbuf);
+ (void) sm_strlcat(pathbuf, PATH, sizeof pathbuf);
newenv[0] = pathbuf;
newenv[1] = NULL;
@@ -176,7 +170,8 @@ main(argc, argv)
if (argc != 3 || strcmp(argv[1], "-c") != 0)
{
- fprintf(stderr, "Usage: %s -c command\n", prg);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Usage: %s -c command\n", prg);
#ifndef DEBUG
syslog(LOG_ERR, "usage");
#endif /* ! DEBUG */
@@ -199,19 +194,19 @@ main(argc, argv)
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
- (void) strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
+ (void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf);
for (p = specialbuf; *p != '\0'; p++)
*p |= '\200';
- (void) strlcat(specialbuf, SPECIALS, sizeof specialbuf);
+ (void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf);
/*
** Do a quick sanity check on command line length.
*/
- i = strlen(par);
- if (i > (sizeof newcmdbuf - sizeof CMDDIR - 2))
+ if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2))
{
- fprintf(stderr, "%s: command too long: %s\n", prg, par);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: command too long: %s\n", prg, par);
#ifndef DEBUG
syslog(LOG_WARNING, "command too long: %.40s", par);
#endif /* ! DEBUG */
@@ -220,7 +215,7 @@ main(argc, argv)
q = par;
newcmdbuf[0] = '\0';
- isexec = FALSE;
+ isexec = false;
while (*q)
{
@@ -236,10 +231,11 @@ main(argc, argv)
{
if (isexec)
{
- fprintf(stderr, "%s: missing command to exec\n",
- prg);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: missing command to exec\n",
+ prg);
#ifndef DEBUG
- syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
+ syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid());
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
@@ -269,15 +265,15 @@ main(argc, argv)
/* allow a few shell builtins */
if (strcmp(q, "exec") == 0 && p != NULL)
{
- addcmd("exec ", FALSE, strlen("exec "));
+ addcmd("exec ", false, strlen("exec "));
/* test _next_ arg */
q = ++p;
- isexec = TRUE;
+ isexec = true;
continue;
}
else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0)
{
- addcmd(cmd, FALSE, strlen(cmd));
+ addcmd(cmd, false, strlen(cmd));
/* test following chars */
}
else
@@ -285,23 +281,24 @@ main(argc, argv)
/*
** Check to see if the command name is legal.
*/
- (void) strlcpy(cmdbuf, CMDDIR, sizeof cmdbuf);
- (void) strlcat(cmdbuf, "/", sizeof cmdbuf);
- (void) strlcat(cmdbuf, cmd, sizeof cmdbuf);
+ (void) sm_strlcpy(cmdbuf, CMDDIR, sizeof cmdbuf);
+ (void) sm_strlcat(cmdbuf, "/", sizeof cmdbuf);
+ (void) sm_strlcat(cmdbuf, cmd, sizeof cmdbuf);
#ifdef DEBUG
- printf("Trying %s\n", cmdbuf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Trying %s\n", cmdbuf);
#endif /* DEBUG */
if (access(cmdbuf, X_OK) < 0)
{
/* oops.... crack attack possiblity */
- fprintf(stderr,
- "%s: %s not available for sendmail programs\n",
- prg, cmd);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s not available for sendmail programs\n",
+ prg, cmd);
if (p != NULL)
*p = ' ';
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: attempt to use %s",
- getuid(), cmd);
+ (int) getuid(), cmd);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
@@ -310,9 +307,9 @@ main(argc, argv)
** Create the actual shell input.
*/
- addcmd(cmd, TRUE, strlen(cmd));
+ addcmd(cmd, true, strlen(cmd));
}
- isexec = FALSE;
+ isexec = false;
if (p != NULL)
*p = ' ';
@@ -320,13 +317,15 @@ main(argc, argv)
break;
r = strpbrk(p, specialbuf);
- if (r == NULL) {
- addcmd(p, FALSE, strlen(p));
+ if (r == NULL)
+ {
+ addcmd(p, false, strlen(p));
break;
}
#if ALLOWSEMI
- if (*r == ';') {
- addcmd(p, FALSE, r - p + 1);
+ if (*r == ';')
+ {
+ addcmd(p, false, r - p + 1);
q = r + 1;
continue;
}
@@ -334,30 +333,34 @@ main(argc, argv)
if ((*r == '&' && *(r + 1) == '&') ||
(*r == '|' && *(r + 1) == '|'))
{
- addcmd(p, FALSE, r - p + 2);
+ addcmd(p, false, r - p + 2);
q = r + 2;
continue;
}
- fprintf(stderr, "%s: cannot use %c in command\n", prg, *r);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: cannot use %c in command\n", prg, *r);
#ifndef DEBUG
syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
- getuid(), *r, par);
+ (int) getuid(), *r, par);
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
} /* end of while *q */
if (isexec)
{
- fprintf(stderr, "%s: missing command to exec\n", prg);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: missing command to exec\n", prg);
#ifndef DEBUG
- syslog(LOG_CRIT, "uid %d: missing command to exec", getuid());
+ syslog(LOG_CRIT, "uid %d: missing command to exec",
+ (int) getuid());
#endif /* ! DEBUG */
exit(EX_UNAVAILABLE);
}
/* make sure we created something */
if (newcmdbuf[0] == '\0')
{
- fprintf(stderr, "Usage: %s -c command\n", prg);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Usage: %s -c command\n", prg);
#ifndef DEBUG
syslog(LOG_ERR, "usage");
#endif /* ! DEBUG */
@@ -369,15 +372,15 @@ main(argc, argv)
*/
#ifdef DEBUG
- printf("%s\n", newcmdbuf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf);
#endif /* DEBUG */
(void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, NULL, newenv);
save_errno = errno;
#ifndef DEBUG
- syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
+ syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno));
#endif /* ! DEBUG */
errno = save_errno;
- perror("/bin/sh");
+ sm_perror("/bin/sh");
exit(EX_OSFILE);
/* NOTREACHED */
return EX_OSFILE;
diff --git a/contrib/sendmail/src/Makefile.m4 b/contrib/sendmail/src/Makefile.m4
index 3fe0703..8004de4 100644
--- a/contrib/sendmail/src/Makefile.m4
+++ b/contrib/sendmail/src/Makefile.m4
@@ -1,12 +1,17 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
bldPRODUCT_START(`executable', `sendmail')
-define(`bldBIN_TYPE', `S')
+define(`bldBIN_TYPE', `G')
define(`bldINSTALL_DIR', `')
-define(`bldSOURCES', `main.c alias.c arpadate.c bf_'ifdef(`confSTDIO_TYPE', `confSTDIO_TYPE', `portable')`.c clock.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c readcf.c recipient.c savemail.c sfsasl.c shmticklib.c srvrsmtp.c stab.c stats.c sysexits.c timers.c trace.c udb.c usersmtp.c util.c version.c ')
+define(`bldSOURCES', `main.c alias.c arpadate.c bf.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c readcf.c recipient.c savemail.c sasl.c sfsasl.c shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c timers.c tls.c trace.c udb.c usersmtp.c util.c version.c ')
PREPENDDEF(`confENVDEF', `confMAPDEF')
+bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
+dnl hack: /etc/mail is not defined as "location of .cf" in the build system
+define(`bldTARGET_INST_DEP', ifdef(`confINST_DEP', `confINST_DEP',
+`${DESTDIR}/etc/mail/submit.cf ${DESTDIR}${MSPQ}'))dnl
define(`bldTARGET_LINKS', ifdef(`confLINKS', `confLINKS',
`${DESTDIR}${UBINDIR}/newaliases ${DESTDIR}${UBINDIR}/mailq ${DESTDIR}${UBINDIR}/hoststat ${DESTDIR}${UBINDIR}/purgestat')
)dnl
@@ -31,11 +36,45 @@ divert(bldTARGETS_SECTION)
statistics:
${CP} /dev/null statistics
+${DESTDIR}/etc/mail/submit.cf:
+ @echo "Please read INSTALL if anything fails while installing the binary."
+ @echo "${DESTDIR}/etc/mail/submit.cf will be installed now."
+ cd ${SRCDIR}/cf/cf && make install-submit-cf
+
+MSPQ=ifdef(`confMSP_QUEUE_DIR', `confMSP_QUEUE_DIR', `/var/spool/clientmqueue')
+
+${DESTDIR}${MSPQ}:
+ @echo "Please read INSTALL if anything fails while installing the binary."
+ @echo "You must have setup a new user ${MSPQOWN} and a new group ${GBINGRP}"
+ @echo "as explained in sendmail/SECURITY."
+ mkdir -p ${DESTDIR}${MSPQ}
+ chown ${MSPQOWN} ${DESTDIR}${MSPQ}
+ chgrp ${GBINGRP} ${DESTDIR}${MSPQ}
+ chmod 0770 ${DESTDIR}${MSPQ}
+
divert(0)
+ifdef(`confSETUSERID_INSTALL', `bldPUSH_INSTALL_TARGET(`install-set-user-id')')
+ifdef(`confMTA_INSTALL', `bldPUSH_INSTALL_TARGET(`install-sm-mta')')
ifdef(`confNO_HELPFILE_INSTALL',, `bldPUSH_INSTALL_TARGET(`install-hf')')
ifdef(`confNO_STATISTICS_INSTALL',, `bldPUSH_INSTALL_TARGET(`install-st')')
divert(bldTARGETS_SECTION)
+
+install-set-user-id: bldCURRENT_PRODUCT ifdef(`confNO_HELPFILE_INSTALL',, `install-hf') ifdef(`confNO_STATISTICS_INSTALL',, `install-st') ifdef(`confNO_MAN_BUILD',, `install-docs')
+ ${INSTALL} -c -o ${S`'BINOWN} -g ${S`'BINGRP} -m ${S`'BINMODE} bldCURRENT_PRODUCT ${DESTDIR}${M`'BINDIR}
+ for i in ${sendmailTARGET_LINKS}; do \
+ rm -f $$i; \
+ ln -s ${M`'BINDIR}/sendmail $$i; \
+ done
+
+define(`confMTA_LINKS', `${DESTDIR}${UBINDIR}/newaliases ${DESTDIR}${UBINDIR}/mailq ${DESTDIR}${UBINDIR}/hoststat ${DESTDIR}${UBINDIR}/purgestat')
+install-sm-mta: bldCURRENT_PRODUCT
+ ${INSTALL} -c -o ${M`'BINOWN} -g ${M`'BINGRP} -m ${M`'BINMODE} bldCURRENT_PRODUCT ${DESTDIR}${M`'BINDIR}/sm-mta
+ for i in confMTA_LINKS; do \
+ rm -f $$i; \
+ ln -s ${M`'BINDIR}/sm-mta $$i; \
+ done
+
install-hf:
if [ ! -d ${DESTDIR}${HFDIR} ]; then mkdir -p ${DESTDIR}${HFDIR}; else :; fi
${INSTALL} -c -o ${UBINOWN} -g ${UBINGRP} -m 444 helpfile ${DESTDIR}${HFFILE}
diff --git a/contrib/sendmail/src/README b/contrib/sendmail/src/README
index fd8d5ee..3f984d9 100644
--- a/contrib/sendmail/src/README
+++ b/contrib/sendmail/src/README
@@ -1,4 +1,4 @@
-# Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
# All rights reserved.
# Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
# Copyright (c) 1988
@@ -9,17 +9,14 @@
# the sendmail distribution.
#
#
-# $Id: README,v 8.263.2.1.2.38 2001/08/15 22:07:11 gshapiro Exp $
+# $Id: README,v 8.345 2002/01/09 18:04:30 ca Exp $
#
This directory contains the source files for sendmail(TM).
-*********************
-!! DO NOT USE MAKE !! in this directory to compile sendmail --
-********************* instead, use the "Build" script located in
-the sendmail directory. It will build an appropriate Makefile, and
-create an appropriate obj.* subdirectory so that multiplatform
-support works easily.
+ *******************************************************************
+ !! Read sendmail/SECURITY for important installation information !!
+ *******************************************************************
**********************************************************
** Read below for more details on building sendmail. **
@@ -32,7 +29,7 @@ support works easily.
For detailed instructions, please read the document ../doc/op/op.me:
- eqn ../doc/op/op.me | pic | ditroff -me
+ cd ../doc/op ; make op.ps op.txt
Sendmail is a trademark of Sendmail, Inc.
@@ -123,7 +120,9 @@ MAP_REGEX Regular Expression support. You will need to use an
operating system which comes with the POSIX regex()
routines or install a regexp library such as libregex from
the Free Software Foundation.
-PH_MAP PH map support. You will need the qi PH package.
+DNSMAP DNS map support. Requires NAMED_BIND.
+PH_MAP PH map support. You will need the libphclient library from
+ the nph package (http://www-dev.cso.uiuc.edu/ph/nph/).
MAP_NSD nsd map support (IRIX 6.5 and later).
>>> NOTE WELL for NEWDB support: If you want to get ndbm support, for
@@ -202,10 +201,13 @@ SYS5SIGNALS Use System V signal semantics -- the signal handler
signal handler stays in force until an exec or an
explicit delete. Implied by SYSTEM5.
SYS5SETPGRP Use System V setpgrp() semantics. Implied by SYSTEM5.
+HASNICE Define this to zero if you lack the nice(2) system call.
+HASRRESVPORT Define this to zero if you lack the rresvport(3) system call.
HASFCHMOD Define this to one if you have the fchmod(2) system call.
This improves security.
HASFCHOWN Define this to one if you have the fchown(2) system call.
- This is required for the TrustedUser option.
+ This is required for the TrustedUser option if sendmail
+ must rebuild an (alias) map.
HASFLOCK Set this if you prefer to use the flock(2) system call
rather than using fcntl-based locking. Fcntl locking
has some semantic gotchas, but many vendor systems
@@ -251,6 +253,15 @@ USESETEUID Define this to 1 if you have a seteuid(2) system call that
Posix.1. The test program ../test/t_seteuid.c will try
this out on your system. If you define both HASSETREUID
and USESETEUID, the former is ignored.
+HASSETEGID Define this if you have setegid(2) and it can be
+ used to set the saved gid. Please run t_dropgid in
+ test/ if you are not sure whether the call works.
+HASSETREGID Define this if you have setregid(2) and it can be
+ used to set the saved gid. Please run t_dropgid in
+ test/ if you are not sure whether the call works.
+HASSETRESGID Define this if you have setresgid(2) and it can be
+ used to set the saved gid. Please run t_dropgid in
+ test/ if you are not sure whether the call works.
HASLSTAT Define this if you have symbolic links (and thus the
lstat(2) system call). This improves security. Unlike
most other options, this one is on by default, so you
@@ -273,17 +284,13 @@ HASURANDOMDEV Define this if your system has /dev/urandom(4).
HASSTRERROR Define this if you have the libc strerror(3) function (which
should be declared in <errno.h>), and it should be used
instead of sys_errlist.
-NEEDGETOPT Define this if you need a reimplementation of getopt(3).
+SM_CONF_GETOPT Define this as 0 if you need a reimplementation of getopt(3).
On some systems, getopt does very odd things if called
to scan the arguments twice. This flag will ask sendmail
to compile in a local version of getopt that works
properly.
NEEDSTRTOL Define this if your standard C library does not define
strtol(3). This will compile in a local version.
-NEEDVPRINTF Define this if your standard C library does not define
- vprintf(3). Note that the resulting fake implementation
- is not very elegant and may not even work on some
- architectures.
NEEDFSYNC Define this if your standard C library does not define
fsync(2). This will try to simulate the operation using
fcntl(2); if that is not available it does nothing, which
@@ -446,9 +453,6 @@ SIOCGIFNUM_IS_BROKEN
Set this if your system has an SIOCGIFNUM ioctl defined,
but it doesn't behave the same way as "most" systems
(Solaris, HP-UX).
-NEED_PERCENTQ Set this if your system doesn't support the printf
- format strings %lld or %llu. If this is set, %qd and
- %qu are used instead.
FAST_PID_RECYCLE
Set this if your system can reuse the same PID in the same
second.
@@ -456,13 +460,22 @@ SO_REUSEADDR_IS_BROKEN
Set this if your system has a setsockopt() SO_REUSEADDR
flag but doesn't pay attention to it when trying to bind a
socket to a recently closed port.
-SNPRINTF_IS_BROKEN
- Set this if your system has an snprintf() implementation
- which does not NUL terminate the string being filled in.
- Use test/t_snprintf.c to test your system.
NEEDSGETIPNODE Set this if your system supports IPv6 but doesn't include
the getipnodeby{name,addr}() functions. Set automatically
for Linux's glibc.
+PIPELINING Support SMTP PIPELINING (set by default).
+USING_NETSCAPE_LDAP
+ Set this if LDAPMAP is set and your LDAP libraries are from
+ (or are derived from) Netscape's implementation, which
+ requires that the return value of ldap_first_attribute()
+ and ldap_next_attribute() be ldap_memfree()'d.
+NEEDLINK Set this if your system doesn't have a link() call. It
+ will create a copy of the file instead of a hardlink.
+USE_ENVIRON Set this to 1 to access process environment variables from
+ the external variable environ instead of the third
+ parameter of main().
+USE_DOUBLE_FORK By default this is on (1). Set it to 0 to suppress the
+ extra fork() used to avoid intermediate zombies.
+-----------------------+
@@ -529,8 +542,6 @@ NETUNIX Define this to get Unix domain networking support. Defined
support this networking domain.
NETNS Define this to get NS networking support.
NETX25 Define this to get X.25 networking support.
-SMTP Define this to get the SMTP code. Implied by NETINET
- or NETISO.
NAMED_BIND If non-zero, include DNS (name daemon) support, including
MX support. The specs say you must use this if you run
SMTP. You don't have to be running a name server daemon
@@ -538,12 +549,6 @@ NAMED_BIND If non-zero, include DNS (name daemon) support, including
including remote access to another machine, requires this
option. Defined by default in conf.h. Define it to zero
ONLY on machines that do not use DNS in any way.
-QUEUE Define this to get queueing code. Implied by NETINET
- or NETISO; required by SMTP. This gives you other good
- stuff -- it should be on.
-DAEMON Define this to get general network support. Implied by
- NETINET or NETISO. Defined by default in conf.h. You
- almost certainly want it on.
MATCHGECOS Permit fuzzy matching of user names against the full
name (GECOS) field in the /etc/passwd file. This should
probably be on, since you can disable it from the config
@@ -568,7 +573,7 @@ SHARE_V1 Support for the fair share scheduler, version 1. Setting to
1 causes final delivery to be done using the recipients
resource limitations. So far as I know, this is only
supported on ConvexOS.
-SASL Enables SMTP AUTH (RFC 2554). This requires the Cyrus SASL
+SASL Enables SMTP AUTH (RFC 2554). This requires the Cyrus SASL
library (ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/). Please
install at least version 1.5.13. See below for further
information: SASL COMPILATION AND CONFIGURATION. If your
@@ -576,31 +581,27 @@ SASL Enables SMTP AUTH (RFC 2554). This requires the Cyrus SASL
to its version number using a simple conversion: a.b.c
-> c + b*100 + a*10000, e.g. for 1.5.9 define SASL=10509.
Note: Using an older version than 1.5.5 of Cyrus SASL is
- not supported. Starting with version 1.5.10, setting SASL=1
- is sufficient. Any value other than 1 (or 0) will be
+ not supported. Starting with version 1.5.10, setting SASL=1
+ is sufficient. Any value other than 1 (or 0) will be
compared with the actual version found and if there is a
mismatch, compilation will fail.
EGD Define this if your system has EGD installed, see
- http://www.lothar.com/tech/crypto/ . It should be used to
+ http://www.lothar.com/tech/crypto/ . It should be used to
seed the PRNG for STARTTLS if HASURANDOMDEV is not defined.
-STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL
- (http://www.OpenSSL.org/) and sfio (see below).
- Use OpenSSL 0.9.5a or later (if compatible with this
- version), do not use 0.9.3.
+STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL
+ (http://www.OpenSSL.org/); use OpenSSL 0.9.5a or later
+ (if compatible with this version), do not use 0.9.3.
See STARTTLS COMPILATION AND CONFIGURATION for further
information.
TLS_NO_RSA Turn off support for RSA algorithms in STARTTLS.
-SFIO Uses sfio instead of stdio. sfio is available from AT&T
- (http://www.research.att.com/sw/tools/sfio/). If this
- compile flag is set, confSTDIO_TYPE must be set to portable.
- This compile flag is necessary for STARTTLS; it also
- enables the security layer of SASL. The sfio include file
- stdio.h must be installed in a subdirectory called sfio,
- i.e., if you install sfio in /usr/local, stdio.h should
- be in /usr/local/include/sfio, and libsfio.a should be in
- /usr/local/lib. Notice: read the sfio section in
- OPERATING SYSTEM AND COMPILE QUIRKS.
-
+MILTER Turn on support for external filters using the Milter API.
+ See libmilter/README for more information.
+REQUIRES_DIR_FSYNC Turn on support for file systems that require to
+ call fsync() for a directory if the meta-data in it has
+ been changed. This should be turned on at least for
+ ReiserFS; it is enabled by default for Linux. An alternative
+ to this compile time flag is to mount the queue directory
+ without the -async option, or using chattr +S on Linux.
Generic notice: If you enable a compile time option that needs
libraries or include files that don't come with sendmail or are
@@ -642,25 +643,21 @@ YOU HEADACHES!
When attempting to canonify a hostname, some broken name servers will
return SERVFAIL (a temporary failure) on T_AAAA (IPv6) lookups. If you
-want to excuse this behavior, compile sendmail with
--D_FFR_WORKAROUND_BROKEN_NAMESERVERS and add WorkAroundBrokenAAAA to your
-ResolverOptions setting. However, instead, we recommend catching the
-problem and reporting it to the name server administrator so we can rid the
-world of broken name servers.
+want to excuse this behavior, include WorkAroundBrokenAAAA in
+ResolverOptions. However, instead, we recommend catching the problem and
+reporting it to the name server administrator so we can rid the world of
+broken name servers.
+----------------------------------------+
| STARTTLS COMPILATION AND CONFIGURATION |
+----------------------------------------+
-Please read the docs accompanying the OpenSSL library and sfio.
-You have to compile and install both libraries before you can compile
+Please read the documentation accompanying the OpenSSL library. You
+have to compile and install the OpenSSL libraries before you can compile
sendmail. See devtools/README how to set the correct compile time
parameters; you should at least set the following variables:
-define(`confSTDIO_TYPE', `portable')
-APPENDDEF(`conf_sendmail_ENVDEF', `-DSFIO')
-APPENDDEF(`conf_sendmail_LIBS', `-lsfio')
APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS')
APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto')
@@ -681,10 +678,6 @@ and try again. Then take a look at the logfile and see whether
there are any problems listed about permissions (unsafe files)
or the validity of X.509 certificates.
-Note: sfio must be used in all libraries with which sendmail exchanges
-file pointers. An example is PH map support. This does not apply to the
-usual libraries, e.g., OpenSSL, Berkeley DB, Cyrus SASL.
-
Further information can be found via:
http://www.sendmail.org/tips/
@@ -693,11 +686,11 @@ http://www.sendmail.org/tips/
| SASL COMPILATION AND CONFIGURATION |
+------------------------------------+
-Please read the docs accompanying the library (INSTALL and README).
-If you use Berkeley DB for Cyrus SASL then you must compile sendmail
-with the same version of Berkeley DB. See devtools/README how to
-set the correct compile time parameters; you should at least set
-the following variables:
+Please read the documentation accompanying the Cyrus SASL library
+(INSTALL and README). If you use Berkeley DB for Cyrus SASL then
+you must compile sendmail with the same version of Berkeley DB.
+See devtools/README how to set the correct compile time parameters;
+you should at least set the following variables:
APPENDDEF(`conf_sendmail_ENVDEF', `-DSASL')
APPENDDEF(`conf_sendmail_LIBS', `-lsasl')
@@ -709,10 +702,10 @@ BUILDING SENDMAIL.
You have to select and install authentication mechanisms and tell
sendmail where to find the sasl library and the include files (see
-devtools/README for the parameters to set). Setup the required
+devtools/README for the parameters to set). Setup the required
users and passwords as explained in the SASL documentation. See
-also cf/README for authentication related options (esp. DefaultAuthInfo
-if you want authentication between MTAs).
+also cf/README for authentication related options (especially
+DefaultAuthInfo if you want authentication between MTAs).
To perform an initial test, connect to your sendmail daemon
(telnet localhost 25) and issue a EHLO localhost and see whether
@@ -731,6 +724,9 @@ http://www.sendmail.org/tips/
+-------------------------------------+
GCC problems
+ When compiling with "gcc -O -Wall" specify "-DSM_OMIT_BOGUS_WARNINGS"
+ too (see include/sm/cdefs.h for more info).
+
*****************************************************************
** IMPORTANT: DO NOT USE OPTIMIZATION (``-O'') IF YOU ARE **
** RUNNING GCC 2.4.x or 2.5.x. THERE IS A BUG IN THE GCC **
@@ -774,9 +770,9 @@ Configuration file location
binary.
NETINFO systems use NETINFO to determine the location of
- sendmail.cf. The full path to sendmail.cf is stored as the value of
+ sendmail.cf. The full path to sendmail.cf is stored as the value of
the "sendmail.cf" property in the "/locations/sendmail"
- subdirectory of NETINFO. Set the value of this property to
+ subdirectory of NETINFO. Set the value of this property to
"/etc/mail/sendmail.cf" (without the quotes) to use this new
default location for Sendmail 8.10.0 and higher.
@@ -789,6 +785,23 @@ ControlSocket permissions
owned directories which do not permit non-root to r/w/x through them.
The long term fix is for all kernels to upgrade to 4.4BSD semantics.
+HP MPE/iX
+ The MPE-specific code within sendmail emulates a set-user-id root
+ environment for the sendmail binary. But there is no root uid 0 on
+ MPE, nor is there any support for set-user-id programs. Even when
+ sendmail thinks it is running as uid 0, it will still have the file
+ access rights of the underlying non-zero uid, but because sendmail is
+ an MPE priv-mode program it will still be able to call setuid() to
+ successfully switch to a new uid.
+
+ MPE setgid() semantics don't quite work the way sendmail expects, so
+ special emulation is done here also.
+
+ This uid/gid emulation is enabled via the setuid/setgid file mode bits
+ which are not currently used by MPE. Code in libsm/mpeix.c examines
+ these bits and enables emulation if they have been set, i.e.,
+ chmod u+s,g+s /SENDMAIL/CURRENT/SENDMAIL.
+
SunOS 4.x (Solaris 1.x)
You may have to use -lresolv on SunOS. However, beware that
this links in a new version of gethostbyname that does not
@@ -901,7 +914,7 @@ Solaris 2.4 (SunOS 5.4)
>> testing and debugging mechanisms. It was decided that the only
>> secure way to do this was to allow a `trusted' path to be used in
>> LD_LIBRARY_PATH. The only trusted directory we presently define
- >> is /usr/lib. Thus a setuid root developer could play with some
+ >> is /usr/lib. Thus a set-user-ID root developer could play with some
>> alternative shared object implementations and place them in
>> /usr/lib (being root we assume they'ed have access to write in this
>> directory). This change was made as part of 1155380 - after a
@@ -920,7 +933,7 @@ Solaris 2.5.1 (SunOS 5.5.1) and 2.6 (SunOS 5.6)
Apparently Solaris 2.5.1 patch 103663-01 installs a new
/usr/include/resolv.h file that defines the __P macro without
checking to see if it is already defined. This new resolv.h is also
- included in the Solaris 2.6 distribution. This causes compile
+ included in the Solaris 2.6 distribution. This causes compile
warnings such as:
In file included from daemon.c:51:
@@ -933,8 +946,7 @@ Solaris 2.5.1 (SunOS 5.5.1) and 2.6 (SunOS 5.6)
#undef __P
#include "/usr/include/resolv.h"
- Sun is aware of the problem (Sun bug ID 4081053) and it will be fixed
- in Solaris 2.7.
+ This problem was fixed in Solaris 7 (Sun bug ID 4081053).
Solaris 7 (SunOS 5.7)
Solaris 7 includes LDAP libraries but the implementation was
@@ -950,6 +962,23 @@ Solaris 7 (SunOS 5.7)
to ldap_set_option for LDAP_OPT_REFERRALS in ldapmap_setopts if
LDAP support is compiled in sendmail.
+Solaris 8 and later (SunOS 5.8 and later)
+ Solaris 8 and later can optionally install LDAP support. If you
+ have installed the Entire Distribution meta-cluster, you can use
+ the following in devtools/Site/site.SunOS.5.8.m4 (or other
+ appropriately versioned file) to enable LDAP:
+
+ APPENDDEF(`confMAPDEF', `-DLDAPMAP')
+ APPENDDEF(`confLIBS', `-lldap')
+
+Solaris 9 and later (SunOS 5.9 and later)
+ Solaris 9 and later have a revised LDAP library, libldap.so.5,
+ which is derived from a Netscape implementation, thus requiring
+ that USING_NETSCAPE_LDAP be defined in conjunction with LDAPMAP:
+
+ APPENDDEF(`confMAPDEF', `-DLDAPMAP -DUSING_NETSCAPE_LDAP')
+ APPENDDEF(`confLIBS', `-lldap')
+
Solaris
If you are using dns for hostname resolution on Solaris, make sure
that the 'dns' entry is last on the hosts line in
@@ -1070,6 +1099,9 @@ IRIX 6.x
less than 16 bits long unless they are 8 bits; IRIX 6.2 has
some other sized structs. See
http://www.bitmechanic.com/mail-archives/mysql/current/0418.html
+ This problem seems to be fixed by gcc v2.95.2, gcc v2.8.1
+ is reported as broken. Check your gcc version for this bug
+ before installing sendmail.
IRIX 6.4
The IRIX 6.5.4 version of /bin/m4 does not work properly with
@@ -1102,13 +1134,13 @@ BSDI (BSD/386) 1.0, NetBSD 0.9, FreeBSD 1.0
I haven't had a chance to test this myself.
The M4 shipped in FreeBSD and NetBSD 0.9 don't handle the config
- files properly. One must use either GNU m4 1.1 or the PD-M4
+ files properly. One must use either GNU m4 1.1 or the PD-M4
recently posted in comp.os.386bsd.bugs (and maybe others).
NetBSD-current includes the PD-M4 (as stated in the NetBSD file
CHANGES).
- FreeBSD 1.0 RELEASE has uname(2) now. Use -DUSEUNAME in order to
- use it (look into devtools/OS/FreeBSD). NetBSD-current may have
+ FreeBSD 1.0 RELEASE has uname(2) now. Use -DUSEUNAME in order to
+ use it (look into devtools/OS/FreeBSD). NetBSD-current may have
it too but it has not been verified.
The latest version of Berkeley DB uses a different naming
@@ -1134,6 +1166,12 @@ BSDI (BSD/386) 1.0, NetBSD 0.9, FreeBSD 1.0
APPENDDEF(`confOBJADD', `oldbind.compat.o')
+OpenBSD (up to 2.9 Release), NetBSD, FreeBSD (up to 4.3-RELEASE)
+ m4 from *BSD won't handle libsm/Makefile.m4 properly, since the
+ maximum length for strings is too short. You need to use GNU m4
+ or patch m4, see for example:
+ http://FreeBSD.org/cgi/cvsweb.cgi/src/usr.bin/m4/eval.c.diff?r1=1.11&r2=1.12
+
A/UX
Date: Tue, 12 Oct 1993 18:28:28 -0400 (EDT)
From: "Eric C. Hagberg" <hagberg@med.cornell.edu>
@@ -1151,7 +1189,7 @@ A/UX
What I did was to get the gnu-dbm-1.6 package, compile it, and
then re-compile sendmail with "-lgdbm", "-DNDBM", and using the
- ndbm.h header file that comes with the gnu-package. This makes
+ ndbm.h header file that comes with the gnu-package. This makes
things behave properly.
[NOTE: see comment above about GDBM]
@@ -1171,14 +1209,18 @@ SCO Unix
to know that if they are on SCO, they had better set
OI-dnsrch
or they will core dump as soon as they try to use the resolver.
- ie. although SCO has _res.dnsrch defined, and is kinda BIND 4.8.3, it
- does not inititialise it, nor does it understand 'search' in
+ i.e., although SCO has _res.dnsrch defined, and is kinda BIND 4.8.3,
+ it does not inititialise it, nor does it understand 'search' in
/etc/named.boot.
- sigh -
According to SCO, the m4 which ships with UnixWare 2.1.2 is broken.
We recommend installing GNU m4 before attempting to build sendmail.
+ On some versions a bogus error value is listed if connections
+ time out (large negative number). To avoid this explicitly set
+ Timeout.connect to a reasonable value (several minutes).
+
DG/UX
Doug Anderson <dlander@afterlife.ncsc.mil> has successfully run
V8 on the DG/UX 5.4.2 and 5.4R3.x platforms under heavy usage.
@@ -1205,8 +1247,8 @@ HP-UX 8.00
From: Kimmo Suominen <Kimmo.Suominen@lut.fi>
Subject: 8.6.5 w/ HP-UX 8.00 on s300
- Just compiled and fought with sendmail 8.6.5 on a HP9000/360 (ie. a
- series 300 machine) running HP-UX 8.00.
+ Just compiled and fought with sendmail 8.6.5 on a HP9000/360 (i.e.,
+ a series 300 machine) running HP-UX 8.00.
I was getting segmentation fault when delivering to a local user.
With debugging I saw it was faulting when doing _free@libc... *sigh*
@@ -1237,13 +1279,6 @@ Linux
with sendmail's version of cdefs.h. Deleting sendmail's version
on those systems should be non-harmful, and new versions don't care.
- Sendmail assumes that libc has snprintf, which has been true since
- libc 4.7.0. If you are running an older version, you will need to
- use -DHASSNPRINTF=0 in the Makefile. If may be able to use -lbsd
- (which includes snprintf) instead of turning this off on versions
- of libc between 4.4.4 and 4.7.0 (snprintf improves security, so
- you want to use this if at all possible).
-
NOTE ON LINUX & BIND: By default, the Makefile generated for Linux
includes header files in /usr/local/include and libraries in
/usr/local/lib. If you've installed BIND on your system, the header
@@ -1266,11 +1301,6 @@ Linux
implementation in the Linux 2.2.0 kernel and poll()-aware versions
of glib (at least up to 2.0.111).
- Some pre-glibc distributions of Linux include a syslog.h that does
- not work properly with SFIO. You can fix this by adding
- "#include <syslog.h>" to the SFIO version of stdio.h as the very
- first line.
-
glibc
glibc 2.2.1 (and possibly other versions) changed the value of
__RES in resolv.h but failed to actually provide the IPv6 API
@@ -1303,6 +1333,19 @@ AIX 4.X
gcc -Wl,-rpath /usr/lib -Wl,-rpath /lib -Wl,-rpath /usr/local/lib
+AIX 4.X If the test program t-event (and most others) in libsm fails,
+ check your compiler settings. It seems that the flags -qnoro or
+ -qnoroconst on some AIX versions trigger a compiler bug. Check
+ your compiler settings or use cc instead of xlc.
+
+AIX 4.0-4.2, maybe some AIX 4.3 versions
+ The AIX m4 implements a different mechanism for ifdef which is
+ inconsistent with other versions of m4. Therefore, it will not
+ work properly with the sendmail Build architecture or m4
+ configuration method. To work around this problem, please use
+ GNU m4 from ftp://ftp.gnu.org/pub/gnu/.
+ The problem seems to be solved in AIX 4.3.3 at least.
+
AIX 4.3.3
From: Valdis.Kletnieks@vt.edu
Date: Sun, 02 Jul 2000 03:58:02 -0400
@@ -1317,13 +1360,6 @@ AIX 4.3.3
2) Build against a real BIND 8.2.2 include/lib tree
3) Wait for IBM to fix it
-AIX 4.X
- The AIX m4 implements a different mechanism for ifdef which is
- inconsistent with other versions of m4. Therefore, it will not
- work properly with the sendmail Build architecture or m4
- configuration method. To work around this problem, please use
- GNU m4 from ftp://ftp.gnu.org/pub/gnu/.
-
AIX 3.x
This version of sendmail does not support MB, MG, and MR resource
records, which are supported by AIX sendmail.
@@ -1342,44 +1378,6 @@ AIX 3.1.x
If you don't care about load average throttling, just turn off
load average checking using -DLA_TYPE=LA_ZERO.
-AIX 2.2.1
- Date: Mon Dec 4 14:14:56 CST 1995
- From: Mark Whetzel <markw@antimatr.houston.tx.us>
- Subject: Porting sendmail 8.7.2 to AIX V2 on the RT.
-
- This version of sendmail does not support MB, MG, and MR resource
- records, which are supported by AIX sendmail.
-
- AIX V2 on the RT does not have 'paths.h'. Create a null
- file in the 'obj' directory to remove this compile error.
-
- A patch file is needed to get the BSD 'db' library to compile
- for AIX/RT. I have sent the necessary updates to the author,
- but they may not be immediately available.
- [NOTE: Berkeley DB version 2.X runs on AIX/RT.]
-
- The original AIX/RT resolver libraries are very old, and you
- should get the latest BIND to replace it. The 4.8.3 version
- has been tested, but 4.9.x is out and should work.
-
- To make the load average code work correctly requires an
- external routine, as the kernel does not maintain system
- load averages, similar to AIX V3.1.x. A reverse port of the
- older 1.05 'monitor' load average daemon code written by
- Jussi Maki that will work on AIX V2 for the RT is available
- by E-mail to Mark Whetzel <markw@antimatr.houston.tx.us>.
- That code depends on an external daemon to collect system
- load information, and the external routine 'getloadavg',
- that will return that information. The 'LA_SUBR' define
- will handle this for AIX V2 on the RT.
-
- Note: You will have to change devtools/OS/AIX.2 to correctly
- point to the locatons of the updated BIND source tree and
- the location of the 'newdb' tree and library location.
- You will also have to change devtools/OS/AIX.2 to know
- about the location of the 'getloadavg' routine if you use
- the LA_SUBR define.
-
RISC/os
RISC/os from MIPS is a merged AT&T/Berkeley system. When you
compile on that platform you will get duplicate definitions
@@ -1475,7 +1473,8 @@ UNICOS 8.0.3.4
running sendmail. Reported by Jerry G. DeLapp <jgd@acl.lanl.gov>.
Mac OS X (10.0.X)
- From: Mike Zimmerman <zimmy@torrentnet.com>
+ From Mike Zimmerman <zimmy@torrentnet.com>:
+
From scratch here is what Darwin users need to do to the standard
10.0.0, 10.0.1 install to get sendmail working.
From http://www.macosx.com/forums/showthread.php?s=6dac0e9e1f3fd118a4870a8a9b559491&threadid=2242:
@@ -1489,6 +1488,28 @@ Mac OS X (10.0.X)
Remove the "&" after the sendmail command:
/usr/sbin/sendmail -bd -q1h
+ From Carsten Klapp <carsten.klapp@home.com>:
+
+ The easiest workaround is to remove the group-writable permission
+ for the root directory and the symbolic /etc inherits this
+ change. While this does fix sendmail, the unfortunate side-effect
+ is the OS X admin will no longer be able to manipulate icons in the
+ top level of the Startup disk unless logged into the GUI as the
+ superuser.
+
+ In applying the alternate workaround, care must be taken while
+ swapping the symlink /etc with the directory /private/etc. In all
+ likelihood any admin who is concerned with this sendmail error has
+ enough experience to not accidentally harm anything in the process.
+
+ a. Swap the /etc symlink with /private/etc (as superuser):
+ rm /etc
+ mv /private/etc /etc
+ ln -s /etc /private/etc
+
+ b. Set / to group unwritable (as superuser):
+ chmod g-w /
+
GNU getopt
I'm told that GNU getopt has a problem in that it gets confused
by the double call. Use the version in conf.c instead.
@@ -1555,30 +1576,14 @@ OpenSSL
Do not use 0.9.3, but OpenSSL 0.9.5a or later if compatible with
0.9.5a.
-sfio
- You may run into problems if you use sfio2000 (the body of a
- message is lost). Use sfio1999 instead; however, it also has
- a bug that can cause sendmail to fail. A patch has been provided
- by Petr Lampa of Brno University of Technology, which is given here:
-
-diff -rc ../../../../sfio/src/lib/sfio/sfputr.c ./sfputr.c
-*** ../../../../sfio/src/lib/sfio/sfputr.c Tue May 16 18:25:49 2000
---- ./sfputr.c Wed Sep 20 09:06:01 2000
-***************
-*** 24,29 ****
---- 24,30 ----
- for(w = 0; (*s || rc >= 0); )
- { SFWPEEK(f,ps,p);
-
-+ if(p == -1) return -1; /* PL */
- if(p == 0 || (f->flags&SF_WHOLE) )
- { n = strlen(s);
- if(p >= (n + (rc < 0 ? 0 : 1)) )
-
-
PH
PH support is provided by Mark Roth <roth@uiuc.edu>. The map is
described at http://www-dev.cso.uiuc.edu/sendmail/ .
+
+ NOTE: The "spacedname" pseudo-field which was used by earlier
+ versions of the PH map code is no longer supported! See the URL
+ listed above for more information.
+
Please contact Mark Roth for support and questions regarding the
map.
@@ -1605,7 +1610,7 @@ Regular Expressions (MAP_REGEX)
pattern-compile-error: : Operation not applicable
- Your libc does not include a running version of POSIX-regex. Use
+ Your libc does not include a running version of POSIX-regex. Use
librx or regex.o from the GNU Free Software Foundation,
ftp://ftp.gnu.org/pub/gnu/rx-?.?.tar.gz or
ftp://ftp.gnu.org/pub/gnu/regex-?.?.tar.gz.
@@ -1665,14 +1670,10 @@ TRACEFLAGS My own personal list of the trace flags -- not guaranteed
alias.c Does name aliasing in all forms.
aliases.5 Man page describing the format of the aliases file.
arpadate.c A subroutine which creates ARPANET standard dates.
-bf.h Buffered file I/O function declarations.
-bf_portable.c Stub routines for systems lacking the Torek stdio library.
-bf_portable.h Data structure and function declarations for bf_portable.c.
-bf_torek.c Routines to implement memory-buffered file system using
- hooks provided by Torek stdio library.
-bf_torek.h Data structure and function declarations for bf_torek.c.
-clock.c Routines to implement real-time oriented functions
- in sendmail -- e.g., timeouts.
+bf.c Routines to implement memory-buffered file system using
+ hooks provided by libsm now (formerly Torek stdio library).
+bf.h Buffered file I/O function declarations and
+ data structure and function declarations for bf.c.
collect.c The routine that actually reads the mail into a temp
file. It also does a certain amount of parsing of
the header, etc.
@@ -1681,9 +1682,9 @@ conf.c The configuration file. This contains information
controversial, or code compiled in for efficiency
reasons. Most of the configuration is in sendmail.cf.
conf.h Configuration that must be known everywhere.
+control.c Routines to implement control socket.
convtime.c A routine to sanely process times.
-daemon.c Routines to implement daemon mode. This version is
- specifically for Berkeley 4.1 IPC.
+daemon.c Routines to implement daemon mode.
deliver.c Routines to deliver mail.
domain.c Routines that interface with DNS (the Domain Name
System).
@@ -1707,12 +1708,15 @@ queue.c Routines to implement message queueing.
readcf.c The routine that reads the configuration file and
translates it to internal form.
recipient.c Routines that manipulate the recipient list.
+sasl.c Routines to interact with Cyrys-SASL.
savemail.c Routines which save the letter on processing errors.
sendmail.8 Man page for the sendmail command.
sendmail.h Main header file for sendmail.
-sfsasl.c I/O interface between SASL/TLS and the MTA using SFIO.
+sfsasl.c I/O interface between SASL/TLS and the MTA.
sfsasl.h Header file for sfsasl.c.
shmticklib.c Routines for shared memory counters.
+sm_resolve.c Routines for DNS lookups (for DNS map type).
+sm_resolve.h Header file for sm_resolve.c.
srvrsmtp.c Routines to implement server SMTP.
stab.c Routines to manage the symbol table.
stats.c Routines to collect and post the statistics.
@@ -1722,6 +1726,7 @@ sysexits.c List of error messages associated with error codes
sysexits.h List of error codes for systems that lack their own.
timers.c Routines to provide microtimers.
timers.h Data structure and function declarations for timers.h.
+tls.c Routines for TLS.
trace.c The trace package. These routines allow setting and
testing of trace flags with a high granularity.
udb.c The user database interface module.
@@ -1730,4 +1735,4 @@ util.c Some general purpose routines used by sendmail.
version.c The version number and information about this
version of sendmail.
-(Version $Revision: 8.263.2.1.2.38 $, last update $Date: 2001/08/15 22:07:11 $ )
+(Version $Revision: 8.345 $, last update $Date: 2002/01/09 18:04:30 $ )
diff --git a/contrib/sendmail/src/SECURITY b/contrib/sendmail/src/SECURITY
new file mode 100644
index 0000000..7e55024
--- /dev/null
+++ b/contrib/sendmail/src/SECURITY
@@ -0,0 +1,192 @@
+# Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: SECURITY,v 1.47 2001/09/23 02:29:05 ca Exp $
+#
+
+This file gives some hints how to configure and run sendmail for
+people who are very security conscious (you should be...).
+
+Even though sendmail goes through great lengths to assure that it
+can't be compromised even if the system it is running on is
+incorrectly or insecurely configured, it can't work around everything.
+This has been demonstrated by recent OS problems which have
+subsequently been used to compromise the root account using sendmail
+as a vector. One way to minimize the possibility of such problems
+is to install sendmail without set-user-ID root, which avoids local
+exploits. This configuration, which is the default starting with
+8.12, is described in the first section of this security guide.
+
+
+*****************************************************
+** sendmail configuration without set-user-ID root **
+*****************************************************
+
+sendmail needs to run as root for several purposes:
+
+- bind to port 25
+- call the local delivery agent (LDA) as root (or other user) if the LDA
+ isn't set-user-ID root (unless some other method of storing e-mail in
+ local mailboxes is used).
+- read .forward files
+- write e-mail submitted via the command line to the queue directory.
+
+Only the last item requires a set-user-ID/set-group-ID program to
+avoid problems with a world-writable directory. It is however
+sufficient to have a set-group-ID program and a group-writable
+queue directory. The other requirements listed above can be
+fulfilled by a sendmail daemon that is started by root. Hence this
+section explains how to use two sendmail configurations to accomplish
+the goal to have a sendmail binary that is not set-user-ID root,
+and hence is not open to system configuration/OS problems or at
+least less problematic in presence of those.
+
+The default configuration starting with sendmail 8.12 uses one
+sendmail binary which acts differently based on operation mode and
+supplied options.
+
+sendmail must be a set-group-ID (default group: smmsp, recommended
+gid: 25) program to allow for queueing mail in a group-writable
+directory. Two .cf files are required: sendmail.cf for the daemon
+and submit.cf for the submission program. The following permissions
+should be used:
+
+-r-xr-sr-x root smmsp ... /PATH/TO/sendmail
+drwxrwx--- smmsp smmsp ... /var/spool/clientmqueue
+drwx------ root wheel ... /var/spool/mqueue
+-r--r--r-- root wheel ... /etc/mail/sendmail.cf
+-r--r--r-- root wheel ... /etc/mail/submit.cf
+
+That is, the owner of sendmail is root, the group is smmsp, and
+the binary is set-group-ID. The client mail queue is owned by
+smmsp with group smmsp and is group writable. The client mail
+queue directory must be writable by smmsp, but it must not be
+accessible for others. That is, do not use world read or execute
+permissions. In submit.cf the option UseMSP must be set, and
+QueueFileMode must be set to 0660. submit.cf is available in
+cf/cf/, which has been built from cf/cf/submit.mc. The file can
+be used as-is, if you want to add more options, use cf/cf/submit.mc
+as starting point and read cf/README: MESSAGE SUBMISSION PROGRAM
+carefully.
+
+The .cf file is chosen based on the operation mode. For -bm (default),
+-bs, and -t it is submit.cf (if it exists) for all others it is
+sendmail.cf. This selection can be changed by -Ac or -Am (alternative
+.cf file: client or mta).
+
+The daemon must be started by root as usual, e.g.,
+
+/PATH/TO/sendmail -L sm-mta -bd -q1h
+
+(replace /PATH/TO with the right path for your OS, e.g.,
+/usr/sbin or /usr/lib).
+
+Notice: if you run sendmail from inetd (which in general is not a
+good idea), you must specify -Am in addition to -bs.
+
+Mail will end up in the client queue if the daemon doesn't accept
+connections or if an address is temporarily not resolvable. The
+latter problem can be minimized by using
+
+ FEATURE(`nocanonify', `canonify_hosts')
+ define(`confDIRECT_SUBMISSION_MODIFIERS', `C')
+
+which, however, may have undesired side effects. See cf/README for
+a discussion. In general it is necessary to clean the queue either
+via a cronjob or by running a daemon, e.g.,
+
+/PATH/TO/sendmail -L sm-msp-queue -Ac -q30m
+
+If the option UseMSP is not set, sendmail will complain during
+queue runs about bogus file permission. If you want a queue runner
+for the client queue, you probably have to change OS specific
+scripts to accomplish this (check the man pages of your OS for more
+information.) You can start this program as root, it will change
+its user id to RunAsUser (smmsp by default, recommended uid: 25).
+This way smmsp does not need a valid shell.
+
+Summary
+-------
+
+This is a brief summary how the two configuration files are used:
+
+sendmail.cf For the MTA (mail transmission agent)
+ The MTA is started by root as daemon:
+
+ /PATH/TO/sendmail -L sm-mta -bd -q1h
+
+ it accepts SMTP connections (on ports 25 and 587 by default);
+ it runs the main queue (/var/spool/mqueue by default).
+
+submit.cf For the MSP (mail submission program)
+ The MSP is used to submit e-mails, hence it is invoked
+ by programs (and maybe users); it does not run as SMTP
+ daemon; it uses /var/spool/clientmqueue by default; it
+ can be started to run that queue periodically:
+
+ /PATH/TO/sendmail -L sm-msp-queue -Ac -q30m
+
+
+Hints and Troubleshooting
+-------------------------
+
+RunAsUser: FEATURE(`msp') sets the option RunAsUser to smmsp.
+This user must have the group smmsp, i.e., the same group as the
+clientmqueue directory. If you specify a user whose primary group
+is not the same as that of the clientmqueue directory, then you
+should explicitly set the group, e.g.,
+
+ FEATURE(`msp')
+ define(`confRUN_AS_USER', `mailmsp:smmsp')
+
+STARTTLS: If sendmail is compiled with STARTTLS support on a platform
+that does not have HASURANDOMDEV defined, you either need to specify
+the RandFile option (as for the MTA), or you have to turn off
+STARTTLS in the MSP, e.g.,
+
+ DAEMON_OPTIONS(`Name=NoMTA, Addr=127.0.0.1, M=S')
+ FEATURE(`msp')
+ CLIENT_OPTIONS(`Family=inet, Address=0.0.0.0, M=S')
+
+The first option is used to turn off STARTTLS when the MSP is
+invoked with -bs as some MUAs do.
+
+
+What doesn't work anymore
+-------------------------
+
+Normal users can't use mailq anymore to see the MTA mail queue.
+There are several ways around it, e.g., changing QueueFileMode
+or giving users access via a program like sudo.
+
+sendmail -bv may give misleading output for normal users since it
+may not be able to access certain files, e.g., .forward files of
+other users.
+
+
+Alternative
+-----------
+
+Instead of having one set-group-ID binary, it is possible to use
+two with different permissions: one for message submission
+(set-group-ID), one acting as daemon etc, which is only executable
+by root. In that case it is possible to remove features from
+the message submission program to have a smaller binary.
+You can use
+
+ sh ./Build install-sm-mta
+
+to install a sendmail program to act as daemon etc under the name
+sm-mta.
+
+Set-User-Id
+-----------
+
+If you really have to install sendmail set-user-ID root, you can use
+
+ sh ./Build install-set-user-id
+
diff --git a/contrib/sendmail/src/TRACEFLAGS b/contrib/sendmail/src/TRACEFLAGS
index 09f7d35..d43bc5c 100644
--- a/contrib/sendmail/src/TRACEFLAGS
+++ b/contrib/sendmail/src/TRACEFLAGS
@@ -1,4 +1,4 @@
-# $Id: TRACEFLAGS,v 8.29.16.1 2001/05/03 17:24:00 gshapiro Exp $
+# $Id: TRACEFLAGS,v 8.35 2001/11/28 01:01:25 gshapiro Exp $
0, 1 main.c main skip background fork
0, 4 main.c main canonical name, UUCP node name, a.k.a.s
0, 15 main.c main print configuration
@@ -75,11 +75,17 @@
62 multiple file descriptor checking
63 queue.c runqueue process watching
64 multiple Milter
+65 main.c permission checks
+66 srvrsmtp.c conformance checks
67 conf.c signals
+69 queue.c scheduling
+#if _FFR_QUARANTINE
+70 queue.c quarantining
+#endif /* _FFR_QUARANTINE */
80 content length
81 sun remote mode
91 mci.c syslogging of MCI cache information
-94 srvrsmtp.c cause commands to fail (for protocol testing)
+94,>99 srvrsmtp.c cause commands to fail (for protocol testing)
95 srvrsmtp.c AUTH
95 usersmtp.c AUTH
98 * timers
diff --git a/contrib/sendmail/src/TUNING b/contrib/sendmail/src/TUNING
new file mode 100644
index 0000000..e055269
--- /dev/null
+++ b/contrib/sendmail/src/TUNING
@@ -0,0 +1,232 @@
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: TUNING,v 1.16 2001/08/19 21:03:38 gshapiro Exp $
+#
+
+********************************************
+** This is a DRAFT, comments are welcome! **
+********************************************
+
+
+If the default configuration of sendmail does not achieve the
+required performance, there are several configuration options that
+can be changed to accomplish higher performance. However, before
+those options are changed it is necessary to understand why the
+performance is not as good as desired. This may also involve hardware
+and software (OS) configurations which are not extensively explored
+in this document. We assume that your system is not limited by
+network bandwidth because optimizing for this situation is beyond
+the scope of this guide. In almost all other cases performance will
+be limited by disk I/O.
+
+
+This text assumes that all options which are mentioned here are
+familiar to the reader, they are explained in the Sendmail Installation
+and Operations Guide; doc/op/op.txt.
+
+There are basically three different scenarios which are treated
+in the following:
+* Mailing Lists and Large Aliases (1-n Mailing)
+* 1-1 Mass Mailing
+* High Volume Mail
+
+Depending on your requirements, these may need different options
+to optimize sendmail for the particular purpose. It is also possible
+to configure sendmail to achieve good performance in all cases, but
+it will not be optimal for any specific purpose. For example, it
+is non-trivival to combine low latency (fast delivery of incoming
+mail) with high overall throughput.
+
+Before we explore the different scenarios, a basic discussion about
+disk I/O, delivery modes, and queue control is required.
+
+
+* Disk I/O
+-----------------------------------------------
+
+In general mail will be written to disk up before a delivery attempt
+is made. This is required for reliability and should only be changed
+in a few specific cases that are mentioned later on. To achieve
+better disk I/O performance the queue directories can be spread
+over several disks to distribute the load. This is some basic tuning
+that should be done in all cases where the I/O speed of a single
+disk is exceeded, which is true for almost every high-volume
+situation except if a special disk subsystem with large (NV)RAM
+buffer is used.
+
+Depending on your OS there might be ways to speed up I/O, e.g.,
+using softupdates or turning on the noatime mount option. If this
+is done make sure the filesystem is still reliable, i.e., if fsync()
+returns without an error, the file has really been committed to
+disk.
+
+
+* Queueing Strategies and DeliveryMode
+-----------------------------------------------
+
+There are basically three delivery modes:
+
+background: incoming mail will be immediately delivered by a new process
+interactive: incoming mail will be immediately delivered by the same process
+queue: incoming mail will be queued and delivered by a queue runner later on
+
+The first offers the lowest latency without the disadvantage of the
+second, which keep the connection from the sender open until the
+delivery to the next hop succeeded or failed. However, it does not
+allow for a good control over the number of delivery processes other
+than limiting the total number of direct children of the daemon
+processes (MaxChildren) or by load control options (RefuseLA,
+DelayLA). Moreover, it can't make as good use as 'queue' mode can
+for connection caching.
+
+Interactive DeliveryMode should only be used in rare cases, e.g.,
+if the delivery time to the next hop is a known quantity or if the
+sender is under local control and it does not matter if it has to
+wait for delivery.
+
+Queueing up e-mail before delivery is done by a queue runner allows
+the best load control but does not achieve as low latency as the
+other two modes. However, this mode is probably also best for
+concurrent delivery since the number of queue runners can be specified
+on a queue group basis. Persistent queue runners (-qp) can be used
+to minimize the overhead for creating processes because they just
+sleep for the specified interval (which shold be short) instead of
+exiting after a queue run.
+
+
+* Queue Groups
+-----------------------------------------------
+
+In most situations disk I/O is a bottleneck which can be mitigated
+by spreading the load over several disks. This can easily be achieved
+with different queue directories. sendmail 8.12 introduces queue
+groups which are collections of queue directories with similar
+properties, i.e., number of processes to run the queues in the
+group, maximum number of recipients within an e-mail (envelope),
+etc. Queue groups allow control over the behaviour of different
+queues. Depending on the setup, it is usually possible to have
+several queue runners delivering mails concurrently which should
+increase throughput. The number of queue runners can be controlled
+per queue group (Runner=) and overall (MaxQueueChildren).
+
+
+* DNS Lookups
+-----------------------------------------------
+
+sendmail performs by default host name canonifications by using
+host name lookups. This process is meant to replace unqualified
+host name with qualified host names, and CNAMEs with the non-aliased
+name. However, these lookups can take a while for large address
+lists, e.g., mailing lists. If you can assure by other means that
+host names are canonical, you should use
+
+ FEATURE(`nocanonify', `canonify_hosts')
+
+in your .mc file. For further information on this feature and
+additional options see cf/README. If sendmail is invoked directly
+to send e-mail then either the -G option should be used or
+
+ define(`confDIRECT_SUBMISSION_MODIFIERS', `C')
+
+should be added to the .mc file.
+
+
+* Mailing Lists and Large Aliases (1-n Mailing)
+-----------------------------------------------
+
+Before 8.12 sendmail delivers an e-mail sequentially to all its
+recipients. For mailing lists or large aliases the overall delivery
+time can be substantial, especially if some of the recipients are located
+at hosts that are slow to accept e-mail. Some mailing list software
+therefore "split" up e-mails into smaller pieces with fewer recipients.
+sendmail 8.12 can do this itself, either across queue groups or
+within a queue directory. For the former the option SplitAcrossQueueGroups
+option must be set, the latter is controlled by the 'r=' field of
+a queue group declaration.
+
+Let's assume a simple example: a mailing lists where most of
+the recipients are at three domains: the local one (local.domain)
+and two remotes (one.domain, two.domain) and the rest is splittered
+over several other domains. For this case it is useful to specify
+three queue groups:
+
+QUEUE_GROUP(`local', `P=/var/spool/mqueue/local, F=f, R=2, I=1m')dnl
+QUEUE_GROUP(`one', `P=/var/spool/mqueue/one, F=f, r=50, R=3')dnl
+QUEUE_GROUP(`two', `P=/var/spool/mqueue/two, F=f, r=30, R=4')dnl
+QUEUE_GROUP(`remote', `P=/var/spool/mqueue/remote, F=f, r=5, R=8, I=2m')dnl
+define(`ESMTP_MAILER_QGRP', `remote')dnl
+define(`confSPLIT_ACROSS_QUEUEGROUPS', `True')dnl
+define(`confDELIVERY_MODE', `q')dnl
+define(`confMAX_QUEUE_CHILDREN', `50')dnl
+define(`confMIN_QUEUE_AGE', `27m')dnl
+
+and specify the queuegroup ruleset as follows:
+
+LOCAL_RULESETS
+Squeuegroup
+R$* @ local.domain $# local
+R$* @ $* one.domain $# one
+R$* @ $* two.domain $# two
+R$* @ $* $# remote
+R$* $# mqueue
+
+Now it is necessary to control the number of queue runners, which
+is done by MaxQueueChildren. Starting the daemon with the option
+-q5m assures that the first delivery attempt for each e-mail is
+done within 5 minutes, however, there are also individual queue
+intervals for the queue groups as specified above. MinQueueAge
+is set to 27 minutes to avoid that entries are run too often.
+
+Notice: if envelope splitting happens due to alias expansion, and
+DeliveryMode is not 'i'nteractive, then only one envelope is sent
+immediately. The rest (after splitting) are queued up and queue
+runners must come along and take care of them. Hence it is essential
+that the queue interval is very short.
+
+
+* 1-1 Mass Mailing
+-----------------------------------------------
+
+In this case some program generates e-mails which are sent to
+individual recipients (or at most very few per e-mail). A simple
+way to achieve high throughput is to set the delivery mode to
+'interactive', turn off the SuperSafe option and make sure that the
+program that generates the mails can deal with mail losses if the
+server loses power. In no other case should SuperSafe be set to
+'false'. If these conditions are met, sendmail does not need to
+commit mails to disk but can buffer them in memory which will greatly
+enhance performance, especially compared to normal disk subsystems, e.g.,
+non solid-state disks.
+
+
+* High Volume Mail
+-----------------------------------------------
+
+For high volume mail it is necessary to be able to control the load
+on the system. Therefore the 'queue' delivery mode should be used,
+and all options related to number of processes and the load should
+be set to reasonable values. It is important not to accept mail
+faster than it can be delivered otherwise the system will be
+overwhelmed. Hence RefuseLA should be lower than QueueLA, the number
+of daemon children should probably be lower than the number of queue
+runnners (MaxChildren vs. MaxQueueChildren). DelayLA is a new option
+in 8.12 which allows delaying connections instead of rejecting them.
+This may result in a smoother load distribution depending on how
+the mails are submitted to sendmail.
+
+
+* Miscellaneous
+-----------------------------------------------
+
+Other options that are interesting to tweak performance are
+(in no particular order):
+
+SuperSafe: if interactive DeliveryMode is used, then this can
+be set to the new value "interactive" in 8.12 to save some disk
+synchronizations which are not really necessary in that mode.
+
diff --git a/contrib/sendmail/src/alias.c b/contrib/sendmail/src/alias.c
index 070da59..28a76d5 100644
--- a/contrib/sendmail/src/alias.c
+++ b/contrib/sendmail/src/alias.c
@@ -8,23 +8,22 @@
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
+ *
*/
#include <sendmail.h>
-#ifndef lint
-static char id[] = "@(#)$Id: alias.c,v 8.142.4.11 2001/05/03 17:24:01 gshapiro Exp $";
-#endif /* ! lint */
+SM_RCSID("@(#)$Id: alias.c,v 8.211 2001/11/12 22:52:18 ca Exp $")
-# define SEPARATOR ':'
+#define SEPARATOR ':'
# define ALIAS_SPEC_SEPARATORS " ,/:"
static MAP *AliasFileMap = NULL; /* the actual aliases.files map */
static int NAliasFileMaps; /* the number of entries in AliasFileMap */
-static char *aliaslookup __P((char *, int *));
+static char *aliaslookup __P((char *, int *, char *));
- /*
+/*
** ALIAS -- Compute aliases.
**
** Scans the alias file for an alias for the given address.
@@ -62,7 +61,7 @@ alias(a, sendq, aliaslevel, e)
char obuf[MAXNAME + 7];
if (tTd(27, 1))
- dprintf("alias(%s)\n", a->q_user);
+ sm_dprintf("alias(%s)\n", a->q_user);
/* don't realias already aliased names */
if (!QS_IS_OK(a->q_state))
@@ -81,35 +80,38 @@ alias(a, sendq, aliaslevel, e)
** bounce messages inappropriately.
*/
-
#if _FFR_REDIRECTEMPTY
/*
** envelope <> can't be sent to mailing lists, only owner-
** send spam of this type to owner- of the list
** ---- to stop spam from going to mailing lists!
*/
+
if (e->e_sender != NULL && *e->e_sender == '\0')
{
/* Look for owner of alias */
- (void) strlcpy(obuf, "owner-", sizeof obuf);
- (void) strlcat(obuf, a->q_user, sizeof obuf);
- if (aliaslookup(obuf, &status) != NULL)
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2, "owner-", a->q_user);
+ if (aliaslookup(obuf, &status, a->q_host) != NULL)
{
if (LogLevel > 8)
syslog(LOG_WARNING,
"possible spam from <> to list: %s, redirected to %s\n",
a->q_user, obuf);
- a->q_user = newstr(obuf);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, obuf);
}
}
#endif /* _FFR_REDIRECTEMPTY */
- p = aliaslookup(a->q_user, &status);
+ p = aliaslookup(a->q_user, &status, a->q_host);
if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE)
{
a->q_state = QS_QUEUEUP;
if (e->e_message == NULL)
- e->e_message = newstr("alias database unavailable");
+ e->e_message = "alias database unavailable";
+
+ /* XXX msg only per recipient? */
+ if (a->q_message == NULL)
+ a->q_message = "alias database unavailable";
return;
}
if (p == NULL)
@@ -121,8 +123,8 @@ alias(a, sendq, aliaslevel, e)
*/
if (tTd(27, 1))
- dprintf("%s (%s, %s) aliased to %s\n",
- a->q_paddr, a->q_host, a->q_user, p);
+ sm_dprintf("%s (%s, %s) aliased to %s\n",
+ a->q_paddr, a->q_host, a->q_user, p);
if (bitset(EF_VRFYONLY, e->e_flags))
{
a->q_state = QS_VERIFIED;
@@ -131,13 +133,13 @@ alias(a, sendq, aliaslevel, e)
message("aliased to %s", shortenstring(p, MAXSHORTSTR));
if (LogLevel > 10)
sm_syslog(LOG_INFO, e->e_id,
- "alias %.100s => %s",
- a->q_paddr, shortenstring(p, MAXSHORTSTR));
+ "alias %.100s => %s",
+ a->q_paddr, shortenstring(p, MAXSHORTSTR));
a->q_flags &= ~QSELFREF;
if (tTd(27, 5))
{
- dprintf("alias: QS_EXPANDED ");
- printaddr(a, FALSE);
+ sm_dprintf("alias: QS_EXPANDED ");
+ printaddr(a, false);
}
a->q_state = QS_EXPANDED;
@@ -153,6 +155,7 @@ alias(a, sendq, aliaslevel, e)
a->q_flags |= QGOODUID|QALIAS;
(void) sendtolist(p, a, sendq, aliaslevel + 1, e);
+
if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state))
a->q_state = QS_OK;
@@ -160,34 +163,35 @@ alias(a, sendq, aliaslevel, e)
** Look for owner of alias
*/
- (void) strlcpy(obuf, "owner-", sizeof obuf);
if (strncmp(a->q_user, "owner-", 6) == 0 ||
- strlen(a->q_user) > (SIZE_T) sizeof obuf - 7)
- (void) strlcat(obuf, "owner", sizeof obuf);
+ strlen(a->q_user) > sizeof obuf - 7)
+ (void) sm_strlcpy(obuf, "owner-owner", sizeof obuf);
else
- (void) strlcat(obuf, a->q_user, sizeof obuf);
- owner = aliaslookup(obuf, &status);
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2, "owner-", a->q_user);
+ owner = aliaslookup(obuf, &status, a->q_host);
if (owner == NULL)
return;
/* reflect owner into envelope sender */
if (strpbrk(owner, ",:/|\"") != NULL)
owner = obuf;
- a->q_owner = newstr(owner);
+ a->q_owner = sm_rpool_strdup_x(e->e_rpool, owner);
/* announce delivery to this alias; NORECEIPT bit set later */
if (e->e_xfp != NULL)
- fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
- a->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Message delivered to mailing list %s\n",
+ a->q_paddr);
e->e_flags |= EF_SENDRECEIPT;
a->q_flags |= QDELIVERED|QEXPANDED;
}
- /*
+/*
** ALIASLOOKUP -- look up a name in the alias file.
**
** Parameters:
** name -- the name to look up.
** pstat -- a pointer to a place to put the status.
+** av -- argument for %1 expansion.
**
** Returns:
** the value of name.
@@ -201,11 +205,16 @@ alias(a, sendq, aliaslevel, e)
*/
static char *
-aliaslookup(name, pstat)
+aliaslookup(name, pstat, av)
char *name;
int *pstat;
+ char *av;
{
static MAP *map = NULL;
+#if _FFR_ALIAS_DETAIL
+ int i;
+ char *argv[4];
+#endif /* _FFR_ALIAS_DETAIL */
if (map == NULL)
{
@@ -218,12 +227,24 @@ aliaslookup(name, pstat)
DYNOPENMAP(map);
/* special case POstMastER -- always use lower case */
- if (strcasecmp(name, "postmaster") == 0)
+ if (sm_strcasecmp(name, "postmaster") == 0)
name = "postmaster";
+#if _FFR_ALIAS_DETAIL
+ i = 0;
+ argv[i++] = name;
+ argv[i++] = av;
+
+ /* XXX '+' is hardwired here as delimiter! */
+ if (av != NULL && *av == '+')
+ argv[i++] = av + 1;
+ argv[i++] = NULL;
+ return (*map->map_class->map_lookup)(map, name, argv, pstat);
+#else /* _FFR_ALIAS_DETAIL */
return (*map->map_class->map_lookup)(map, name, NULL, pstat);
+#endif /* _FFR_ALIAS_DETAIL */
}
- /*
+/*
** SETALIAS -- set up an alias map
**
** Called when reading configuration file.
@@ -245,7 +266,7 @@ setalias(spec)
STAB *s;
if (tTd(27, 8))
- dprintf("setalias(%s)\n", spec);
+ sm_dprintf("setalias(%s)\n", spec);
for (p = spec; p != NULL; )
{
@@ -265,8 +286,8 @@ setalias(spec)
}
if (AliasFileMap == NULL)
{
- (void) strlcpy(buf, "aliases.files sequence",
- sizeof buf);
+ (void) sm_strlcpy(buf, "aliases.files sequence",
+ sizeof buf);
AliasFileMap = makemapentry(buf);
if (AliasFileMap == NULL)
{
@@ -274,7 +295,7 @@ setalias(spec)
return;
}
}
- (void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps);
+ (void) sm_snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps);
s = stab(buf, ST_MAP, ST_ENTER);
map = &s->s_map;
memset(map, '\0', sizeof *map);
@@ -296,7 +317,7 @@ setalias(spec)
/* find end of spec */
if (p != NULL)
{
- bool quoted = FALSE;
+ bool quoted = false;
for (; *p != '\0'; p++)
{
@@ -320,7 +341,7 @@ setalias(spec)
*p++ = '\0';
if (tTd(27, 20))
- dprintf(" map %s:%s %s\n", class, s->s_name, spec);
+ sm_dprintf(" map %s:%s %s\n", class, s->s_name, spec);
/* look up class */
s = stab(class, ST_MAPCLASS, ST_FIND);
@@ -336,15 +357,16 @@ setalias(spec)
else
{
map->map_class = &s->s_mapclass;
+ map->map_mflags |= MF_ALIAS;
if (map->map_class->map_parse(map, spec))
{
- map->map_mflags |= MF_VALID|MF_ALIAS;
+ map->map_mflags |= MF_VALID;
AliasFileMap->map_stack[NAliasFileMaps++] = map;
}
}
}
}
- /*
+/*
** ALIASWAIT -- wait for distinguished @:@ token to appear.
**
** This can decide to reopen or rebuild the alias file
@@ -358,8 +380,8 @@ setalias(spec)
** just checking to see if it should be created.
**
** Returns:
-** TRUE -- if the database is open when we return.
-** FALSE -- if the database is closed when we return.
+** true -- if the database is open when we return.
+** false -- if the database is closed when we return.
*/
bool
@@ -368,14 +390,14 @@ aliaswait(map, ext, isopen)
char *ext;
bool isopen;
{
- bool attimeout = FALSE;
+ bool attimeout = false;
time_t mtime;
struct stat stb;
char buf[MAXNAME + 1];
if (tTd(27, 3))
- dprintf("aliaswait(%s:%s)\n",
- map->map_class->map_cname, map->map_file);
+ sm_dprintf("aliaswait(%s:%s)\n",
+ map->map_class->map_cname, map->map_file);
if (bitset(MF_ALIASWAIT, map->map_mflags))
return isopen;
map->map_mflags |= MF_ALIASWAIT;
@@ -383,8 +405,9 @@ aliaswait(map, ext, isopen)
if (SafeAlias > 0)
{
auto int st;
- time_t toolong = curtime() + SafeAlias;
unsigned int sleeptime = 2;
+ unsigned int loopcount = 0; /* only used for debugging */
+ time_t toolong = curtime() + SafeAlias;
while (isopen &&
map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
@@ -392,7 +415,7 @@ aliaswait(map, ext, isopen)
if (curtime() > toolong)
{
/* we timed out */
- attimeout = TRUE;
+ attimeout = true;
break;
}
@@ -402,8 +425,11 @@ aliaswait(map, ext, isopen)
*/
if (tTd(27, 2))
- dprintf("aliaswait: sleeping for %u seconds\n",
- sleeptime);
+ {
+ loopcount++;
+ sm_dprintf("aliaswait: sleeping for %u seconds (loopcount = %u)\n",
+ sleeptime, loopcount);
+ }
map->map_mflags |= MF_CLOSING;
map->map_class->map_close(map);
@@ -420,64 +446,31 @@ aliaswait(map, ext, isopen)
if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
{
if (tTd(27, 3))
- dprintf("aliaswait: not rebuildable\n");
+ sm_dprintf("aliaswait: not rebuildable\n");
map->map_mflags &= ~MF_ALIASWAIT;
return isopen;
}
if (stat(map->map_file, &stb) < 0)
{
if (tTd(27, 3))
- dprintf("aliaswait: no source file\n");
+ sm_dprintf("aliaswait: no source file\n");
map->map_mflags &= ~MF_ALIASWAIT;
return isopen;
}
mtime = stb.st_mtime;
- snprintf(buf, sizeof buf, "%s%s",
- map->map_file, ext == NULL ? "" : ext);
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ map->map_file, ext == NULL ? "" : ext);
if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
{
-#if !_FFR_REMOVE_AUTOREBUILD
- /* database is out of date */
- if (AutoRebuild &&
- stb.st_ino != 0 &&
- (stb.st_uid == geteuid() ||
- (geteuid() == 0 && stb.st_uid == TrustedUid)))
- {
- bool oldSuprErrs;
-
- message("auto-rebuilding alias database %s", buf);
- oldSuprErrs = SuprErrs;
- SuprErrs = TRUE;
- if (isopen)
- {
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
- }
- (void) rebuildaliases(map, TRUE);
- isopen = map->map_class->map_open(map, O_RDONLY);
- SuprErrs = oldSuprErrs;
- }
- else
- {
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, NOQID,
- "alias database %s out of date",
- buf);
- message("Warning: alias database %s out of date", buf);
- }
-#else /* !_FFR_REMOVE_AUTOREBUILD */
if (LogLevel > 3)
sm_syslog(LOG_INFO, NOQID,
- "alias database %s out of date",
- buf);
+ "alias database %s out of date", buf);
message("Warning: alias database %s out of date", buf);
-#endif /* !_FFR_REMOVE_AUTOREBUILD */
}
map->map_mflags &= ~MF_ALIASWAIT;
return isopen;
}
- /*
+/*
** REBUILDALIASES -- rebuild the alias database.
**
** Parameters:
@@ -485,7 +478,7 @@ aliaswait(map, ext, isopen)
** automatic -- set if this was automatically generated.
**
** Returns:
-** TRUE if successful; FALSE otherwise.
+** true if successful; false otherwise.
**
** Side Effects:
** Reads the text version of the database, builds the
@@ -497,9 +490,9 @@ rebuildaliases(map, automatic)
register MAP *map;
bool automatic;
{
- FILE *af;
- bool nolock = FALSE;
- bool success = FALSE;
+ SM_FILE_T *af;
+ bool nolock = false;
+ bool success = false;
long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
sigfunc_t oldsigint, oldsigquit;
#ifdef SIGTSTP
@@ -507,7 +500,7 @@ rebuildaliases(map, automatic)
#endif /* SIGTSTP */
if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
- return FALSE;
+ return false;
if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
sff |= SFF_NOWLINK;
@@ -527,25 +520,26 @@ rebuildaliases(map, automatic)
int saveerr = errno;
if (tTd(27, 1))
- dprintf("Can't open %s: %s\n",
- map->map_file, errstring(saveerr));
+ sm_dprintf("Can't open %s: %s\n",
+ map->map_file, sm_errstring(saveerr));
if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
message("newaliases: cannot open %s: %s",
- map->map_file, errstring(saveerr));
+ map->map_file, sm_errstring(saveerr));
errno = 0;
- return FALSE;
+ return false;
}
- nolock = TRUE;
+ nolock = true;
if (tTd(27, 1) ||
- fstat(fileno(af), &stb) < 0 ||
+ fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &stb) < 0 ||
bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
message("warning: cannot lock %s: %s",
- map->map_file, errstring(errno));
+ map->map_file, sm_errstring(errno));
}
/* see if someone else is rebuilding the alias file */
if (!nolock &&
- !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
+ !lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), map->map_file,
+ NULL, LOCK_EX|LOCK_NB))
{
/* yes, they are -- wait until done */
message("Alias file %s is locked (maybe being rebuilt)",
@@ -553,18 +547,18 @@ rebuildaliases(map, automatic)
if (OpMode != MD_INITALIAS)
{
/* wait for other rebuild to complete */
- (void) lockfile(fileno(af), map->map_file, NULL,
- LOCK_EX);
+ (void) lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL),
+ map->map_file, NULL, LOCK_EX);
}
- (void) fclose(af);
+ (void) sm_io_close(af, SM_TIME_DEFAULT);
errno = 0;
- return FALSE;
+ return false;
}
- oldsigint = setsignal(SIGINT, SIG_IGN);
- oldsigquit = setsignal(SIGQUIT, SIG_IGN);
+ oldsigint = sm_signal(SIGINT, SIG_IGN);
+ oldsigquit = sm_signal(SIGQUIT, SIG_IGN);
#ifdef SIGTSTP
- oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
+ oldsigtstp = sm_signal(SIGTSTP, SIG_IGN);
#endif /* SIGTSTP */
if (map->map_class->map_open(map, O_RDWR))
@@ -577,22 +571,22 @@ rebuildaliases(map, automatic)
username());
}
map->map_mflags |= MF_OPEN|MF_WRITABLE;
- map->map_pid = getpid();
- readaliases(map, af, !automatic, TRUE);
- success = TRUE;
+ map->map_pid = CurrentPid;
+ readaliases(map, af, !automatic, true);
+ success = true;
}
else
{
if (tTd(27, 1))
- dprintf("Can't create database for %s: %s\n",
- map->map_file, errstring(errno));
+ sm_dprintf("Can't create database for %s: %s\n",
+ map->map_file, sm_errstring(errno));
if (!automatic)
syserr("Cannot create database for alias file %s",
map->map_file);
}
/* close the file, thus releasing locks */
- (void) fclose(af);
+ (void) sm_io_close(af, SM_TIME_DEFAULT);
/* add distinguished entries and close the database */
if (bitset(MF_OPEN, map->map_mflags))
@@ -603,14 +597,14 @@ rebuildaliases(map, automatic)
}
/* restore the old signals */
- (void) setsignal(SIGINT, oldsigint);
- (void) setsignal(SIGQUIT, oldsigquit);
-# ifdef SIGTSTP
- (void) setsignal(SIGTSTP, oldsigtstp);
-# endif /* SIGTSTP */
+ (void) sm_signal(SIGINT, oldsigint);
+ (void) sm_signal(SIGQUIT, oldsigquit);
+#ifdef SIGTSTP
+ (void) sm_signal(SIGTSTP, oldsigtstp);
+#endif /* SIGTSTP */
return success;
}
- /*
+/*
** READALIASES -- read and process the alias file.
**
** This routine implements the part of initaliases that occurs
@@ -634,7 +628,7 @@ rebuildaliases(map, automatic)
void
readaliases(map, af, announcestats, logstats)
register MAP *map;
- FILE *af;
+ SM_FILE_T *af;
bool announcestats;
bool logstats;
{
@@ -652,52 +646,56 @@ readaliases(map, af, announcestats, logstats)
FileName = map->map_file;
LineNumber = 0;
naliases = bytes = longest = 0;
- skipping = FALSE;
- while (fgets(line, sizeof line, af) != NULL)
+ skipping = false;
+ while (sm_io_fgets(af, SM_TIME_DEFAULT, line, sizeof line) != NULL)
{
int lhssize, rhssize;
int c;
LineNumber++;
p = strchr(line, '\n');
+
+ /* XXX what if line="a\\" ? */
while (p != NULL && p > line && p[-1] == '\\')
{
p--;
- if (fgets(p, SPACELEFT(line, p), af) == NULL)
+ if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
+ SPACELEFT(line, p)) == NULL)
break;
LineNumber++;
p = strchr(p, '\n');
}
if (p != NULL)
*p = '\0';
- else if (!feof(af))
+ else if (!sm_io_eof(af))
{
errno = 0;
syserr("554 5.3.0 alias line too long");
/* flush to end of line */
- while ((c = getc(af)) != EOF && c != '\n')
+ while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) !=
+ SM_IO_EOF && c != '\n')
continue;
/* skip any continuation lines */
- skipping = TRUE;
+ skipping = true;
continue;
}
switch (line[0])
{
case '#':
case '\0':
- skipping = FALSE;
+ skipping = false;
continue;
case ' ':
case '\t':
if (!skipping)
syserr("554 5.3.5 Non-continuation line starts with space");
- skipping = TRUE;
+ skipping = true;
continue;
}
- skipping = FALSE;
+ skipping = false;
/*
** Process the LHS
@@ -715,7 +713,8 @@ readaliases(map, af, announcestats, logstats)
syserr("554 5.3.5 missing colon");
continue;
}
- if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
+ if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv, true)
+ == NULL)
{
syserr("554 5.3.5 %.40s... illegal alias name", line);
continue;
@@ -751,7 +750,8 @@ readaliases(map, af, announcestats, logstats)
if (*p == '\0')
break;
if (parseaddr(p, &bl, RF_COPYNONE, ',',
- &delimptr, CurEnv) == NULL)
+ &delimptr, CurEnv, true)
+ == NULL)
usrerr("553 5.3.5 %s... bad address", p);
p = delimptr;
}
@@ -762,24 +762,26 @@ readaliases(map, af, announcestats, logstats)
}
/* see if there should be a continuation line */
- c = getc(af);
- if (!feof(af))
- (void) ungetc(c, af);
+ c = sm_io_getc(af, SM_TIME_DEFAULT);
+ if (!sm_io_eof(af))
+ (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c);
if (c != ' ' && c != '\t')
break;
/* read continuation line */
- if (fgets(p, sizeof line - (p - line), af) == NULL)
+ if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
+ sizeof line - (p-line)) == NULL)
break;
LineNumber++;
/* check for line overflow */
- if (strchr(p, '\n') == NULL && !feof(af))
+ if (strchr(p, '\n') == NULL && !sm_io_eof(af))
{
usrerr("554 5.3.5 alias too long");
- while ((c = fgetc(af)) != EOF && c != '\n')
+ while ((c = sm_io_getc(af, SM_TIME_DEFAULT))
+ != SM_IO_EOF && c != '\n')
continue;
- skipping = TRUE;
+ skipping = true;
break;
}
}
@@ -800,7 +802,7 @@ readaliases(map, af, announcestats, logstats)
** Special case pOStmaStER -- always make it lower case.
*/
- if (strcasecmp(al.q_user, "postmaster") == 0)
+ if (sm_strcasecmp(al.q_user, "postmaster") == 0)
makelower(al.q_user);
lhssize = strlen(al.q_user);
@@ -829,12 +831,18 @@ readaliases(map, af, announcestats, logstats)
longest = rhssize;
}
+#if 0
+ /*
+ ** address strings are now stored in the envelope rpool,
+ ** and therefore cannot be freed.
+ */
if (al.q_paddr != NULL)
- sm_free(al.q_paddr);
+ sm_free(al.q_paddr); /* disabled */
if (al.q_host != NULL)
- sm_free(al.q_host);
+ sm_free(al.q_host); /* disabled */
if (al.q_user != NULL)
- sm_free(al.q_user);
+ sm_free(al.q_user); /* disabled */
+#endif /* 0 */
}
CurEnv->e_to = NULL;
@@ -847,7 +855,7 @@ readaliases(map, af, announcestats, logstats)
"%s: %ld aliases, longest %ld bytes, %ld bytes total",
map->map_file, naliases, longest, bytes);
}
- /*
+/*
** FORWARD -- Try to forward mail
**
** This is similar but not identical to aliasing.
@@ -881,11 +889,13 @@ forward(user, sendq, aliaslevel, e)
bool got_transient;
if (tTd(27, 1))
- dprintf("forward(%s)\n", user->q_paddr);
+ sm_dprintf("forward(%s)\n", user->q_paddr);
if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
!QS_IS_OK(user->q_state))
return;
+ if (ForwardPath != NULL && *ForwardPath == '\0')
+ return;
if (user->q_home == NULL)
{
syserr("554 5.3.0 forward: no home");
@@ -893,13 +903,13 @@ forward(user, sendq, aliaslevel, e)
}
/* good address -- look for .forward file in home */
- define('z', user->q_home, e);
- define('u', user->q_user, e);
- define('h', user->q_host, e);
+ macdefine(&e->e_macro, A_PERM, 'z', user->q_home);
+ macdefine(&e->e_macro, A_PERM, 'u', user->q_user);
+ macdefine(&e->e_macro, A_PERM, 'h', user->q_host);
if (ForwardPath == NULL)
ForwardPath = newstr("\201z/.forward");
- got_transient = FALSE;
+ got_transient = false;
for (pp = ForwardPath; pp != NULL; pp = ep)
{
int err;
@@ -915,18 +925,18 @@ forward(user, sendq, aliaslevel, e)
if (buf[0] == '\0')
continue;
if (tTd(27, 3))
- dprintf("forward: trying %s\n", buf);
+ sm_dprintf("forward: trying %s\n", buf);
- err = include(buf, TRUE, user, sendq, aliaslevel, e);
+ err = include(buf, true, user, sendq, aliaslevel, e);
if (err == 0)
break;
else if (transienterror(err))
{
/* we may have to suspend this message */
- got_transient = TRUE;
+ got_transient = true;
if (tTd(27, 2))
- dprintf("forward: transient error on %s\n",
- buf);
+ sm_dprintf("forward: transient error on %s\n",
+ buf);
if (LogLevel > 2)
{
char *curhost = CurHostName;
@@ -934,7 +944,7 @@ forward(user, sendq, aliaslevel, e)
CurHostName = NULL;
sm_syslog(LOG_ERR, e->e_id,
"forward %s: transient error: %s",
- buf, errstring(err));
+ buf, sm_errstring(err));
CurHostName = curhost;
}
@@ -964,19 +974,18 @@ forward(user, sendq, aliaslevel, e)
case E_SM_ISEXEC:
case E_SM_WWFILE:
case E_SM_GWFILE:
- syserr("forward: %s: %s", buf, errstring(err));
+ syserr("forward: %s: %s", buf, sm_errstring(err));
break;
#endif /* _FFR_FORWARD_SYSERR */
default:
if (LogLevel > (RunAsUid == 0 ? 2 : 10))
sm_syslog(LOG_WARNING, e->e_id,
- "forward %s: %s", buf,
- errstring(err));
+ "forward %s: %s", buf,
+ sm_errstring(err));
if (Verbose)
message("forward: %s: %s",
- buf,
- errstring(err));
+ buf, sm_errstring(err));
break;
}
}
diff --git a/contrib/sendmail/src/aliases b/contrib/sendmail/src/aliases
index 1b19f41..73899d4 100644
--- a/contrib/sendmail/src/aliases
+++ b/contrib/sendmail/src/aliases
@@ -1,33 +1,66 @@
#
-# $Id: aliases,v 8.1.36.1 2000/10/16 20:18:39 gshapiro Exp $
+# $Id: aliases,v 8.4 2001/12/30 04:46:23 gshapiro Exp $
# @(#)aliases 8.2 (Berkeley) 3/5/94
#
# Aliases in this file will NOT be expanded in the header from
-# Mail, but WILL be visible over networks or from /bin/mail.
+# Mail, but WILL be visible over networks.
#
# >>>>>>>>>> The program "newaliases" must be run after
# >> NOTE >> this file is updated for any changes to
# >>>>>>>>>> show through to sendmail.
#
+#
+# See also RFC 2142, `MAILBOX NAMES FOR COMMON SERVICES, ROLES
+# AND FUNCTIONS', May 1997
+
+# Pretty much everything else in this file points to "root", so
+# you should forward root's email to the system administrator.
+# Delivering mail to root's mailbox or reading mail as root is
+# inadvisable.
-# Basic system aliases -- these MUST be present.
+# Uncomment and *CHANGE* this!
+# root: insert-human-being-here
+
+# Basic system aliases -- these MUST be present
MAILER-DAEMON: postmaster
postmaster: root
-# General redirections for pseudo accounts.
+# General redirections for pseudo accounts
bin: root
daemon: root
games: root
+mailnull: postmaster
+smmsp: postmaster
ingres: root
nobody: root
system: root
toor: root
uucp: root
-# Well-known aliases.
+# Well-known aliases
manager: root
dumper: root
operator: root
-# trap decode to catch security attacks
+# RFC 2142: BUSINESS-RELATED MAILBOX NAMES
+# info: root
+# marketing: root
+# sales: root
+# support: root
+
+# RFC 2142: NETWORK OPERATIONS MAILBOX NAMES
+abuse: root
+noc: root
+security: root
+
+# RFC 2142: SUPPORT MAILBOX NAMES FOR SPECIFIC INTERNET SERVICES
+hostmaster: root
+usenet: root
+news: usenet
+webmaster: root
+www: webmaster
+uucp: root
+ftp: root
+
+# Trap decode to catch security attacks
decode: root
diff --git a/contrib/sendmail/src/aliases.5 b/contrib/sendmail/src/aliases.5
index 5142320..62b5dfb 100644
--- a/contrib/sendmail/src/aliases.5
+++ b/contrib/sendmail/src/aliases.5
@@ -9,9 +9,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: aliases.5,v 8.15.4.2 2000/12/14 23:08:15 gshapiro Exp $
+.\" $Id: aliases.5,v 8.17 2000/12/14 23:09:46 gshapiro Exp $
.\"
-.TH ALIASES 5 "$Date: 2000/12/14 23:08:15 $"
+.TH ALIASES 5 "$Date: 2000/12/14 23:09:46 $"
.SH NAME
aliases
\- aliases file for sendmail
diff --git a/contrib/sendmail/src/arpadate.c b/contrib/sendmail/src/arpadate.c
index c67c3b9..16082cd 100644
--- a/contrib/sendmail/src/arpadate.c
+++ b/contrib/sendmail/src/arpadate.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 1999, 2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,12 +11,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: arpadate.c,v 8.23.20.2 2001/05/07 22:07:26 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: arpadate.c,v 8.30 2001/09/11 04:05:12 gshapiro Exp $")
+
/*
** ARPADATE -- Create date in ARPANET format
**
@@ -74,6 +72,7 @@ arpadate(ud)
** to resolve the timezone.
*/
+ /* SM_REQUIRE(ud == NULL || strlen(ud) >= 23); */
t = curtime();
if (ud == NULL)
ud = ctime(&t);
diff --git a/contrib/sendmail/src/bf.c b/contrib/sendmail/src/bf.c
new file mode 100644
index 0000000..031b1f7
--- /dev/null
+++ b/contrib/sendmail/src/bf.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ * Contributed by Exactis.com, Inc.
+ *
+ */
+
+/*
+** This is in transition. Changed from the original bf_torek.c code
+** to use sm_io function calls directly rather than through stdio
+** translation layer. Will be made a built-in file type of libsm
+** next (once safeopen() linkable from libsm).
+*/
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: bf.c,v 8.48 2001/11/04 17:10:49 ca Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "sendmail.h"
+#include "bf.h"
+
+#include <syslog.h>
+
+/* bf io functions */
+static ssize_t sm_bfread __P((SM_FILE_T *, char *, size_t));
+static ssize_t sm_bfwrite __P((SM_FILE_T *, const char *, size_t));
+static off_t sm_bfseek __P((SM_FILE_T *, off_t, int));
+static int sm_bfclose __P((SM_FILE_T *));
+
+static int sm_bfopen __P((SM_FILE_T *, const void *, int, const void *));
+static int sm_bfsetinfo __P((SM_FILE_T *, int , void *));
+static int sm_bfgetinfo __P((SM_FILE_T *, int , void *));
+
+/*
+** Data structure for storing information about each buffered file
+** (Originally in sendmail/bf_torek.h for the curious.)
+*/
+
+struct bf
+{
+ bool bf_committed; /* Has this buffered file been committed? */
+ bool bf_ondisk; /* On disk: committed or buffer overflow */
+ long bf_flags;
+ int bf_disk_fd; /* If on disk, associated file descriptor */
+ char *bf_buf; /* Memory buffer */
+ int bf_bufsize; /* Length of above buffer */
+ int bf_buffilled; /* Bytes of buffer actually filled */
+ char *bf_filename; /* Name of buffered file, if ever committed */
+ MODE_T bf_filemode; /* Mode of buffered file, if ever committed */
+ off_t bf_offset; /* Currect file offset */
+ int bf_size; /* Total current size of file */
+ int bf_refcount; /* Reference count */
+};
+
+#ifdef BF_STANDALONE
+# define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode)
+#else /* BF_STANDALONE */
+# define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff)
+#endif /* BF_STANDALONE */
+
+struct bf_info
+{
+ char *bi_filename;
+ MODE_T bi_fmode;
+ size_t bi_bsize;
+ long bi_flags;
+};
+
+/*
+** SM_BFOPEN -- the "base" open function called by sm_io_open() for the
+** internal, file-type-specific info setup.
+**
+** Parameters:
+** fp -- file pointer being filled-in for file being open'd
+** filename -- name of the file being open'd
+** flags -- ignored
+** fmode -- file mode (stored for use later)
+** sflags -- "safeopen" flags (stored for use later)
+** rpool -- ignored (currently)
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: 0 (zero)
+*/
+
+static int
+sm_bfopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ char *filename;
+ MODE_T fmode;
+ size_t bsize;
+ long sflags;
+ struct bf *bfp;
+ int l;
+ struct stat st;
+
+ filename = ((struct bf_info *) info)->bi_filename;
+ fmode = ((struct bf_info *) info)->bi_fmode;
+ bsize = ((struct bf_info *) info)->bi_bsize;
+ sflags = ((struct bf_info *) info)->bi_flags;
+
+ /* Sanity checks */
+ if (*filename == '\0')
+ {
+ /* Empty filename string */
+ errno = ENOENT;
+ return -1;
+ }
+ if (stat(filename, &st) == 0)
+ {
+ /* File already exists on disk */
+ errno = EEXIST;
+ return -1;
+ }
+
+ /* Allocate memory */
+ bfp = (struct bf *) sm_malloc(sizeof(struct bf));
+ if (bfp == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Assign data buffer */
+ /* A zero bsize is valid, just don't allocate memory */
+ if (bsize > 0)
+ {
+ bfp->bf_buf = (char *) sm_malloc(bsize);
+ if (bfp->bf_buf == NULL)
+ {
+ bfp->bf_bufsize = 0;
+ sm_free(bfp);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ else
+ bfp->bf_buf = NULL;
+
+ /* Nearly home free, just set all the parameters now */
+ bfp->bf_committed = false;
+ bfp->bf_ondisk = false;
+ bfp->bf_refcount = 1;
+ bfp->bf_flags = sflags;
+ bfp->bf_bufsize = bsize;
+ bfp->bf_buffilled = 0;
+ l = strlen(filename) + 1;
+ bfp->bf_filename = (char *) sm_malloc(l);
+ if (bfp->bf_filename == NULL)
+ {
+ if (bfp->bf_buf != NULL)
+ sm_free(bfp->bf_buf);
+ sm_free(bfp);
+ errno = ENOMEM;
+ return -1;
+ }
+ (void) sm_strlcpy(bfp->bf_filename, filename, l);
+ bfp->bf_filemode = fmode;
+ bfp->bf_offset = 0;
+ bfp->bf_size = bsize;
+ bfp->bf_disk_fd = -1;
+ fp->f_cookie = bfp;
+
+ if (tTd(58, 8))
+ sm_dprintf("sm_bfopen(%s)\n", filename);
+
+ return 0;
+}
+
+/*
+** BFOPEN -- create a new buffered file
+**
+** Parameters:
+** filename -- the file's name
+** fmode -- what mode the file should be created as
+** bsize -- amount of buffer space to allocate (may be 0)
+** flags -- if running under sendmail, passed directly to safeopen
+**
+** Returns:
+** a SM_FILE_T * which may then be used with stdio functions,
+** or NULL on failure. SM_FILE_T * is opened for writing
+** "SM_IO_WHAT_VECTORS").
+**
+** Side Effects:
+** none.
+**
+** Sets errno:
+** any value of errno specified by sm_io_setinfo_type()
+** any value of errno specified by sm_io_open()
+** any value of errno specified by sm_io_setinfo()
+*/
+
+SM_FILE_T *
+bfopen(filename, fmode, bsize, flags)
+ char *filename;
+ MODE_T fmode;
+ size_t bsize;
+ long flags;
+{
+ MODE_T omask;
+ SM_FILE_T SM_IO_SET_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose,
+ sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo,
+ SM_TIME_FOREVER);
+ struct bf_info info;
+
+ /*
+ ** Apply current umask to fmode as it may change by the time
+ ** the file is actually created. fmode becomes the true
+ ** permissions of the file, which OPEN() must obey.
+ */
+
+ omask = umask(0);
+ fmode &= ~omask;
+ (void) umask(omask);
+
+ SM_IO_INIT_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose,
+ sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo,
+ SM_TIME_FOREVER);
+ info.bi_filename = filename;
+ info.bi_fmode = fmode;
+ info.bi_bsize = bsize;
+ info.bi_flags = flags;
+
+ return sm_io_open(&vector, SM_TIME_DEFAULT, &info, SM_IO_RDWR, NULL);
+}
+
+/*
+** SM_BFGETINFO -- returns info about an open file pointer
+**
+** Parameters:
+** fp -- file pointer to get info about
+** what -- type of info to obtain
+** valp -- thing to return the info in
+*/
+
+static int
+sm_bfgetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ struct bf *bfp;
+
+ bfp = (struct bf *) fp->f_cookie;
+ switch (what)
+ {
+ case SM_IO_WHAT_FD:
+ return bfp->bf_disk_fd;
+ default:
+ return -1;
+ }
+}
+
+/*
+** SM_BFCLOSE -- close a buffered file
+**
+** Parameters:
+** fp -- cookie of file to close
+**
+** Returns:
+** 0 to indicate success
+**
+** Side Effects:
+** deletes backing file, sm_frees memory.
+**
+** Sets errno:
+** never.
+*/
+
+static int
+sm_bfclose(fp)
+ SM_FILE_T *fp;
+{
+ struct bf *bfp;
+
+ /* Cast cookie back to correct type */
+ bfp = (struct bf *) fp->f_cookie;
+
+ /* Need to clean up the file */
+ if (bfp->bf_ondisk && !bfp->bf_committed)
+ unlink(bfp->bf_filename);
+ sm_free(bfp->bf_filename);
+
+ if (bfp->bf_disk_fd != -1)
+ close(bfp->bf_disk_fd);
+
+ /* Need to sm_free the buffer */
+ if (bfp->bf_bufsize > 0)
+ sm_free(bfp->bf_buf);
+
+ /* Finally, sm_free the structure */
+ sm_free(bfp);
+ return 0;
+}
+
+/*
+** SM_BFREAD -- read a buffered file
+**
+** Parameters:
+** cookie -- cookie of file to read
+** buf -- buffer to fill
+** nbytes -- how many bytes to read
+**
+** Returns:
+** number of bytes read or -1 indicate failure
+**
+** Side Effects:
+** none.
+**
+*/
+
+static ssize_t
+sm_bfread(fp, buf, nbytes)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t nbytes;
+{
+ struct bf *bfp;
+ ssize_t count = 0; /* Number of bytes put in buf so far */
+ int retval;
+
+ /* Cast cookie back to correct type */
+ bfp = (struct bf *) fp->f_cookie;
+
+ if (bfp->bf_offset < bfp->bf_buffilled)
+ {
+ /* Need to grab some from buffer */
+ count = nbytes;
+ if ((bfp->bf_offset + count) > bfp->bf_buffilled)
+ count = bfp->bf_buffilled - bfp->bf_offset;
+
+ memcpy(buf, bfp->bf_buf + bfp->bf_offset, count);
+ }
+
+ if ((bfp->bf_offset + nbytes) > bfp->bf_buffilled)
+ {
+ /* Need to grab some from file */
+ if (!bfp->bf_ondisk)
+ {
+ /* Oops, the file doesn't exist. EOF. */
+ if (tTd(58, 8))
+ sm_dprintf("sm_bfread(%s): to disk\n",
+ bfp->bf_filename);
+ goto finished;
+ }
+
+ /* Catch a read() on an earlier failed write to disk */
+ if (bfp->bf_disk_fd < 0)
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ if (lseek(bfp->bf_disk_fd,
+ bfp->bf_offset + count, SEEK_SET) < 0)
+ {
+ if ((errno == EINVAL) || (errno == ESPIPE))
+ {
+ /*
+ ** stdio won't be expecting these
+ ** errnos from read()! Change them
+ ** into something it can understand.
+ */
+
+ errno = EIO;
+ }
+ return -1;
+ }
+
+ while (count < nbytes)
+ {
+ retval = read(bfp->bf_disk_fd,
+ buf + count,
+ nbytes - count);
+ if (retval < 0)
+ {
+ /* errno is set implicitly by read() */
+ return -1;
+ }
+ else if (retval == 0)
+ goto finished;
+ else
+ count += retval;
+ }
+ }
+
+finished:
+ bfp->bf_offset += count;
+ return count;
+}
+
+/*
+** SM_BFSEEK -- seek to a position in a buffered file
+**
+** Parameters:
+** fp -- fp of file to seek
+** offset -- position to seek to
+** whence -- how to seek
+**
+** Returns:
+** new file offset or -1 indicate failure
+**
+** Side Effects:
+** none.
+**
+*/
+
+static off_t
+sm_bfseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+
+{
+ struct bf *bfp;
+
+ /* Cast cookie back to correct type */
+ bfp = (struct bf *) fp->f_cookie;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ bfp->bf_offset = offset;
+ break;
+
+ case SEEK_CUR:
+ bfp->bf_offset += offset;
+ break;
+
+ case SEEK_END:
+ bfp->bf_offset = bfp->bf_size + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return bfp->bf_offset;
+}
+
+/*
+** SM_BFWRITE -- write to a buffered file
+**
+** Parameters:
+** fp -- fp of file to write
+** buf -- data buffer
+** nbytes -- how many bytes to write
+**
+** Returns:
+** number of bytes written or -1 indicate failure
+**
+** Side Effects:
+** may create backing file if over memory limit for file.
+**
+*/
+
+static ssize_t
+sm_bfwrite(fp, buf, nbytes)
+ SM_FILE_T *fp;
+ const char *buf;
+ size_t nbytes;
+{
+ struct bf *bfp;
+ ssize_t count = 0; /* Number of bytes written so far */
+ int retval;
+
+ /* Cast cookie back to correct type */
+ bfp = (struct bf *) fp->f_cookie;
+
+ /* If committed, go straight to disk */
+ if (bfp->bf_committed)
+ {
+ if (lseek(bfp->bf_disk_fd, bfp->bf_offset, SEEK_SET) < 0)
+ {
+ if ((errno == EINVAL) || (errno == ESPIPE))
+ {
+ /*
+ ** stdio won't be expecting these
+ ** errnos from write()! Change them
+ ** into something it can understand.
+ */
+
+ errno = EIO;
+ }
+ return -1;
+ }
+
+ count = write(bfp->bf_disk_fd, buf, nbytes);
+ if (count < 0)
+ {
+ /* errno is set implicitly by write() */
+ return -1;
+ }
+ goto finished;
+ }
+
+ if (bfp->bf_offset < bfp->bf_bufsize)
+ {
+ /* Need to put some in buffer */
+ count = nbytes;
+ if ((bfp->bf_offset + count) > bfp->bf_bufsize)
+ count = bfp->bf_bufsize - bfp->bf_offset;
+
+ memcpy(bfp->bf_buf + bfp->bf_offset, buf, count);
+ if ((bfp->bf_offset + count) > bfp->bf_buffilled)
+ bfp->bf_buffilled = bfp->bf_offset + count;
+ }
+
+ if ((bfp->bf_offset + nbytes) > bfp->bf_bufsize)
+ {
+ /* Need to put some in file */
+ if (!bfp->bf_ondisk)
+ {
+ MODE_T omask;
+
+ /* Clear umask as bf_filemode are the true perms */
+ omask = umask(0);
+ retval = OPEN(bfp->bf_filename,
+ O_RDWR | O_CREAT | O_TRUNC,
+ bfp->bf_filemode, bfp->bf_flags);
+ (void) umask(omask);
+
+ /* Couldn't create file: failure */
+ if (retval < 0)
+ {
+ /*
+ ** stdio may not be expecting these
+ ** errnos from write()! Change to
+ ** something which it can understand.
+ ** Note that ENOSPC and EDQUOT are saved
+ ** because they are actually valid for
+ ** write().
+ */
+
+ if (!(errno == ENOSPC
+#ifdef EDQUOT
+ || errno == EDQUOT
+#endif /* EDQUOT */
+ ))
+ errno = EIO;
+
+ return -1;
+ }
+ bfp->bf_disk_fd = retval;
+ bfp->bf_ondisk = true;
+ }
+
+ /* Catch a write() on an earlier failed write to disk */
+ if (bfp->bf_ondisk && bfp->bf_disk_fd < 0)
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ if (lseek(bfp->bf_disk_fd,
+ bfp->bf_offset + count, SEEK_SET) < 0)
+ {
+ if ((errno == EINVAL) || (errno == ESPIPE))
+ {
+ /*
+ ** stdio won't be expecting these
+ ** errnos from write()! Change them into
+ ** something which it can understand.
+ */
+
+ errno = EIO;
+ }
+ return -1;
+ }
+
+ while (count < nbytes)
+ {
+ retval = write(bfp->bf_disk_fd, buf + count,
+ nbytes - count);
+ if (retval < 0)
+ {
+ /* errno is set implicitly by write() */
+ return -1;
+ }
+ else
+ count += retval;
+ }
+ }
+
+finished:
+ bfp->bf_offset += count;
+ if (bfp->bf_offset > bfp->bf_size)
+ bfp->bf_size = bfp->bf_offset;
+ return count;
+}
+
+/*
+** BFREWIND -- rewinds the SM_FILE_T *
+**
+** Parameters:
+** fp -- SM_FILE_T * to rewind
+**
+** Returns:
+** 0 on success, -1 on error
+**
+** Side Effects:
+** rewinds the SM_FILE_T * and puts it into read mode. Normally one
+** would bfopen() a file, write to it, then bfrewind() and
+** fread(). If fp is not a buffered file, this is equivalent to
+** rewind().
+**
+** Sets errno:
+** any value of errno specified by sm_io_rewind()
+*/
+
+int
+bfrewind(fp)
+ SM_FILE_T *fp;
+{
+ (void) sm_io_flush(fp, SM_TIME_DEFAULT);
+ sm_io_clearerr(fp); /* quicker just to do it */
+ return sm_io_seek(fp, SM_TIME_DEFAULT, 0, SM_IO_SEEK_SET);
+}
+
+/*
+** SM_BFCOMMIT -- "commits" the buffered file
+**
+** Parameters:
+** fp -- SM_FILE_T * to commit to disk
+**
+** Returns:
+** 0 on success, -1 on error
+**
+** Side Effects:
+** Forces the given SM_FILE_T * to be written to disk if it is not
+** already, and ensures that it will be kept after closing. If
+** fp is not a buffered file, this is a no-op.
+**
+** Sets errno:
+** any value of errno specified by open()
+** any value of errno specified by write()
+** any value of errno specified by lseek()
+*/
+
+static int
+sm_bfcommit(fp)
+ SM_FILE_T *fp;
+{
+ struct bf *bfp;
+ int retval;
+ int byteswritten;
+
+ /* Get associated bf structure */
+ bfp = (struct bf *) fp->f_cookie;
+
+ /* If already committed, noop */
+ if (bfp->bf_committed)
+ return 0;
+
+ /* Do we need to open a file? */
+ if (!bfp->bf_ondisk)
+ {
+ MODE_T omask;
+ struct stat st;
+
+ if (tTd(58, 8))
+ {
+ sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename);
+ if (tTd(58, 32))
+ sm_dprintf("bfcommit(): filemode %o flags %ld\n",
+ bfp->bf_filemode, bfp->bf_flags);
+ }
+
+ if (stat(bfp->bf_filename, &st) == 0)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ /* Clear umask as bf_filemode are the true perms */
+ omask = umask(0);
+ retval = OPEN(bfp->bf_filename, O_RDWR | O_CREAT | O_TRUNC,
+ bfp->bf_filemode, bfp->bf_flags);
+ (void) umask(omask);
+
+ /* Couldn't create file: failure */
+ if (retval < 0)
+ {
+ /* errno is set implicitly by open() */
+ return -1;
+ }
+
+ bfp->bf_disk_fd = retval;
+ bfp->bf_ondisk = true;
+ }
+
+ /* Write out the contents of our buffer, if we have any */
+ if (bfp->bf_buffilled > 0)
+ {
+ byteswritten = 0;
+
+ if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0)
+ {
+ /* errno is set implicitly by lseek() */
+ return -1;
+ }
+
+ while (byteswritten < bfp->bf_buffilled)
+ {
+ retval = write(bfp->bf_disk_fd,
+ bfp->bf_buf + byteswritten,
+ bfp->bf_buffilled - byteswritten);
+ if (retval < 0)
+ {
+ /* errno is set implicitly by write() */
+ return -1;
+ }
+ else
+ byteswritten += retval;
+ }
+ }
+ bfp->bf_committed = true;
+
+ /* Invalidate buf; all goes to file now */
+ bfp->bf_buffilled = 0;
+ if (bfp->bf_bufsize > 0)
+ {
+ /* Don't need buffer anymore; free it */
+ bfp->bf_bufsize = 0;
+ sm_free(bfp->bf_buf);
+ }
+ return 0;
+}
+
+/*
+** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T *
+**
+** Parameters:
+** fp -- SM_FILE_T * to truncate
+**
+** Returns:
+** 0 on success, -1 on error
+**
+** Side Effects:
+** rewinds the SM_FILE_T *, truncates it to zero length, and puts
+** it into write mode.
+**
+** Sets errno:
+** any value of errno specified by fseek()
+** any value of errno specified by ftruncate()
+*/
+
+static int
+sm_bftruncate(fp)
+ SM_FILE_T *fp;
+{
+ struct bf *bfp;
+
+ if (bfrewind(fp) < 0)
+ return -1;
+
+ /* Get bf structure */
+ bfp = (struct bf *) fp->f_cookie;
+ bfp->bf_buffilled = 0;
+ bfp->bf_size = 0;
+
+ /* Need to zero the buffer */
+ if (bfp->bf_bufsize > 0)
+ memset(bfp->bf_buf, '\0', bfp->bf_bufsize);
+ if (bfp->bf_ondisk)
+ {
+#if NOFTRUNCATE
+ /* XXX: Not much we can do except rewind it */
+ errno = EINVAL;
+ return -1;
+#else /* NOFTRUNCATE */
+ return ftruncate(bfp->bf_disk_fd, 0);
+#endif /* NOFTRUNCATE */
+ }
+ else
+ return 0;
+}
+
+/*
+** SM_BFSETINFO -- set/change info for an open file pointer
+**
+** Parameters:
+** fp -- file pointer to get info about
+** what -- type of info to set/change
+** valp -- thing to set/change the info to
+**
+*/
+
+static int
+sm_bfsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ struct bf *bfp;
+ int bsize;
+
+ /* Get bf structure */
+ bfp = (struct bf *) fp->f_cookie;
+ switch (what)
+ {
+ case SM_BF_SETBUFSIZE:
+ bsize = *((int *) valp);
+ bfp->bf_bufsize = bsize;
+
+ /* A zero bsize is valid, just don't allocate memory */
+ if (bsize > 0)
+ {
+ bfp->bf_buf = (char *) sm_malloc(bsize);
+ if (bfp->bf_buf == NULL)
+ {
+ bfp->bf_bufsize = 0;
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ else
+ bfp->bf_buf = NULL;
+ return 0;
+ case SM_BF_COMMIT:
+ return sm_bfcommit(fp);
+ case SM_BF_TRUNCATE:
+ return sm_bftruncate(fp);
+ case SM_BF_TEST:
+ return 1; /* always */
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
diff --git a/contrib/sendmail/src/bf.h b/contrib/sendmail/src/bf.h
index 8fc86ae..030a6f8 100644
--- a/contrib/sendmail/src/bf.h
+++ b/contrib/sendmail/src/bf.h
@@ -1,27 +1,33 @@
/*
- * Copyright (c) 1999, 2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
- * $Id: bf.h,v 8.5.16.2 2001/02/14 04:07:27 gshapiro Exp $
+ * $Id: bf.h,v 8.15 2001/05/31 21:02:53 ca Exp $
*
* Contributed by Exactis.com, Inc.
*
*/
#ifndef BF_H
-#define BF_H 1
+# define BF_H 1
-extern FILE *bfopen __P((char *, int, size_t, long));
-extern FILE *bfdup __P((FILE *));
-extern int bfcommit __P((FILE *));
-extern int bfrewind __P((FILE *));
-extern int bftruncate __P((FILE *));
-extern int bffsync __P((FILE *));
-extern int bfclose __P((FILE *));
-extern bool bftest __P((FILE *));
+extern SM_FILE_T *bfopen __P((char *, MODE_T, size_t, long));
+extern SM_FILE_T *bfdup __P((SM_FILE_T *));
+extern int bfcommit __P((SM_FILE_T *));
+extern int bfrewind __P((SM_FILE_T *));
+extern int bftruncate __P((SM_FILE_T *));
+extern int bfclose __P((SM_FILE_T *));
+extern bool bftest __P((SM_FILE_T *));
-#endif /* BF_H */
+/* "what" flags for sm_io_setinfo() for the SM_FILE_TYPE file type */
+# define SM_BF_SETBUFSIZE 1000 /* set buffer size */
+# define SM_BF_COMMIT 1001 /* commit file to disk */
+# define SM_BF_TRUNCATE 1002 /* truncate the file */
+# define SM_BF_TEST 1003 /* historical support; temp */
+
+# define BF_FILE_TYPE "SendmailBufferedFile"
+#endif /* ! BF_H */
diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c
index fcf3117..95a14ae 100644
--- a/contrib/sendmail/src/collect.c
+++ b/contrib/sendmail/src/collect.c
@@ -11,18 +11,232 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: collect.c,v 8.136.4.22 2001/06/07 21:01:02 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: collect.c,v 8.237 2001/12/10 19:56:03 ca Exp $")
static void collecttimeout __P((time_t));
-static void dferror __P((FILE *volatile, char *, ENVELOPE *));
+static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *));
static void eatfrom __P((char *volatile, ENVELOPE *));
+static void collect_doheader __P((ENVELOPE *));
+static SM_FILE_T *collect_dfopen __P((ENVELOPE *));
+static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));
+
+/*
+** COLLECT_EOH -- end-of-header processing in collect()
+**
+** Called by collect() when it encounters the blank line
+** separating the header from the message body, or when it
+** encounters EOF in a message that contains only a header.
+**
+** Parameters:
+** e -- envelope
+** numhdrs -- number of headers
+** hdrslen -- length of headers
+**
+** Results:
+** NULL, or handle to open data file
+**
+** Side Effects:
+** end-of-header check ruleset is invoked.
+** envelope state is updated.
+** headers may be added and deleted.
+** selects the queue.
+** opens the data file.
+*/
+
+static SM_FILE_T *
+collect_eoh(e, numhdrs, hdrslen)
+ ENVELOPE *e;
+ int numhdrs;
+ int hdrslen;
+{
+ char hnum[16];
+ char hsize[16];
+
+ /* call the end-of-header check ruleset */
+ (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs);
+ (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen);
+ if (tTd(30, 10))
+ sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
+ hnum, hsize);
+ (void) rscheck("check_eoh", hnum, hsize, e, false, true, 3, NULL,
+ e->e_id);
+
+ /*
+ ** Process the header,
+ ** select the queue, open the data file.
+ */
+
+ collect_doheader(e);
+ return collect_dfopen(e);
+}
+
+/*
+** COLLECT_DOHEADER -- process header in collect()
+**
+** Called by collect() after it has finished parsing the header,
+** but before it selects the queue and creates the data file.
+** The results of processing the header will affect queue selection.
+**
+** Parameters:
+** e -- envelope
+**
+** Results:
+** none.
+**
+** Side Effects:
+** envelope state is updated.
+** headers may be added and deleted.
+*/
+
+static void
+collect_doheader(e)
+ ENVELOPE *e;
+{
+ /*
+ ** Find out some information from the headers.
+ ** Examples are who is the from person & the date.
+ */
+
+ eatheader(e, true, false);
+
+ if (GrabTo && e->e_sendqueue == NULL)
+ usrerr("No recipient addresses found in header");
+
+ /* collect statistics */
+ if (OpMode != MD_VERIFY)
+ markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
+
+ /*
+ ** If we have a Return-Receipt-To:, turn it into a DSN.
+ */
+
+ if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
+ {
+ ADDRESS *q;
+
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ if (!bitset(QHASNOTIFY, q->q_flags))
+ q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
+ }
+
+ /*
+ ** Add an appropriate recipient line if we have none.
+ */
+
+ if (hvalue("to", e->e_header) != NULL ||
+ hvalue("cc", e->e_header) != NULL ||
+ hvalue("apparently-to", e->e_header) != NULL)
+ {
+ /* have a valid recipient header -- delete Bcc: headers */
+ e->e_flags |= EF_DELETE_BCC;
+ }
+ else if (hvalue("bcc", e->e_header) == NULL)
+ {
+ /* no valid recipient headers */
+ register ADDRESS *q;
+ char *hdr = NULL;
+
+ /* create a recipient field */
+ switch (NoRecipientAction)
+ {
+ case NRA_ADD_APPARENTLY_TO:
+ hdr = "Apparently-To";
+ break;
+
+ case NRA_ADD_TO:
+ hdr = "To";
+ break;
+
+ case NRA_ADD_BCC:
+ addheader("Bcc", " ", 0, e);
+ break;
+
+ case NRA_ADD_TO_UNDISCLOSED:
+ addheader("To", "undisclosed-recipients:;", 0, e);
+ break;
+ }
+
+ if (hdr != NULL)
+ {
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (q->q_alias != NULL)
+ continue;
+ if (tTd(30, 3))
+ sm_dprintf("Adding %s: %s\n",
+ hdr, q->q_paddr);
+ addheader(hdr, q->q_paddr, 0, e);
+ }
+ }
+ }
+}
+
+/*
+** COLLECT_DFOPEN -- open the message data file
+**
+** Called by collect() after it has finished processing the header.
+** Queue selection occurs at this point, possibly based on the
+** envelope's recipient list and on header information.
+**
+** Parameters:
+** e -- envelope
+**
+** Results:
+** NULL, or a pointer to an open data file,
+** into which the message body will be written by collect().
+**
+** Side Effects:
+** Calls syserr, sets EF_FATALERRS and returns NULL
+** if there is insufficient disk space.
+** Aborts process if data file could not be opened.
+** Otherwise, the queue is selected,
+** e->e_{dfino,dfdev,msgsize,flags} are updated,
+** and a pointer to an open data file is returned.
+*/
+
+static SM_FILE_T *
+collect_dfopen(e)
+ ENVELOPE *e;
+{
+ MODE_T oldumask = 0;
+ int dfd;
+ struct stat stbuf;
+ SM_FILE_T *df;
+ char *dfname;
+
+ if (!setnewqueue(e))
+ return NULL;
+
+ dfname = queuename(e, DATAFL_LETTER);
+ if (bitset(S_IWGRP, QueueFileMode))
+ oldumask = umask(002);
+ df = bfopen(dfname, QueueFileMode, DataFileBufferSize,
+ SFF_OPENASROOT);
+ if (bitset(S_IWGRP, QueueFileMode))
+ (void) umask(oldumask);
+ if (df == NULL)
+ {
+ syserr("@Cannot create %s", dfname);
+ e->e_flags |= EF_NO_BODY_RETN;
+ flush_errors(true);
+ finis(true, true, ExitStat);
+ /* NOTREACHED */
+ }
+ dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
+ if (dfd < 0 || fstat(dfd, &stbuf) < 0)
+ e->e_dfino = -1;
+ else
+ {
+ e->e_dfdev = stbuf.st_dev;
+ e->e_dfino = stbuf.st_ino;
+ }
+ e->e_flags |= EF_HAS_DF;
+ return df;
+}
- /*
+/*
** COLLECT -- read & parse message header & make temp file.
**
** Creates a temporary file name and copies the standard
@@ -42,13 +256,20 @@ static void eatfrom __P((char *volatile, ENVELOPE *));
** none.
**
** Side Effects:
-** Temp file is created and filled.
-** The from person may be set.
+** If successful,
+** - Data file is created and filled, and e->e_dfp is set.
+** - The from person may be set.
+** If the "enough disk space" check fails,
+** - syserr is called.
+** - e->e_dfp is NULL.
+** - e->e_flags & EF_FATALERRS is set.
+** - collect() returns.
+** If data file cannot be created, the process is terminated.
*/
static jmp_buf CtxCollectTimeout;
static bool volatile CollectProgress;
-static EVENT *volatile CollectTimeout = NULL;
+static SM_EVENT *volatile CollectTimeout = NULL;
/* values for input state machine */
#define IS_NORM 0 /* middle of line */
@@ -65,83 +286,44 @@ static EVENT *volatile CollectTimeout = NULL;
void
collect(fp, smtpmode, hdrp, e)
- FILE *fp;
+ SM_FILE_T *fp;
bool smtpmode;
HDR **hdrp;
register ENVELOPE *e;
{
- register FILE *volatile df;
- volatile bool ignrdot = smtpmode ? FALSE : IgnrDot;
- volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
+ register SM_FILE_T *volatile df;
+ volatile bool ignrdot;
+ volatile time_t dbto;
register char *volatile bp;
- volatile int c = EOF;
- volatile bool inputerr = FALSE;
+ volatile int c;
+ volatile bool inputerr;
bool headeronly;
char *volatile buf;
volatile int buflen;
volatile int istate;
volatile int mstate;
- volatile int hdrslen = 0;
- volatile int numhdrs = 0;
- volatile int dfd;
- volatile int rstat = EX_OK;
- u_char *volatile pbp;
- u_char peekbuf[8];
- char hsize[16];
- char hnum[16];
- char dfname[MAXPATHLEN];
+ volatile int hdrslen;
+ volatile int numhdrs;
+ volatile int afd;
+ unsigned char *volatile pbp;
+ unsigned char peekbuf[8];
char bufbuf[MAXLINE];
+ df = NULL;
+ ignrdot = smtpmode ? false : IgnrDot;
+ dbto = smtpmode ? TimeOuts.to_datablock : 0;
+ c = SM_IO_EOF;
+ inputerr = false;
headeronly = hdrp != NULL;
-
- /*
- ** Create the temp file name and create the file.
- */
-
- if (!headeronly)
- {
- struct stat stbuf;
- long sff = SFF_OPENASROOT;
-
-
- (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
-#if _FFR_QUEUE_FILE_MODE
- {
- MODE_T oldumask;
-
- if (bitset(S_IWGRP, QueueFileMode))
- oldumask = umask(002);
- df = bfopen(dfname, QueueFileMode,
- DataFileBufferSize, sff);
- if (bitset(S_IWGRP, QueueFileMode))
- (void) umask(oldumask);
- }
-#else /* _FFR_QUEUE_FILE_MODE */
- df = bfopen(dfname, FileMode, DataFileBufferSize, sff);
-#endif /* _FFR_QUEUE_FILE_MODE */
- if (df == NULL)
- {
- HoldErrs = FALSE;
- if (smtpmode)
- syserr("421 4.3.5 Unable to create data file");
- else
- syserr("Cannot create %s", dfname);
- e->e_flags |= EF_NO_BODY_RETN;
- finis(TRUE, ExitStat);
- /* NOTREACHED */
- }
- dfd = fileno(df);
- if (dfd < 0 || fstat(dfd, &stbuf) < 0)
- e->e_dfino = -1;
- else
- {
- e->e_dfdev = stbuf.st_dev;
- e->e_dfino = stbuf.st_ino;
- }
- HasEightBits = FALSE;
- e->e_msgsize = 0;
- e->e_flags |= EF_HAS_DF;
- }
+ hdrslen = 0;
+ numhdrs = 0;
+ HasEightBits = false;
+ buf = bp = bufbuf;
+ buflen = sizeof bufbuf;
+ pbp = peekbuf;
+ istate = IS_BOL;
+ mstate = SaveFrom ? MS_HEADER : MS_UFROM;
+ CollectProgress = false;
/*
** Tell ARPANET to go ahead.
@@ -151,7 +333,7 @@ collect(fp, smtpmode, hdrp, e)
message("354 Enter mail, end with \".\" on a line by itself");
if (tTd(30, 2))
- dprintf("collect\n");
+ sm_dprintf("collect\n");
/*
** Read the message.
@@ -162,13 +344,6 @@ collect(fp, smtpmode, hdrp, e)
** the larger picture (e.g., header versus body).
*/
- buf = bp = bufbuf;
- buflen = sizeof bufbuf;
- pbp = peekbuf;
- istate = IS_BOL;
- mstate = SaveFrom ? MS_HEADER : MS_UFROM;
- CollectProgress = FALSE;
-
if (dbto != 0)
{
/* handle possible input timeout */
@@ -176,52 +351,57 @@ collect(fp, smtpmode, hdrp, e)
{
if (LogLevel > 2)
sm_syslog(LOG_NOTICE, e->e_id,
- "timeout waiting for input from %s during message collect",
- CurHostName ? CurHostName : "<local machine>");
+ "timeout waiting for input from %s during message collect",
+ CURHOSTNAME);
errno = 0;
usrerr("451 4.4.1 timeout waiting for input during message collect");
goto readerr;
}
- CollectTimeout = setevent(dbto, collecttimeout, dbto);
+ CollectTimeout = sm_setevent(dbto, collecttimeout, dbto);
}
+ e->e_msgsize = 0;
for (;;)
{
if (tTd(30, 35))
- dprintf("top, istate=%d, mstate=%d\n", istate, mstate);
+ sm_dprintf("top, istate=%d, mstate=%d\n", istate,
+ mstate);
for (;;)
{
if (pbp > peekbuf)
c = *--pbp;
else
{
- while (!feof(fp) && !ferror(fp))
+ while (!sm_io_eof(fp) && !sm_io_error(fp))
{
errno = 0;
- c = getc(fp);
-
- if (c == EOF && errno == EINTR)
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
+ if (c == SM_IO_EOF && errno == EINTR)
{
/* Interrupted, retry */
- clearerr(fp);
+ sm_io_clearerr(fp);
continue;
}
break;
}
- CollectProgress = TRUE;
+ CollectProgress = true;
if (TrafficLogFile != NULL && !headeronly)
{
if (istate == IS_BOL)
- (void) fprintf(TrafficLogFile,
- "%05d <<< ",
- (int) getpid());
- if (c == EOF)
- (void) fprintf(TrafficLogFile,
- "[EOF]\n");
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d <<< ",
+ (int) CurrentPid);
+ if (c == SM_IO_EOF)
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "[EOF]\n");
else
- (void) putc(c, TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ c);
}
- if (c == EOF)
+ if (c == SM_IO_EOF)
goto readerr;
if (SevenBitInput)
c &= 0x7f;
@@ -229,7 +409,7 @@ collect(fp, smtpmode, hdrp, e)
HasEightBits |= bitset(0x80, c);
}
if (tTd(30, 94))
- dprintf("istate=%d, c=%c (0x%x)\n",
+ sm_dprintf("istate=%d, c=%c (0x%x)\n",
istate, (char) c, c);
switch (istate)
{
@@ -278,7 +458,8 @@ collect(fp, smtpmode, hdrp, e)
istate = IS_BOL;
else
{
- (void) ungetc(c, fp);
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
+ c);
c = '\r';
istate = IS_NORM;
}
@@ -290,7 +471,8 @@ collect(fp, smtpmode, hdrp, e)
istate = IS_CR;
continue;
}
- else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
+ else if (c == '\n' && !bitset(EF_NL_NOT_EOL,
+ e->e_flags))
istate = IS_BOL;
else
istate = IS_NORM;
@@ -313,7 +495,9 @@ bufferchar:
case MS_BODY:
/* just put the character out */
if (!bitset(EF_TOOBIG, e->e_flags))
- (void) putc(c, df);
+ (void) sm_io_putc(df, SM_TIME_DEFAULT,
+ c);
+
/* FALLTHROUGH */
case MS_DISCARD:
@@ -338,11 +522,22 @@ bufferchar:
memmove(buf, obuf, bp - obuf);
bp = &buf[bp - obuf];
if (obuf != bufbuf)
- sm_free(obuf);
+ sm_free(obuf); /* XXX */
}
+
+ /*
+ ** XXX Notice: the logic here is broken.
+ ** An input to sendmail that doesn't contain a
+ ** header but starts immediately with the body whose
+ ** first line contain characters which match the
+ ** following "if" will cause problems: those
+ ** characters will NOT appear in the output...
+ ** Do we care?
+ */
+
if (c >= 0200 && c <= 0237)
{
-#if 0 /* causes complaints -- figure out something for 8.11 */
+#if 0 /* causes complaints -- figure out something for 8.n+1 */
usrerr("Illegal character 0x%x in header", c);
#else /* 0 */
/* EMPTY */
@@ -351,7 +546,7 @@ bufferchar:
else if (c != '\0')
{
*bp++ = c;
- hdrslen++;
+ ++hdrslen;
if (!headeronly &&
MaxHeadersLength > 0 &&
hdrslen > MaxHeadersLength)
@@ -359,7 +554,7 @@ bufferchar:
sm_syslog(LOG_NOTICE, e->e_id,
"headers too large (%d max) from %s during message collect",
MaxHeadersLength,
- CurHostName != NULL ? CurHostName : "localhost");
+ CURHOSTNAME);
errno = 0;
e->e_flags |= EF_CLRQUEUE;
e->e_status = "5.6.0";
@@ -376,7 +571,7 @@ bufferchar:
nextstate:
if (tTd(30, 35))
- dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
+ sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
istate, mstate, buf);
switch (mstate)
{
@@ -402,12 +597,12 @@ nextstate:
/* check for possible continuation line */
do
{
- clearerr(fp);
+ sm_io_clearerr(fp);
errno = 0;
- c = getc(fp);
- } while (c == EOF && errno == EINTR);
- if (c != EOF)
- (void) ungetc(c, fp);
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
+ } while (c == SM_IO_EOF && errno == EINTR);
+ if (c != SM_IO_EOF)
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
if (c == ' ' || c == '\t')
{
/* yep -- defer this */
@@ -431,19 +626,14 @@ nextstate:
case MS_BODY:
if (tTd(30, 1))
- dprintf("EOH\n");
+ sm_dprintf("EOH\n");
if (headeronly)
goto readerr;
- /* call the end-of-header check ruleset */
- snprintf(hnum, sizeof hnum, "%d", numhdrs);
- snprintf(hsize, sizeof hsize, "%d", hdrslen);
- if (tTd(30, 10))
- dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
- hnum, hsize);
- rstat = rscheck("check_eoh", hnum, hsize, e, FALSE,
- TRUE, 4, NULL);
+ df = collect_eoh(e, numhdrs, hdrslen);
+ if (df == NULL)
+ e->e_flags |= EF_TOOBIG;
bp = buf;
@@ -460,7 +650,8 @@ nextstate:
if (!bitset(EF_TOOBIG, e->e_flags))
{
while (*bp != '\0')
- (void) putc(*bp++, df);
+ (void) sm_io_putc(df, SM_TIME_DEFAULT,
+ *bp++);
}
break;
}
@@ -468,43 +659,54 @@ nextstate:
}
readerr:
- if ((feof(fp) && smtpmode) || ferror(fp))
+ if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
{
- const char *errmsg = errstring(errno);
+ const char *errmsg;
+ if (sm_io_eof(fp))
+ errmsg = "unexpected close";
+ else
+ errmsg = sm_errstring(errno);
if (tTd(30, 1))
- dprintf("collect: premature EOM: %s\n", errmsg);
- if (LogLevel >= 2)
+ sm_dprintf("collect: premature EOM: %s\n", errmsg);
+ if (LogLevel > 1)
sm_syslog(LOG_WARNING, e->e_id,
"collect: premature EOM: %s", errmsg);
- inputerr = TRUE;
+ inputerr = true;
}
/* reset global timer */
if (CollectTimeout != NULL)
- clrevent(CollectTimeout);
+ sm_clrevent(CollectTimeout);
if (headeronly)
return;
+ if (mstate != MS_BODY)
+ {
+ /* no body or discard, so we never opened the data file */
+ SM_ASSERT(df == NULL);
+ df = collect_eoh(e, numhdrs, hdrslen);
+ }
+
if (df == NULL)
{
/* skip next few clauses */
/* EMPTY */
}
- else if (fflush(df) != 0 || ferror(df))
+ else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df))
{
- dferror(df, "fflush||ferror", e);
- flush_errors(TRUE);
- finis(TRUE, ExitStat);
+ dferror(df, "sm_io_flush||sm_io_error", e);
+ flush_errors(true);
+ finis(true, true, ExitStat);
/* NOTREACHED */
}
- else if (!SuperSafe)
+ else if (SuperSafe != SAFE_REALLY)
{
/* skip next few clauses */
/* EMPTY */
}
- else if (bfcommit(df) < 0)
+ else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL)
{
int save_errno = errno;
@@ -512,40 +714,45 @@ readerr:
{
char *dfile;
struct stat st;
+ int dfd;
- dfile = queuename(e, 'd');
+ dfile = queuename(e, DATAFL_LETTER);
if (stat(dfile, &st) < 0)
st.st_size = -1;
errno = EEXIST;
- syserr("collect: bfcommit(%s): already on disk, size = %ld",
+ syserr("@collect: bfcommit(%s): already on disk, size = %ld",
dfile, (long) st.st_size);
- dfd = fileno(df);
+ dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
if (dfd >= 0)
- dumpfd(dfd, TRUE, TRUE);
+ dumpfd(dfd, true, true);
}
errno = save_errno;
dferror(df, "bfcommit", e);
- flush_errors(TRUE);
- finis(save_errno != EEXIST, ExitStat);
+ flush_errors(true);
+ finis(save_errno != EEXIST, true, ExitStat);
}
- else if (bffsync(df) < 0)
+ else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 &&
+ fsync(afd) < 0)
{
- dferror(df, "bffsync", e);
- flush_errors(TRUE);
- finis(TRUE, ExitStat);
+ dferror(df, "fsync", e);
+ flush_errors(true);
+ finis(true, true, ExitStat);
/* NOTREACHED */
}
- else if (bfclose(df) < 0)
+ else if (sm_io_close(df, SM_TIME_DEFAULT) < 0)
{
- dferror(df, "bfclose", e);
- flush_errors(TRUE);
- finis(TRUE, ExitStat);
+ dferror(df, "sm_io_close", e);
+ flush_errors(true);
+ finis(true, true, ExitStat);
/* NOTREACHED */
}
else
{
/* everything is happily flushed to disk */
df = NULL;
+
+ /* remove from available space in filesystem */
+ updfs(e, false, true);
}
/* An EOF when running SMTP is an error */
@@ -558,19 +765,18 @@ readerr:
if (host == NULL)
host = "localhost";
- if (feof(fp))
+ if (sm_io_eof(fp))
problem = "unexpected close";
- else if (ferror(fp))
+ else if (sm_io_error(fp))
problem = "I/O error";
else
problem = "read timeout";
- if (LogLevel > 0 && feof(fp))
+ if (LogLevel > 0 && sm_io_eof(fp))
sm_syslog(LOG_NOTICE, e->e_id,
- "collect: %s on connection from %.100s, sender=%s: %s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
- errstring(errno));
- if (feof(fp))
+ "collect: %s on connection from %.100s, sender=%s",
+ problem, host,
+ shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+ if (sm_io_eof(fp))
usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
problem, host,
shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
@@ -584,104 +790,32 @@ readerr:
e->e_flags &= ~EF_FATALERRS;
e->e_flags |= EF_CLRQUEUE;
- /* and don't try to deliver the partial message either */
- if (InChild)
- ExitStat = EX_QUIT;
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
/* NOTREACHED */
}
- /*
- ** Find out some information from the headers.
- ** Examples are who is the from person & the date.
- */
-
- eatheader(e, TRUE);
-
- if (GrabTo && e->e_sendqueue == NULL)
- usrerr("No recipient addresses found in header");
-
- /* collect statistics */
- if (OpMode != MD_VERIFY)
- markstats(e, (ADDRESS *) NULL, FALSE);
-
- /*
- ** If we have a Return-Receipt-To:, turn it into a DSN.
- */
-
- if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
+ /* Log collection information. */
+ if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
{
- ADDRESS *q;
-
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- if (!bitset(QHASNOTIFY, q->q_flags))
- q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
- }
-
- /*
- ** Add an Apparently-To: line if we have no recipient lines.
- */
-
- if (hvalue("to", e->e_header) != NULL ||
- hvalue("cc", e->e_header) != NULL ||
- hvalue("apparently-to", e->e_header) != NULL)
- {
- /* have a valid recipient header -- delete Bcc: headers */
- e->e_flags |= EF_DELETE_BCC;
- }
- else if (hvalue("bcc", e->e_header) == NULL)
- {
- /* no valid recipient headers */
- register ADDRESS *q;
- char *hdr = NULL;
-
- /* create an Apparently-To: field */
- /* that or reject the message.... */
- switch (NoRecipientAction)
- {
- case NRA_ADD_APPARENTLY_TO:
- hdr = "Apparently-To";
- break;
-
- case NRA_ADD_TO:
- hdr = "To";
- break;
-
- case NRA_ADD_BCC:
- addheader("Bcc", " ", 0, &e->e_header);
- break;
-
- case NRA_ADD_TO_UNDISCLOSED:
- addheader("To", "undisclosed-recipients:;", 0, &e->e_header);
- break;
- }
-
- if (hdr != NULL)
- {
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (q->q_alias != NULL)
- continue;
- if (tTd(30, 3))
- dprintf("Adding %s: %s\n",
- hdr, q->q_paddr);
- addheader(hdr, q->q_paddr, 0, &e->e_header);
- }
- }
+ logsender(e, e->e_msgid);
+ e->e_flags &= ~EF_LOGSENDER;
}
/* check for message too large */
if (bitset(EF_TOOBIG, e->e_flags))
{
e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
- e->e_status = "5.2.3";
- usrerrenh(e->e_status,
- "552 Message exceeds maximum fixed size (%ld)",
- MaxMessageSize);
- if (LogLevel > 6)
- sm_syslog(LOG_NOTICE, e->e_id,
- "message size (%ld) exceeds maximum (%ld)",
- e->e_msgsize, MaxMessageSize);
+ if (!bitset(EF_FATALERRS, e->e_flags))
+ {
+ e->e_status = "5.2.3";
+ usrerrenh(e->e_status,
+ "552 Message exceeds maximum fixed size (%ld)",
+ MaxMessageSize);
+ if (LogLevel > 6)
+ sm_syslog(LOG_NOTICE, e->e_id,
+ "message size (%ld) exceeds maximum (%ld)",
+ e->e_msgsize, MaxMessageSize);
+ }
}
/* check for illegal 8-bit data */
@@ -699,27 +833,26 @@ readerr:
{
/* if it claimed to be 8 bits, well, it lied.... */
if (e->e_bodytype != NULL &&
- strcasecmp(e->e_bodytype, "8BITMIME") == 0)
+ sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0)
e->e_bodytype = "7BIT";
}
- if (SuperSafe)
+ if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags))
{
- if ((e->e_dfp = fopen(dfname, "r")) == NULL)
+ char *dfname = queuename(e, DATAFL_LETTER);
+ if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
+ SM_IO_RDONLY, NULL)) == NULL)
{
/* we haven't acked receipt yet, so just chuck this */
- syserr("Cannot reopen %s", dfname);
- finis(TRUE, ExitStat);
+ syserr("@Cannot reopen %s", dfname);
+ finis(true, true, ExitStat);
/* NOTREACHED */
}
}
else
e->e_dfp = df;
- if (e->e_dfp == NULL)
- syserr("!collect: no e_dfp");
}
-
static void
collecttimeout(timeout)
time_t timeout;
@@ -735,9 +868,9 @@ collecttimeout(timeout)
if (CollectProgress)
{
/* reset the timeout */
- CollectTimeout = sigsafe_setevent(timeout, collecttimeout,
- timeout);
- CollectProgress = FALSE;
+ CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout,
+ timeout);
+ CollectProgress = false;
}
else
{
@@ -751,12 +884,16 @@ collecttimeout(timeout)
errno = ETIMEDOUT;
longjmp(CtxCollectTimeout, 1);
}
-
errno = save_errno;
}
- /*
+/*
** DFERROR -- signal error on writing the data file.
**
+** Called by collect(). Collect() always terminates the process
+** immediately after calling dferror(), which means that the SMTP
+** session will be terminated, which means that any error message
+** issued by dferror must be a 421 error, as per RFC 821.
+**
** Parameters:
** df -- the file pointer for the data file.
** msg -- detailed message.
@@ -772,13 +909,13 @@ collecttimeout(timeout)
static void
dferror(df, msg, e)
- FILE *volatile df;
+ SM_FILE_T *volatile df;
char *msg;
register ENVELOPE *e;
{
char *dfname;
- dfname = queuename(e, 'd');
+ dfname = queuename(e, DATAFL_LETTER);
setstat(EX_IOERR);
if (errno == ENOSPC)
{
@@ -794,46 +931,54 @@ dferror(df, msg, e)
if (
#if STAT64 > 0
- fstat64(fileno(df), &st)
+ fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
#else /* STAT64 > 0 */
- fstat(fileno(df), &st)
+ fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
#endif /* STAT64 > 0 */
< 0)
st.st_size = 0;
- (void) freopen(dfname, "w", df);
+ (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname,
+ SM_IO_WRONLY, NULL, df);
if (st.st_size <= 0)
- fprintf(df, "\n*** Mail could not be accepted");
- /*CONSTCOND*/
- else if (sizeof st.st_size > sizeof (long))
- fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n",
- quad_to_string(st.st_size));
+ (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
+ "\n*** Mail could not be accepted");
else
- fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n",
- (unsigned long) st.st_size);
- fprintf(df, "*** at %s due to lack of disk space for temp file.\n",
+ (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
+ "\n*** Mail of at least %llu bytes could not be accepted\n",
+ (ULONGLONG_T) st.st_size);
+ (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
+ "*** at %s due to lack of disk space for temp file.\n",
MyHostName);
- avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize);
+ avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir),
+ &bsize);
if (avail > 0)
{
if (bsize > 1024)
avail *= bsize / 1024;
else if (bsize < 1024)
avail /= 1024 / bsize;
- fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n",
+ (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
+ "*** Currently, %ld kilobytes are available for mail temp files.\n",
avail);
}
+#if 0
+ /* Wrong response code; should be 421. */
e->e_status = "4.3.1";
usrerrenh(e->e_status, "452 Out of disk space for temp file");
+#else /* 0 */
+ syserr("421 4.3.1 Out of disk space for temp file");
+#endif /* 0 */
}
else
- syserr("collect: Cannot write %s (%s, uid=%d)",
- dfname, msg, geteuid());
- if (freopen("/dev/null", "w", df) == NULL)
+ syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)",
+ dfname, msg, geteuid(), getegid());
+ if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
+ SM_IO_WRONLY, NULL, df) == NULL)
sm_syslog(LOG_ERR, e->e_id,
- "dferror: freopen(\"/dev/null\") failed: %s",
- errstring(errno));
+ "dferror: sm_io_reopen(\"/dev/null\") failed: %s",
+ sm_errstring(errno));
}
- /*
+/*
** EATFROM -- chew up a UNIX style from line and process
**
** This does indeed make some assumptions about the format
@@ -873,7 +1018,7 @@ eatfrom(fm, e)
register char **dt;
if (tTd(30, 2))
- dprintf("eatfrom(%s)\n", fm);
+ sm_dprintf("eatfrom(%s)\n", fm);
/* find the date part */
p = fm;
@@ -911,13 +1056,12 @@ eatfrom(fm, e)
if (*p != '\0')
{
- char *q;
+ char *q, buf[25];
/* we have found a date */
- q = xalloc(25);
- (void) strlcpy(q, p, 25);
- q = arpadate(q);
- define('a', newstr(q), e);
+ (void) sm_strlcpy(buf, p, sizeof(buf));
+ q = arpadate(buf);
+ macdefine(&e->e_macro, A_TEMP, 'a', q);
}
}
#endif /* ! NOTUNIX */
diff --git a/contrib/sendmail/src/conf.c b/contrib/sendmail/src/conf.c
index 8c90cf9..41644e0 100644
--- a/contrib/sendmail/src/conf.c
+++ b/contrib/sendmail/src/conf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,11 +11,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: conf.c,v 8.646.2.2.2.87 2001/07/20 23:56:52 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+
+SM_RCSID("@(#)$Id: conf.c,v 8.939 2002/01/09 17:26:28 gshapiro Exp $")
+
#include <sendmail/pathnames.h>
# include <sys/ioctl.h>
@@ -32,6 +31,7 @@ static char id[] = "@(#)$Id: conf.c,v 8.646.2.2.2.87 2001/07/20 23:56:52 gshapir
static void setupmaps __P((void));
static void setupmailers __P((void));
+static void setupqueues __P((void));
static int get_num_procs_online __P((void));
@@ -79,6 +79,7 @@ struct hdrinfo HdrInfo[] =
{ "errors-to", H_FROM|H_ERRORSTO, NULL },
{ "full-name", H_ACHECK, NULL },
{ "return-receipt-to", H_RECEIPTTO, NULL },
+ { "disposition-notification-to", H_FROM, NULL },
/* destination fields */
{ "to", H_RCPT, NULL },
@@ -131,6 +132,7 @@ struct prival PrivacyValues[] =
{ "needvrfyhelo", PRIV_NEEDVRFYHELO },
{ "noexpn", PRIV_NOEXPN },
{ "novrfy", PRIV_NOVRFY },
+ { "restrictexpand", PRIV_RESTRICTEXPAND },
{ "restrictmailq", PRIV_RESTRICTMAILQ },
{ "restrictqrun", PRIV_RESTRICTQRUN },
{ "noetrn", PRIV_NOETRN },
@@ -145,6 +147,7 @@ struct prival PrivacyValues[] =
/*
** DontBlameSendmail values
*/
+
struct dbsval DontBlameSendmailValues[] =
{
{ "safe", DBS_SAFE },
@@ -194,29 +197,30 @@ struct dbsval DontBlameSendmailValues[] =
{ "dontwarnforwardfileinunsafedirpath",
DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH },
{ "insufficiententropy", DBS_INSUFFICIENTENTROPY },
-#if _FFR_UNSAFE_SASL
- { "groupreadablesaslfile", DBS_GROUPREADABLESASLFILE },
-#endif /* _FFR_UNSAFE_SASL */
-#if _FFR_UNSAFE_WRITABLE_INCLUDE
+ { "groupreadablesasldbfile", DBS_GROUPREADABLESASLDBFILE },
+ { "groupwritablesasldbfile", DBS_GROUPWRITABLESASLDBFILE },
{ "groupwritableforwardfile", DBS_GROUPWRITABLEFORWARDFILE },
{ "groupwritableincludefile", DBS_GROUPWRITABLEINCLUDEFILE },
{ "worldwritableforwardfile", DBS_WORLDWRITABLEFORWARDFILE },
{ "worldwritableincludefile", DBS_WORLDWRITABLEINCLUDEFILE },
-#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */
+ { "groupreadablekeyfile", DBS_GROUPREADABLEKEYFILE },
+#if _FFR_GROUPREADABLEAUTHINFOFILE
+ { "groupreadableadefaultauthinfofile",
+ DBS_GROUPREADABLEAUTHINFOFILE },
+#endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
{ NULL, 0 }
};
-
/*
** Miscellaneous stuff.
*/
int DtableSize = 50; /* max open files; reset in 4.2bsd */
- /*
+/*
** SETDEFAULTS -- set default values
**
-** Because of the way freezing is done, these must be initialized
-** using direct code.
+** Some of these must be initialized using direct code since they
+** depend on run-time values. So let's do all of them this way.
**
** Parameters:
** e -- the default envelope.
@@ -253,12 +257,13 @@ setdefaults(e)
WkClassFact = 1800L; /* option z */
WkTimeFact = 90000L; /* option Z */
QueueFactor = WkRecipFact * 20; /* option q */
+#if _FFR_QUARANTINE
+ QueueMode = QM_NORMAL; /* what queue items to act upon */
+#endif /* _FFR_QUARANTINE */
FileMode = (RealUid != geteuid()) ? 0644 : 0600;
/* option F */
-#if _FFR_QUEUE_FILE_MODE
QueueFileMode = (RealUid != geteuid()) ? 0644 : 0600;
/* option QueueFileMode */
-#endif /* _FFR_QUEUE_FILE_MODE */
if (((pw = sm_getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
((pw = sm_getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
@@ -276,24 +281,30 @@ setdefaults(e)
}
TrustedUid = 0;
if (tTd(37, 4))
- dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
+ sm_dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
DefUser != NULL ? DefUser : "<1:1>",
(int) DefUid, (int) DefGid);
CheckpointInterval = 10; /* option C */
MaxHopCount = 25; /* option h */
set_delivery_mode(SM_FORK, e); /* option d */
e->e_errormode = EM_PRINT; /* option e */
- e->e_queuedir = NOQDIR;
+ e->e_qgrp = NOQGRP;
+ e->e_qdir = NOQDIR;
+ e->e_xfqgrp = NOQGRP;
+ e->e_xfqdir = NOQDIR;
e->e_ctime = curtime();
- SevenBitInput = FALSE; /* option 7 */
+ SevenBitInput = false; /* option 7 */
MaxMciCache = 1; /* option k */
MciCacheTimeout = 5 MINUTES; /* option K */
LogLevel = 9; /* option L */
- inittimeouts(NULL, FALSE); /* option r */
+#if MILTER
+ MilterLogLevel = -1;
+#endif /* MILTER */
+ inittimeouts(NULL, false); /* option r */
PrivacyFlags = PRIV_PUBLIC; /* option p */
- MeToo = TRUE; /* option m */
- SendMIMEErrors = TRUE; /* option f */
- SuperSafe = TRUE; /* option s */
+ MeToo = true; /* option m */
+ SendMIMEErrors = true; /* option f */
+ SuperSafe = SAFE_REALLY; /* option s */
clrbitmap(DontBlameSendmail); /* DontBlameSendmail option */
#if MIME8TO7
MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */
@@ -314,14 +325,20 @@ setdefaults(e)
MaxRuleRecursion = MAXRULERECURSION;
MaxAliasRecursion = 10;
MaxMacroRecursion = 10;
- ColonOkInAddr = TRUE;
- DontLockReadFiles = TRUE;
+ ColonOkInAddr = true;
+ DontLockReadFiles = true;
+ DontProbeInterfaces = DPI_PROBEALL;
DoubleBounceAddr = "postmaster";
MaxHeadersLength = MAXHDRSLEN;
MaxForwardEntries = 0;
+ FastSplit = 1;
#if SASL
AuthMechanisms = newstr(AUTH_MECHANISMS);
+ MaxSLBits = INT_MAX;
#endif /* SASL */
+#if STARTTLS
+ TLS_Srv_Opts = TLS_I_SRV;
+#endif /* STARTTLS */
#ifdef HESIOD_INIT
HesiodContext = NULL;
#endif /* HESIOD_INIT */
@@ -344,10 +361,11 @@ setdefaults(e)
XscriptFileBufferSize = 4096;
for (i = 0; i < MAXRWSETS; i++)
RuleSetNames[i] = NULL;
-#if _FFR_MILTER
+#if MILTER
InputFilters[0] = NULL;
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
setupmaps();
+ setupqueues();
setupmailers();
setupheaders();
}
@@ -365,13 +383,32 @@ setdefuser()
DefUser = defuserbuf;
defpwent = sm_getpwuid(DefUid);
- snprintf(defuserbuf, sizeof defuserbuf, "%s",
- defpwent == NULL ? "nobody" : defpwent->pw_name);
+ (void) sm_strlcpy(defuserbuf,
+ (defpwent == NULL || defpwent->pw_name == NULL)
+ ? "nobody" : defpwent->pw_name,
+ sizeof defuserbuf);
if (tTd(37, 4))
- dprintf("setdefuser: DefUid=%d, DefUser=%s\n",
- (int) DefUid, DefUser);
+ sm_dprintf("setdefuser: DefUid=%d, DefUser=%s\n",
+ (int) DefUid, DefUser);
+}
+/*
+** SETUPQUEUES -- initialize default queues
+**
+** The mqueue QUEUE structure gets filled in after readcf() but
+** we need something to point to now for the mailer setup,
+** which use "mqueue" as default queue.
+*/
+
+static void
+setupqueues()
+{
+ char buf[100];
+
+ MaxRunnersPerQueue = 1;
+ (void) sm_strlcpy(buf, "mqueue, P=/var/spool/mqueue", sizeof buf);
+ makequeue(buf, false);
}
- /*
+/*
** SETUPMAILERS -- initialize default mailers
*/
@@ -380,20 +417,20 @@ setupmailers()
{
char buf[100];
- (void) strlcpy(buf, "prog, P=/bin/sh, F=lsouDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u",
- sizeof buf);
+ (void) sm_strlcpy(buf, "prog, P=/bin/sh, F=lsouDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u",
+ sizeof buf);
makemailer(buf);
- (void) strlcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=X-Unix/X-Unix/X-Unix, A=FILE \201u",
- sizeof buf);
+ (void) sm_strlcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=X-Unix/X-Unix/X-Unix, A=FILE \201u",
+ sizeof buf);
makemailer(buf);
- (void) strlcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u",
- sizeof buf);
+ (void) sm_strlcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u",
+ sizeof buf);
makemailer(buf);
initerrmailers();
}
- /*
+/*
** SETUPMAPS -- set up map classes
*/
@@ -420,7 +457,7 @@ setupmaps()
{
register STAB *s;
-#ifdef NEWDB
+#if NEWDB
MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
map_parseargs, hash_map_open, db_map_close,
db_map_lookup, db_map_store);
@@ -430,37 +467,32 @@ setupmaps()
db_map_lookup, db_map_store);
#endif /* NEWDB */
-#ifdef NDBM
+#if NDBM
MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
map_parseargs, ndbm_map_open, ndbm_map_close,
ndbm_map_lookup, ndbm_map_store);
#endif /* NDBM */
-#ifdef NIS
+#if NIS
MAPDEF("nis", NULL, MCF_ALIASOK,
map_parseargs, nis_map_open, null_map_close,
nis_map_lookup, null_map_store);
#endif /* NIS */
-#ifdef NISPLUS
+#if NISPLUS
MAPDEF("nisplus", NULL, MCF_ALIASOK,
map_parseargs, nisplus_map_open, null_map_close,
nisplus_map_lookup, null_map_store);
#endif /* NISPLUS */
-#ifdef LDAPMAP
- MAPDEF("ldap", NULL, MCF_ALIASOK,
+#if LDAPMAP
+ MAPDEF("ldap", NULL, MCF_ALIASOK|MCF_NOTPERSIST,
ldapmap_parseargs, ldapmap_open, ldapmap_close,
ldapmap_lookup, null_map_store);
-
- /* Deprecated */
- MAPDEF("ldapx", NULL, MCF_ALIASOK,
- ldapx_map_parseargs, ldapmap_open, ldapmap_close,
- ldapmap_lookup, null_map_store);
#endif /* LDAPMAP */
-#ifdef PH_MAP
- MAPDEF("ph", NULL, 0,
+#if PH_MAP
+ MAPDEF("ph", NULL, MCF_NOTPERSIST,
ph_map_parseargs, ph_map_open, ph_map_close,
ph_map_lookup, null_map_store);
#endif /* PH_MAP */
@@ -472,9 +504,9 @@ setupmaps()
nsd_map_lookup, null_map_store);
#endif /* MAP_NSD */
-#ifdef HESIOD
+#if HESIOD
MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
- map_parseargs, hes_map_open, null_map_close,
+ map_parseargs, hes_map_open, hes_map_close,
hes_map_lookup, null_map_store);
#endif /* HESIOD */
@@ -491,6 +523,14 @@ setupmaps()
#endif /* 0 */
#if NAMED_BIND
+# if DNSMAP
+ MAPDEF("dns", NULL, 0,
+ dns_map_parseargs, dns_map_open, null_map_close,
+ dns_map_lookup, null_map_store);
+# endif /* DNSMAP */
+#endif /* NAMED_BIND */
+
+#if NAMED_BIND
/* best MX DNS lookup */
MAPDEF("bestmx", NULL, MCF_OPTFILE,
map_parseargs, null_map_open, null_map_close,
@@ -523,7 +563,7 @@ setupmaps()
dequote_init, null_map_open, null_map_close,
dequote_map, null_map_store);
-#ifdef MAP_REGEX
+#if MAP_REGEX
MAPDEF("regex", NULL, 0,
regex_map_init, null_map_open, null_map_close,
regex_map_lookup, null_map_store);
@@ -581,7 +621,7 @@ setupmaps()
}
#undef MAPDEF
- /*
+/*
** INITHOSTMAPS -- initial host-dependent maps
**
** This should act as an interface to any local service switch
@@ -621,41 +661,41 @@ inithostmaps()
if (strcmp(maptype[i], "files") == 0 &&
stab("hosts.files", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts",
+ (void) sm_strlcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts",
sizeof buf);
(void) makemapentry(buf);
}
# if NAMED_BIND
else if (strcmp(maptype[i], "dns") == 0 &&
- stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
+ stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "hosts.dns dns A", sizeof buf);
+ (void) sm_strlcpy(buf, "hosts.dns dns A", sizeof buf);
(void) makemapentry(buf);
}
# endif /* NAMED_BIND */
-# ifdef NISPLUS
+# if NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
- stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
+ stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "hosts.nisplus nisplus -k name -v address hosts.org_dir",
+ (void) sm_strlcpy(buf, "hosts.nisplus nisplus -k name -v address hosts.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NISPLUS */
-# ifdef NIS
+# if NIS
else if (strcmp(maptype[i], "nis") == 0 &&
- stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
+ stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "hosts.nis nis -k 0 -v 1 hosts.byname",
+ (void) sm_strlcpy(buf, "hosts.nis nis -k 0 -v 1 hosts.byname",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NIS */
# if NETINFO
- else if (strcmp(maptype[i], "netinfo") == 0) &&
- stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
+ else if (strcmp(maptype[i], "netinfo") == 0 &&
+ stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "hosts.netinfo netinfo -v name /machines",
+ (void) sm_strlcpy(buf, "hosts.netinfo netinfo -v name /machines",
sizeof buf);
(void) makemapentry(buf);
}
@@ -670,10 +710,10 @@ inithostmaps()
if (stab("host", ST_MAP, ST_FIND) == NULL)
{
/* user didn't initialize: set up host map */
- (void) strlcpy(buf, "host host", sizeof buf);
+ (void) sm_strlcpy(buf, "host host", sizeof buf);
#if NAMED_BIND
if (ConfigLevel >= 2)
- (void) strlcat(buf, " -a. -D", sizeof buf);
+ (void) sm_strlcat(buf, " -a. -D", sizeof buf);
#endif /* NAMED_BIND */
(void) makemapentry(buf);
}
@@ -688,41 +728,42 @@ inithostmaps()
if (strcmp(maptype[i], "files") == 0 &&
stab("aliases.files", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases.files null", sizeof buf);
+ (void) sm_strlcpy(buf, "aliases.files null",
+ sizeof buf);
(void) makemapentry(buf);
}
-#ifdef NISPLUS
+#if NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
- stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
+ stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion mail_aliases.org_dir",
+ (void) sm_strlcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion mail_aliases.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NISPLUS */
-#ifdef NIS
+#if NIS
else if (strcmp(maptype[i], "nis") == 0 &&
- stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
+ stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases.nis nis mail.aliases",
+ (void) sm_strlcpy(buf, "aliases.nis nis mail.aliases",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NIS */
#if NETINFO
else if (strcmp(maptype[i], "netinfo") == 0 &&
- stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
+ stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases.netinfo netinfo -z, /aliases",
+ (void) sm_strlcpy(buf, "aliases.netinfo netinfo -z, /aliases",
sizeof buf);
(void) makemapentry(buf);
}
#endif /* NETINFO */
-#ifdef HESIOD
+#if HESIOD
else if (strcmp(maptype[i], "hesiod") == 0 &&
- stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
+ stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases.hesiod hesiod aliases",
+ (void) sm_strlcpy(buf, "aliases.hesiod hesiod aliases",
sizeof buf);
(void) makemapentry(buf);
}
@@ -730,7 +771,7 @@ inithostmaps()
}
if (stab("aliases", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "aliases switch aliases", sizeof buf);
+ (void) sm_strlcpy(buf, "aliases switch aliases", sizeof buf);
(void) makemapentry(buf);
}
@@ -745,45 +786,45 @@ inithostmaps()
if (strcmp(maptype[i], "files") == 0 &&
stab("users.files", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd",
+ (void) sm_strlcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd",
sizeof buf);
(void) makemapentry(buf);
}
-# ifdef NISPLUS
+# if NISPLUS
else if (strcmp(maptype[i], "nisplus") == 0 &&
stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "users.nisplus nisplus -m -kname -vhome passwd.org_dir",
+ (void) sm_strlcpy(buf, "users.nisplus nisplus -m -kname -vhome passwd.org_dir",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NISPLUS */
-# ifdef NIS
+# if NIS
else if (strcmp(maptype[i], "nis") == 0 &&
stab("users.nis", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "users.nis nis -m passwd.byname",
+ (void) sm_strlcpy(buf, "users.nis nis -m passwd.byname",
sizeof buf);
(void) makemapentry(buf);
}
# endif /* NIS */
-# ifdef HESIOD
- else if (strcmp(maptype[i], "hesiod") == 0) &&
- stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
+# if HESIOD
+ else if (strcmp(maptype[i], "hesiod") == 0 &&
+ stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "users.hesiod hesiod", sizeof buf);
+ (void) sm_strlcpy(buf, "users.hesiod hesiod", sizeof buf);
(void) makemapentry(buf);
}
# endif /* HESIOD */
}
if (stab("users", ST_MAP, ST_FIND) == NULL)
{
- (void) strlcpy(buf, "users switch -m passwd", sizeof buf);
+ (void) sm_strlcpy(buf, "users switch -m passwd", sizeof buf);
(void) makemapentry(buf);
}
#endif /* 0 */
}
- /*
+/*
** SWITCH_MAP_FIND -- find the list of types associated with a map
**
** This is the system-dependent interface to the service switch.
@@ -807,6 +848,12 @@ inithostmaps()
# define _USE_SUN_NSSWITCH_
#endif /* defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) */
+#if _FFR_HPUX_NSSWITCH
+# ifdef __hpux
+# define _USE_SUN_NSSWITCH_
+# endif /* __hpux */
+#endif /* _FFR_HPUX_NSSWITCH */
+
#ifdef _USE_SUN_NSSWITCH_
# include <nsswitch.h>
#endif /* _USE_SUN_NSSWITCH_ */
@@ -919,15 +966,16 @@ switch_map_find(service, maptype, mapreturn)
*/
STAB *st;
+ static time_t servicecachetime; /* time service switch was cached */
time_t now = curtime();
for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
mapreturn[svcno] = 0;
- if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge)
+ if ((now - servicecachetime) > (time_t) ServiceCacheMaxAge)
{
/* (re)read service switch */
- register FILE *fp;
+ register SM_FILE_T *fp;
long sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
if (!bitnset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR,
@@ -935,13 +983,14 @@ switch_map_find(service, maptype, mapreturn)
sff |= SFF_NOWLINK;
if (ConfigFileRead)
- ServiceCacheTime = now;
+ servicecachetime = now;
fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
if (fp != NULL)
{
char buf[MAXLINE];
- while (fgets(buf, sizeof buf, fp) != NULL)
+ while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf,
+ sizeof buf) != NULL)
{
register char *p;
@@ -976,7 +1025,7 @@ switch_map_find(service, maptype, mapreturn)
st = stab(buf, ST_SERVICE, ST_ENTER);
if (st->s_service[0] != NULL)
- sm_free((void *) st->s_service[0]);
+ sm_free((void *) st->s_service[0]); /* XXX */
p = newstr(p);
for (svcno = 0; svcno < MAXMAPSTACK; )
{
@@ -993,7 +1042,7 @@ switch_map_find(service, maptype, mapreturn)
if (svcno < MAXMAPSTACK)
st->s_service[svcno] = NULL;
}
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
}
}
@@ -1029,10 +1078,10 @@ switch_map_find(service, maptype, mapreturn)
maptype[svcno++] = "netinfo";
# endif /* defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) */
# ifdef AUTO_NIS_ALIASES
-# ifdef NISPLUS
+# if NISPLUS
maptype[svcno++] = "nisplus";
# endif /* NISPLUS */
-# ifdef NIS
+# if NIS
maptype[svcno++] = "nis";
# endif /* NIS */
# endif /* AUTO_NIS_ALIASES */
@@ -1060,7 +1109,7 @@ switch_map_find(service, maptype, mapreturn)
return -1;
#endif /* !defined(_USE_SUN_NSSWITCH_) */
}
- /*
+/*
** USERNAME -- return the user id of the logged in user.
**
** Parameters:
@@ -1091,19 +1140,18 @@ username()
{
pw = sm_getpwuid(RealUid);
if (pw != NULL)
- myname = newstr(pw->pw_name);
+ myname = pw->pw_name;
}
else
{
uid_t uid = RealUid;
- myname = newstr(myname);
if ((pw = sm_getpwnam(myname)) == NULL ||
(uid != 0 && uid != pw->pw_uid))
{
pw = sm_getpwuid(uid);
if (pw != NULL)
- myname = newstr(pw->pw_name);
+ myname = pw->pw_name;
}
}
if (myname == NULL || myname[0] == '\0')
@@ -1111,11 +1159,14 @@ username()
syserr("554 5.3.0 Who are you?");
myname = "postmaster";
}
+ else if (strpbrk(myname, ",;:/|\"\\") != NULL)
+ myname = addquotes(myname, NULL);
+ else
+ myname = sm_pstrdup_x(myname);
}
-
return myname;
}
- /*
+/*
** TTYPATH -- Get the path of the user's tty
**
** Returns the pathname of the user's tty. Returns NULL if
@@ -1169,7 +1220,7 @@ ttypath()
/* looks good */
return pathn;
}
- /*
+/*
** CHECKCOMPAT -- check for From and To person compatible.
**
** This routine can be supplied on a per-installation basis
@@ -1203,7 +1254,7 @@ checkcompat(to, e)
register ENVELOPE *e;
{
if (tTd(49, 1))
- dprintf("checkcompat(to=%s, from=%s)\n",
+ sm_dprintf("checkcompat(to=%s, from=%s)\n",
to->q_paddr, e->e_from.q_paddr);
#ifdef EXAMPLE_CODE
@@ -1222,255 +1273,7 @@ checkcompat(to, e)
#endif /* EXAMPLE_CODE */
return EX_OK;
}
- /*
-** SETSIGNAL -- set a signal handler
-**
-** This is essentially old BSD "signal(3)".
-**
-** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
-** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
-** DOING.
-*/
-
-sigfunc_t
-setsignal(sig, handler)
- int sig;
- sigfunc_t handler;
-{
-# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
- struct sigaction n, o;
-# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
-
- /*
- ** First, try for modern signal calls
- ** and restartable syscalls
- */
-
-# ifdef SA_RESTART
- memset(&n, '\0', sizeof n);
-# if USE_SA_SIGACTION
- n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
- n.sa_flags = SA_RESTART|SA_SIGINFO;
-# else /* USE_SA_SIGACTION */
- n.sa_handler = handler;
- n.sa_flags = SA_RESTART;
-# endif /* USE_SA_SIGACTION */
- if (sigaction(sig, &n, &o) < 0)
- return SIG_ERR;
- return o.sa_handler;
-# else /* SA_RESTART */
-
- /*
- ** Else check for SYS5SIGNALS or
- ** BSD4_3 signals
- */
-
-# if defined(SYS5SIGNALS) || defined(BSD4_3)
-# ifdef BSD4_3
- return signal(sig, handler);
-# else /* BSD4_3 */
- return sigset(sig, handler);
-# endif /* BSD4_3 */
-# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
-
- /*
- ** Finally, if nothing else is available,
- ** go for a default
- */
-
- memset(&n, '\0', sizeof n);
- n.sa_handler = handler;
- if (sigaction(sig, &n, &o) < 0)
- return SIG_ERR;
- return o.sa_handler;
-# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
-# endif /* SA_RESTART */
-}
- /*
-** ALLSIGNALS -- act on all signals
-**
-** Parameters:
-** block -- whether to block or release all signals.
-**
-** Returns:
-** none.
-*/
-
-void
-allsignals(block)
- bool block;
-{
-# ifdef BSD4_3
-# ifndef sigmask
-# define sigmask(s) (1 << ((s) - 1))
-# endif /* ! sigmask */
- if (block)
- {
- int mask = 0;
-
- mask |= sigmask(SIGALRM);
- mask |= sigmask(SIGCHLD);
- mask |= sigmask(SIGHUP);
- mask |= sigmask(SIGINT);
- mask |= sigmask(SIGTERM);
- mask |= sigmask(SIGUSR1);
-
- (void) sigblock(mask);
- }
- else
- sigsetmask(0);
-# else /* BSD4_3 */
-# ifdef ALTOS_SYSTEM_V
- if (block)
- {
- (void) sigset(SIGALRM, SIG_HOLD);
- (void) sigset(SIGCHLD, SIG_HOLD);
- (void) sigset(SIGHUP, SIG_HOLD);
- (void) sigset(SIGINT, SIG_HOLD);
- (void) sigset(SIGTERM, SIG_HOLD);
- (void) sigset(SIGUSR1, SIG_HOLD);
- }
- else
- {
- (void) sigset(SIGALRM, SIG_DFL);
- (void) sigset(SIGCHLD, SIG_DFL);
- (void) sigset(SIGHUP, SIG_DFL);
- (void) sigset(SIGINT, SIG_DFL);
- (void) sigset(SIGTERM, SIG_DFL);
- (void) sigset(SIGUSR1, SIG_DFL);
- }
-# else /* ALTOS_SYSTEM_V */
- sigset_t sset;
-
- (void) sigemptyset(&sset);
- (void) sigaddset(&sset, SIGALRM);
- (void) sigaddset(&sset, SIGCHLD);
- (void) sigaddset(&sset, SIGHUP);
- (void) sigaddset(&sset, SIGINT);
- (void) sigaddset(&sset, SIGTERM);
- (void) sigaddset(&sset, SIGUSR1);
- (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
-# endif /* ALTOS_SYSTEM_V */
-# endif /* BSD4_3 */
-}
- /*
-** BLOCKSIGNAL -- hold a signal to prevent delivery
-**
-** Parameters:
-** sig -- the signal to block.
-**
-** Returns:
-** 1 signal was previously blocked
-** 0 signal was not previously blocked
-** -1 on failure.
-*/
-
-int
-blocksignal(sig)
- int sig;
-{
-# ifdef BSD4_3
-# ifndef sigmask
-# define sigmask(s) (1 << ((s) - 1))
-# endif /* ! sigmask */
- return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
-# else /* BSD4_3 */
-# ifdef ALTOS_SYSTEM_V
- sigfunc_t handler;
-
- handler = sigset(sig, SIG_HOLD);
- if (handler == SIG_ERR)
- return -1;
- else
- return handler == SIG_HOLD;
-# else /* ALTOS_SYSTEM_V */
- sigset_t sset, oset;
-
- (void) sigemptyset(&sset);
- (void) sigaddset(&sset, sig);
- if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
- return -1;
- else
- return sigismember(&oset, sig);
-# endif /* ALTOS_SYSTEM_V */
-# endif /* BSD4_3 */
-}
- /*
-** RELEASESIGNAL -- release a held signal
-**
-** Parameters:
-** sig -- the signal to release.
-**
-** Returns:
-** 1 signal was previously blocked
-** 0 signal was not previously blocked
-** -1 on failure.
-*/
-
-int
-releasesignal(sig)
- int sig;
-{
-# ifdef BSD4_3
- return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
-# else /* BSD4_3 */
-# ifdef ALTOS_SYSTEM_V
- sigfunc_t handler;
-
- handler = sigset(sig, SIG_HOLD);
- if (sigrelse(sig) < 0)
- return -1;
- else
- return handler == SIG_HOLD;
-# else /* ALTOS_SYSTEM_V */
- sigset_t sset, oset;
-
- (void) sigemptyset(&sset);
- (void) sigaddset(&sset, sig);
- if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
- return -1;
- else
- return sigismember(&oset, sig);
-# endif /* ALTOS_SYSTEM_V */
-# endif /* BSD4_3 */
-}
- /*
-** HOLDSIGS -- arrange to hold all signals
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Arranges that signals are held.
-*/
-
-void
-holdsigs()
-{
-}
- /*
-** RLSESIGS -- arrange to release all signals
-**
-** This undoes the effect of holdsigs.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Arranges that signals are released.
-*/
-
-void
-rlsesigs()
-{
-}
- /*
+/*
** INIT_MD -- do machine dependent initializations
**
** Systems that have global modes that should be set should do
@@ -1533,7 +1336,7 @@ init_md(argc, argv)
VendorCode = VENDOR_BERKELEY;
#endif /* VENDOR_DEFAULT */
}
- /*
+/*
** INIT_VENDOR_MACROS -- vendor-dependent macro initializations
**
** Called once, on startup.
@@ -1553,7 +1356,7 @@ init_vendor_macros(e)
register ENVELOPE *e;
{
}
- /*
+/*
** GETLA -- get the current load average
**
** This code stolen from la.c.
@@ -1646,9 +1449,10 @@ struct nlist Nl[] =
# endif /* _AUX_SOURCE */
# define X_AVENRUN 0
-static int
+int
getla()
{
+ int j;
static int kmem = -1;
# if LA_TYPE == LA_INT
long avenrun[3];
@@ -1665,7 +1469,7 @@ getla()
if (kmem < 0)
{
# ifdef _AUX_SOURCE
- (void) strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN,
+ (void) sm_strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN,
sizeof Nl[X_AVENRUN].n_name);
Nl[1].n_name[0] = '\0';
# endif /* _AUX_SOURCE */
@@ -1677,14 +1481,14 @@ getla()
# endif /* defined(_AIX3) || defined(_AIX4) */
{
if (tTd(3, 1))
- dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
- errstring(errno));
+ sm_dprintf("getla: nlist(%s): %s\n", _PATH_UNIX,
+ sm_errstring(errno));
return -1;
}
if (Nl[X_AVENRUN].n_value == 0)
{
if (tTd(3, 1))
- dprintf("getla: nlist(%s, %s) ==> 0\n",
+ sm_dprintf("getla: nlist(%s, %s) ==> 0\n",
_PATH_UNIX, LA_AVENRUN);
return -1;
}
@@ -1696,52 +1500,61 @@ getla()
if (kmem < 0)
{
if (tTd(3, 1))
- dprintf("getla: open(/dev/kmem): %s\n",
- errstring(errno));
+ sm_dprintf("getla: open(/dev/kmem): %s\n",
+ sm_errstring(errno));
+ return -1;
+ }
+ if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
+ fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
+ {
+ if (tTd(3, 1))
+ sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
+ sm_errstring(errno));
+ (void) close(kmem);
+ kmem = -1;
return -1;
}
- (void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
if (tTd(3, 20))
- dprintf("getla: symbol address = %#lx\n",
- (u_long) Nl[X_AVENRUN].n_value);
+ sm_dprintf("getla: symbol address = %#lx\n",
+ (unsigned long) Nl[X_AVENRUN].n_value);
if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
{
/* thank you Ian */
if (tTd(3, 1))
- dprintf("getla: lseek or read: %s\n",
- errstring(errno));
+ sm_dprintf("getla: lseek or read: %s\n",
+ sm_errstring(errno));
return -1;
}
# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
if (tTd(3, 5))
{
# if LA_TYPE == LA_SHORT
- dprintf("getla: avenrun = %d", avenrun[0]);
+ sm_dprintf("getla: avenrun = %d", avenrun[0]);
if (tTd(3, 15))
- dprintf(", %d, %d", avenrun[1], avenrun[2]);
+ sm_dprintf(", %d, %d", avenrun[1], avenrun[2]);
# else /* LA_TYPE == LA_SHORT */
- dprintf("getla: avenrun = %ld", avenrun[0]);
+ sm_dprintf("getla: avenrun = %ld", avenrun[0]);
if (tTd(3, 15))
- dprintf(", %ld, %ld", avenrun[1], avenrun[2]);
+ sm_dprintf(", %ld, %ld", avenrun[1], avenrun[2]);
# endif /* LA_TYPE == LA_SHORT */
- dprintf("\n");
+ sm_dprintf("\n");
}
if (tTd(3, 1))
- dprintf("getla: %d\n",
+ sm_dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
# else /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
if (tTd(3, 5))
{
- dprintf("getla: avenrun = %g", avenrun[0]);
+ sm_dprintf("getla: avenrun = %g", avenrun[0]);
if (tTd(3, 15))
- dprintf(", %g, %g", avenrun[1], avenrun[2]);
- dprintf("\n");
+ sm_dprintf(", %g, %g", avenrun[1], avenrun[2]);
+ sm_dprintf("\n");
}
if (tTd(3, 1))
- dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
+ sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
return ((int) (avenrun[0] + 0.5));
# endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */
}
@@ -1752,9 +1565,10 @@ getla()
# include <sys/ksym.h>
-static int
+int
getla()
{
+ int j;
static int kmem = -1;
long avenrun[3];
extern int errno;
@@ -1766,11 +1580,20 @@ getla()
if (kmem < 0)
{
if (tTd(3, 1))
- dprintf("getla: open(/dev/kmem): %s\n",
- errstring(errno));
+ sm_dprintf("getla: open(/dev/kmem): %s\n",
+ sm_errstring(errno));
+ return -1;
+ }
+ if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
+ fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
+ {
+ if (tTd(3, 1))
+ sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
+ sm_errstring(errno));
+ (void) close(kmem);
+ kmem = -1;
return -1;
}
- (void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
mirk.mirk_symname = LA_AVENRUN;
mirk.mirk_buf = avenrun;
@@ -1778,19 +1601,19 @@ getla()
if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
{
if (tTd(3, 1))
- dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
- errstring(errno));
+ sm_dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
+ sm_errstring(errno));
return -1;
}
if (tTd(3, 5))
{
- dprintf("getla: avenrun = %d", avenrun[0]);
+ sm_dprintf("getla: avenrun = %d", avenrun[0]);
if (tTd(3, 15))
- dprintf(", %d, %d", avenrun[1], avenrun[2]);
- dprintf("\n");
+ sm_dprintf(", %d, %d", avenrun[1], avenrun[2]);
+ sm_dprintf("\n");
}
if (tTd(3, 1))
- dprintf("getla: %d\n",
+ sm_dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
}
@@ -1801,7 +1624,7 @@ getla()
# include <sys/dg_sys_info.h>
-static int
+int
getla()
{
struct dg_sys_info_load_info load_info;
@@ -1810,7 +1633,7 @@ getla()
DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
if (tTd(3, 1))
- dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5));
+ sm_dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5));
return ((int) (load_info.one_minute + 0.5));
}
@@ -1832,7 +1655,7 @@ struct pst_swapinfo;
# include <sys/param.h>
# include <sys/pstat.h>
-static int
+int
getla()
{
struct pst_dynamic pstd;
@@ -1842,7 +1665,7 @@ getla()
return 0;
if (tTd(3, 1))
- dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
+ sm_dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
return (int) (pstd.psd_avg_1_min + 0.5);
}
@@ -1851,7 +1674,7 @@ getla()
#if LA_TYPE == LA_SUBR
-static int
+int
getla()
{
double avenrun[3];
@@ -1859,12 +1682,12 @@ getla()
if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
{
if (tTd(3, 1))
- dprintf("getla: getloadavg failed: %s",
- errstring(errno));
+ sm_dprintf("getla: getloadavg failed: %s",
+ sm_errstring(errno));
return -1;
}
if (tTd(3, 1))
- dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
+ sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
return ((int) (avenrun[0] + 0.5));
}
@@ -1882,7 +1705,7 @@ getla()
# include <mach.h>
# endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */
-static int
+int
getla()
{
processor_set_t default_set;
@@ -1895,8 +1718,8 @@ getla()
if (error != KERN_SUCCESS)
{
if (tTd(3, 1))
- dprintf("getla: processor_set_default failed: %s",
- errstring(errno));
+ sm_dprintf("getla: processor_set_default failed: %s",
+ sm_errstring(errno));
return -1;
}
info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
@@ -1905,12 +1728,12 @@ getla()
&info_count) != KERN_SUCCESS)
{
if (tTd(3, 1))
- dprintf("getla: processor_set_info failed: %s",
- errstring(errno));
+ sm_dprintf("getla: processor_set_info failed: %s",
+ sm_errstring(errno));
return -1;
}
if (tTd(3, 1))
- dprintf("getla: %d\n",
+ sm_dprintf("getla: %d\n",
(int) ((info.load_average + (LOAD_SCALE / 2)) /
LOAD_SCALE));
return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
@@ -1919,6 +1742,12 @@ getla()
#endif /* LA_TYPE == LA_MACH */
#if LA_TYPE == LA_PROCSTR
+# if SM_CONF_BROKEN_STRTOD
+ ERROR: This OS has most likely a broken strtod() implemenentation.
+ ERROR: The function is required for getla().
+ ERROR: Check the compilation options _LA_PROCSTR and
+ ERROR: _SM_CONF_BROKEN_STRTOD (without the leading _).
+# endif /* SM_CONF_BROKEN_STRTOD */
/*
** Read /proc/loadavg for the load average. This is assumed to be
@@ -1932,33 +1761,34 @@ getla()
# define _PATH_LOADAVG "/proc/loadavg"
# endif /* ! _PATH_LOADAVG */
-static int
+int
getla()
{
double avenrun;
register int result;
- FILE *fp;
+ SM_FILE_T *fp;
- fp = fopen(_PATH_LOADAVG, "r");
+ fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_LOADAVG, SM_IO_RDONLY,
+ NULL);
if (fp == NULL)
{
if (tTd(3, 1))
- dprintf("getla: fopen(%s): %s\n",
- _PATH_LOADAVG, errstring(errno));
+ sm_dprintf("getla: sm_io_open(%s): %s\n",
+ _PATH_LOADAVG, sm_errstring(errno));
return -1;
}
- result = fscanf(fp, "%lf", &avenrun);
- (void) fclose(fp);
+ result = sm_io_fscanf(fp, SM_TIME_DEFAULT, "%lf", &avenrun);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
if (result != 1)
{
if (tTd(3, 1))
- dprintf("getla: fscanf() = %d: %s\n",
- result, errstring(errno));
+ sm_dprintf("getla: sm_io_fscanf() = %d: %s\n",
+ result, sm_errstring(errno));
return -1;
}
if (tTd(3, 1))
- dprintf("getla(): %.2f\n", avenrun);
+ sm_dprintf("getla(): %.2f\n", avenrun);
return ((int) (avenrun + 0.5));
}
@@ -1969,8 +1799,10 @@ getla()
# include <sys/sysmp.h>
-int getla(void)
+int
+getla(void)
{
+ int j;
static int kmem = -1;
int avenrun[3];
@@ -1980,32 +1812,41 @@ int getla(void)
if (kmem < 0)
{
if (tTd(3, 1))
- dprintf("getla: open(%s): %s\n", _PATH_KMEM,
- errstring(errno));
+ sm_dprintf("getla: open(%s): %s\n", _PATH_KMEM,
+ sm_errstring(errno));
+ return -1;
+ }
+ if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
+ fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
+ {
+ if (tTd(3, 1))
+ sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n",
+ sm_errstring(errno));
+ (void) close(kmem);
+ kmem = -1;
return -1;
}
- (void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
}
if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
- read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
+ read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
{
if (tTd(3, 1))
- dprintf("getla: lseek or read: %s\n",
- errstring(errno));
+ sm_dprintf("getla: lseek or read: %s\n",
+ sm_errstring(errno));
return -1;
}
if (tTd(3, 5))
{
- dprintf("getla: avenrun = %ld", (long int) avenrun[0]);
+ sm_dprintf("getla: avenrun = %ld", (long int) avenrun[0]);
if (tTd(3, 15))
- dprintf(", %ld, %ld",
+ sm_dprintf(", %ld, %ld",
(long int) avenrun[1], (long int) avenrun[2]);
- dprintf("\n");
+ sm_dprintf("\n");
}
if (tTd(3, 1))
- dprintf("getla: %d\n",
+ sm_dprintf("getla: %d\n",
(int) (avenrun[0] + FSCALE/2) >> FSHIFT);
return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
@@ -2016,7 +1857,7 @@ int getla(void)
# include <kstat.h>
-static int
+int
getla()
{
static kstat_ctl_t *kc = NULL;
@@ -2029,8 +1870,8 @@ getla()
if (kc == NULL)
{
if (tTd(3, 1))
- dprintf("getla: kstat_open(): %s\n",
- errstring(errno));
+ sm_dprintf("getla: kstat_open(): %s\n",
+ sm_errstring(errno));
return -1;
}
if (ksp == NULL)
@@ -2038,19 +1879,19 @@ getla()
if (ksp == NULL)
{
if (tTd(3, 1))
- dprintf("getla: kstat_lookup(): %s\n",
- errstring(errno));
+ sm_dprintf("getla: kstat_lookup(): %s\n",
+ sm_errstring(errno));
return -1;
}
if (kstat_read(kc, ksp, NULL) < 0)
{
if (tTd(3, 1))
- dprintf("getla: kstat_read(): %s\n",
- errstring(errno));
+ sm_dprintf("getla: kstat_read(): %s\n",
+ sm_errstring(errno));
return -1;
}
ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
- la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
+ la = ((double) ksn->value.ul + FSCALE/2) / FSCALE;
/* kstat_close(kc); /o do not close for fast access */
return la;
}
@@ -2071,7 +1912,7 @@ getla()
# define _PATH_AVENRUN "/dev/table/avenrun"
# endif /* ! _PATH_AVENRUN */
-static int
+int
getla()
{
static int afd = -1;
@@ -2089,8 +1930,8 @@ getla()
if (afd < 0)
{
sm_syslog(LOG_ERR, NOQID,
- "can't open %s: %m",
- _PATH_AVENRUN);
+ "can't open %s: %s",
+ _PATH_AVENRUN, sm_errstring(errno));
return -1;
}
}
@@ -2098,10 +1939,10 @@ getla()
r = read(afd, &avenrun, sizeof avenrun);
if (tTd(3, 5))
- dprintf("getla: avenrun = %d\n", avenrun);
+ sm_dprintf("getla: avenrun = %d\n", avenrun);
loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
if (tTd(3, 1))
- dprintf("getla: %d\n", loadav);
+ sm_dprintf("getla: %d\n", loadav);
return loadav;
}
@@ -2112,7 +1953,8 @@ struct rtentry;
struct mbuf;
# include <sys/table.h>
-int getla()
+int
+getla()
{
int ave = 0;
struct tbl_loadavg tab;
@@ -2120,12 +1962,12 @@ int getla()
if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
{
if (tTd(3, 1))
- dprintf("getla: table %s\n", errstring(errno));
+ sm_dprintf("getla: table %s\n", sm_errstring(errno));
return -1;
}
if (tTd(3, 1))
- dprintf("getla: scale = %d\n", tab.tl_lscale);
+ sm_dprintf("getla: scale = %d\n", tab.tl_lscale);
if (tab.tl_lscale)
ave = ((tab.tl_avenrun.l[2] + (tab.tl_lscale/2)) /
@@ -2134,7 +1976,7 @@ int getla()
ave = (int) (tab.tl_avenrun.d[2] + 0.5);
if (tTd(3, 1))
- dprintf("getla: %d\n", ave);
+ sm_dprintf("getla: %d\n", ave);
return ave;
}
@@ -2143,7 +1985,7 @@ int getla()
#if LA_TYPE == LA_PSET
-static int
+int
getla()
{
double avenrun[3];
@@ -2152,12 +1994,12 @@ getla()
sizeof(avenrun) / sizeof(avenrun[0])) < 0)
{
if (tTd(3, 1))
- dprintf("getla: pset_getloadavg failed: %s",
- errstring(errno));
+ sm_dprintf("getla: pset_getloadavg failed: %s",
+ sm_errstring(errno));
return -1;
}
if (tTd(3, 1))
- dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
+ sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5));
return ((int) (avenrun[0] + 0.5));
}
@@ -2165,11 +2007,11 @@ getla()
#if LA_TYPE == LA_ZERO
-static int
+int
getla()
{
if (tTd(3, 1))
- dprintf("getla: ZERO\n");
+ sm_dprintf("getla: ZERO\n");
return 0;
}
@@ -2200,7 +2042,7 @@ getla()
/* Non Apollo stuff removed by Don Lewis 11/15/93 */
#ifndef lint
-static char rcsid[] = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
+SM_UNUSED(static char rcsid[]) = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
#endif /* ! lint */
#ifdef apollo
@@ -2209,61 +2051,57 @@ static char rcsid[] = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 pau
/* ARGSUSED */
int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
+ caddr_t call_data; /* pointer to (double) return value */
{
- double *avenrun = (double *) call_data;
- int i;
- status_$t st;
- long loadav[3];
- proc1_$get_loadav(loadav, &st);
- *avenrun = loadav[0] / (double) (1 << 16);
- return 0;
+ double *avenrun = (double *) call_data;
+ int i;
+ status_$t st;
+ long loadav[3];
+
+ proc1_$get_loadav(loadav, &st);
+ *avenrun = loadav[0] / (double) (1 << 16);
+ return 0;
}
#endif /* apollo */
- /*
-** SM_GETLA -- get the current load average and set macro
+/*
+** SM_GETLA -- get the current load average
**
** Parameters:
-** e -- the envelope for the load average macro.
+** none
**
** Returns:
-** The current load average as an integer.
+** none
**
** Side Effects:
-** Sets the load average macro ({load_avg}) if
-** envelope e is not NULL.
+** Set CurrentLA to the current load average.
+** Set {load_avg} in GlobalMacros to the current load average.
*/
-int
-sm_getla(e)
- ENVELOPE *e;
+void
+sm_getla()
{
- register int la;
-
- la = getla();
- if (e != NULL)
- {
- char labuf[8];
+ char labuf[8];
- snprintf(labuf, sizeof labuf, "%d", la);
- define(macid("{load_avg}", NULL), newstr(labuf), e);
- }
- return la;
+ CurrentLA = getla();
+ (void) sm_snprintf(labuf, sizeof labuf, "%d", CurrentLA);
+ macdefine(&GlobalMacros, A_TEMP, macid("{load_avg}"), labuf);
}
-
- /*
+/*
** SHOULDQUEUE -- should this message be queued or sent?
**
** Compares the message cost to the load average to decide.
**
+** Note: Do NOT change this API! It is documented in op.me
+** and theoretically the user can change this function...
+**
** Parameters:
** pri -- the priority of the message in question.
-** ct -- the message creation time.
+** ct -- the message creation time (unused, but see above).
**
** Returns:
-** TRUE -- if this message should be queued up for the
+** true -- if this message should be queued up for the
** time being.
-** FALSE -- if the load is low enough to send this message.
+** false -- if the load is low enough to send this message.
**
** Side Effects:
** none.
@@ -2278,65 +2116,114 @@ shouldqueue(pri, ct)
bool rval;
if (tTd(3, 30))
- dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
+ sm_dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ",
CurrentLA, pri);
if (CurrentLA < QueueLA)
{
if (tTd(3, 30))
- dprintf("FALSE (CurrentLA < QueueLA)\n");
- return FALSE;
+ sm_dprintf("false (CurrentLA < QueueLA)\n");
+ return false;
}
-#if 0 /* this code is reported to cause oscillation around RefuseLA */
+# if 0 /* this code is reported to cause oscillation around RefuseLA */
if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
{
if (tTd(3, 30))
- dprintf("TRUE (CurrentLA >= RefuseLA)\n");
- return TRUE;
+ sm_dprintf("TRUE (CurrentLA >= RefuseLA)\n");
+ return true;
}
-#endif /* 0 */
+# endif /* 0 */
rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1));
if (tTd(3, 30))
- dprintf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
+ sm_dprintf("%s (by calculation)\n", rval ? "true" : "false");
return rval;
}
- /*
+/*
** REFUSECONNECTIONS -- decide if connections should be refused
**
** Parameters:
** name -- daemon name (for error messages only)
** e -- the current envelope.
** d -- number of daemon
+** active -- was this daemon actually active?
**
** Returns:
-** TRUE if incoming SMTP connections should be refused
+** true if incoming SMTP connections should be refused
** (for now).
-** FALSE if we should accept new work.
+** false if we should accept new work.
**
** Side Effects:
** Sets process title when it is rejecting connections.
*/
bool
-refuseconnections(name, e, d)
+refuseconnections(name, e, d, active)
char *name;
ENVELOPE *e;
int d;
+ bool active;
{
-#ifdef XLA
+ static time_t lastconn[MAXDAEMONS];
+ static int conncnt[MAXDAEMONS];
+
+#if XLA
if (!xla_smtp_ok())
- return TRUE;
+ return true;
#endif /* XLA */
- CurrentLA = sm_getla(NULL);
+ if (ConnRateThrottle > 0)
+ {
+ time_t now;
+
+ now = curtime();
+ if (active)
+ {
+ if (now != lastconn[d])
+ {
+ lastconn[d] = now;
+ conncnt[d] = 1;
+ }
+ else if (conncnt[d]++ > ConnRateThrottle)
+ {
+#define D_MSG_CRT "deferring connections on daemon %s: %d per second"
+ /* sleep to flatten out connection load */
+ sm_setproctitle(true, e, D_MSG_CRT,
+ name, ConnRateThrottle);
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID, D_MSG_CRT,
+ name, ConnRateThrottle);
+ (void) sleep(1);
+ }
+ }
+ else if (now != lastconn[d])
+ conncnt[d] = 0;
+ }
+
+ sm_getla();
if (RefuseLA > 0 && CurrentLA >= RefuseLA)
{
- sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: load average: %d",
- name, CurrentLA);
- if (LogLevel >= 9)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting connections on daemon %s: load average: %d",
- name, CurrentLA);
- return TRUE;
+# define R_MSG_LA "rejecting connections on daemon %s: load average: %d"
+ sm_setproctitle(true, e, R_MSG_LA, name, CurrentLA);
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID, R_MSG_LA, name, CurrentLA);
+ return true;
+ }
+
+ if (DelayLA > 0 && CurrentLA >= DelayLA)
+ {
+ time_t now;
+ static time_t log_delay = (time_t) 0;
+
+# define MIN_DELAY_LOG 90 /* wait before logging this again */
+# define D_MSG_LA "delaying connections on daemon %s: load average=%d >= %d"
+ /* sleep to flatten out connection load */
+ sm_setproctitle(true, e, D_MSG_LA, name, DelayLA);
+ if (LogLevel > 8 && (now = curtime()) > log_delay)
+ {
+ sm_syslog(LOG_INFO, NOQID, D_MSG_LA,
+ name, CurrentLA, DelayLA);
+ log_delay = now + MIN_DELAY_LOG;
+ }
+ (void) sleep(1);
}
if (MaxChildren > 0 && CurChildren >= MaxChildren)
@@ -2344,19 +2231,18 @@ refuseconnections(name, e, d)
proc_list_probe();
if (CurChildren >= MaxChildren)
{
- sm_setproctitle(TRUE, e, "rejecting connections on daemon %s: %d children, max %d",
+#define R_MSG_CHILD "rejecting connections on daemon %s: %d children, max %d"
+ sm_setproctitle(true, e, R_MSG_CHILD,
name, CurChildren, MaxChildren);
- if (LogLevel >= 9)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting connections on daemon %s: %d children, max %d",
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID, R_MSG_CHILD,
name, CurChildren, MaxChildren);
- return TRUE;
+ return true;
}
}
-
- return FALSE;
+ return false;
}
- /*
+/*
** SETPROCTITLE -- set process title for ps
**
** Parameters:
@@ -2452,7 +2338,7 @@ initsetproctitle(argc, argv, envp)
char **argv;
char **envp;
{
- register int i, envpsize = 0;
+ register int i;
extern char **environ;
/*
@@ -2461,7 +2347,7 @@ initsetproctitle(argc, argv, envp)
*/
for (i = 0; envp[i] != NULL; i++)
- envpsize += strlen(envp[i]) + 1;
+ continue;
environ = (char **) xalloc(sizeof (char *) * (i + 1));
for (i = 0; envp[i] != NULL; i++)
environ[i] = newstr(envp[i]);
@@ -2505,11 +2391,12 @@ setproctitle(fmt, va_alist)
register int i;
register char *p;
SETPROC_STATIC char buf[SPT_BUFSIZE];
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
# if SPT_TYPE == SPT_PSTAT
union pstun pst;
# endif /* SPT_TYPE == SPT_PSTAT */
# if SPT_TYPE == SPT_SCO
+ int j;
off_t seek_off;
static int kmem = -1;
static pid_t kmempid = -1;
@@ -2519,15 +2406,17 @@ setproctitle(fmt, va_alist)
p = buf;
/* print sendmail: heading for grep */
- (void) strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
+ (void) sm_strlcpy(p, "sendmail: ", SPACELEFT(buf, p));
p += strlen(p);
/* print the argument string */
- VA_START(fmt);
- (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
- VA_END;
+ SM_VA_START(ap, fmt);
+ (void) sm_vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
+ SM_VA_END(ap);
- i = strlen(buf);
+ i = (int) strlen(buf);
+ if (i < 0)
+ return;
# if SPT_TYPE == SPT_PSTAT
pst.pst_command = buf;
@@ -2541,15 +2430,21 @@ setproctitle(fmt, va_alist)
sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
# endif /* SPT_TYPE == SPT_SYSMIPS */
# if SPT_TYPE == SPT_SCO
- if (kmem < 0 || kmempid != getpid())
+ if (kmem < 0 || kmempid != CurrentPid)
{
if (kmem >= 0)
(void) close(kmem);
kmem = open(_PATH_KMEM, O_RDWR, 0);
if (kmem < 0)
return;
- (void) fcntl(kmem, F_SETFD, FD_CLOEXEC);
- kmempid = getpid();
+ if ((j = fcntl(kmem, F_GETFD, 0)) < 0 ||
+ fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0)
+ {
+ (void) close(kmem);
+ kmem = -1;
+ return;
+ }
+ kmempid = CurrentPid;
}
buf[PSARGSZ - 1] = '\0';
seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
@@ -2565,7 +2460,7 @@ setproctitle(fmt, va_alist)
i = LastArgv - Argv[0] - 2;
buf[i] = '\0';
}
- (void) strlcpy(Argv[0], buf, i + 1);
+ (void) sm_strlcpy(Argv[0], buf, i + 1);
p = &Argv[0][i];
while (p < LastArgv)
*p++ = SPT_PADCHAR;
@@ -2579,7 +2474,7 @@ setproctitle(fmt, va_alist)
}
#endif /* SPT_TYPE != SPT_BUILTIN */
- /*
+/*
** SM_SETPROCTITLE -- set process task and set process title for ps
**
** Possibly set process status and call setproctitle() to
@@ -2608,15 +2503,15 @@ sm_setproctitle(status, e, fmt, va_alist)
#endif /* __STDC__ */
{
char buf[SPT_BUFSIZE];
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
/* print the argument string */
- VA_START(fmt);
- (void) vsnprintf(buf, sizeof buf, fmt, ap);
- VA_END;
+ SM_VA_START(ap, fmt);
+ (void) sm_vsnprintf(buf, sizeof buf, fmt, ap);
+ SM_VA_END(ap);
if (status)
- proc_list_set(getpid(), buf);
+ proc_list_set(CurrentPid, buf);
if (ProcTitlePrefix != NULL)
{
@@ -2628,7 +2523,7 @@ sm_setproctitle(status, e, fmt, va_alist)
else
setproctitle("%s", buf);
}
- /*
+/*
** WAITFOR -- wait for a particular process id.
**
** Parameters:
@@ -2646,6 +2541,34 @@ int
waitfor(pid)
pid_t pid;
{
+ int st;
+ pid_t i;
+
+ do
+ {
+ errno = 0;
+ i = sm_wait(&st);
+ if (i > 0)
+ proc_list_drop(i, st, NULL);
+ } while ((i >= 0 || errno == EINTR) && i != pid);
+ if (i < 0)
+ return -1;
+ return st;
+}
+/*
+** SM_WAIT -- wait
+**
+** Parameters:
+** status -- pointer to status (return value)
+**
+** Returns:
+** pid
+*/
+
+pid_t
+sm_wait(status)
+ int *status;
+{
# ifdef WAITUNION
union wait st;
# else /* WAITUNION */
@@ -2656,29 +2579,22 @@ waitfor(pid)
int savesig;
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
- do
- {
- errno = 0;
# if defined(ISC_UNIX) || defined(_SCO_unix_)
- savesig = releasesignal(SIGCHLD);
+ savesig = sm_releasesignal(SIGCHLD);
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
- i = wait(&st);
+ i = wait(&st);
# if defined(ISC_UNIX) || defined(_SCO_unix_)
- if (savesig > 0)
- blocksignal(SIGCHLD);
+ if (savesig > 0)
+ sm_blocksignal(SIGCHLD);
# endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */
- if (i > 0)
- (void) proc_list_drop(i);
- } while ((i >= 0 || errno == EINTR) && i != pid);
- if (i < 0)
- return -1;
# ifdef WAITUNION
- return st.w_status;
+ *status = st.w_status;
# else /* WAITUNION */
- return st;
+ *status = st;
# endif /* WAITUNION */
+ return i;
}
- /*
+/*
** REAPCHILD -- pick up the body of my child, lest it become a zombie
**
** Parameters:
@@ -2701,21 +2617,14 @@ SIGFUNC_DECL
reapchild(sig)
int sig;
{
+ int m = 0;
int save_errno = errno;
int st;
pid_t pid;
# if HASWAITPID
auto int status;
int count;
-# else /* HASWAITPID */
-# ifdef WNOHANG
- union wait status;
-# else /* WNOHANG */
- auto int status;
-# endif /* WNOHANG */
-# endif /* HASWAITPID */
-# if HASWAITPID
count = 0;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
{
@@ -2724,10 +2633,14 @@ reapchild(sig)
break;
# else /* HASWAITPID */
# ifdef WNOHANG
+ union wait status;
+
while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
{
st = status.w_status;
# else /* WNOHANG */
+ auto int status;
+
/*
** Catch one zombie -- we will be re-invoked (we hope) if there
** are more. Unreliable signals probably break this, but this
@@ -2741,170 +2654,14 @@ reapchild(sig)
# endif /* WNOHANG */
# endif /* HASWAITPID */
/* Drop PID and check if it was a control socket child */
- if (proc_list_drop(pid) == PROC_CONTROL &&
- WIFEXITED(st))
- {
- /* if so, see if we need to restart or shutdown */
- if (WEXITSTATUS(st) == EX_RESTART)
- {
- RestartRequest = "control socket";
- }
- else if (WEXITSTATUS(st) == EX_SHUTDOWN)
- {
- /* emulate a SIGTERM shutdown */
- ShutdownRequest = "control socket";
- /* NOTREACHED */
- }
- }
+ proc_list_drop(pid, st, NULL);
+ CurRunners -= m; /* Update */
}
FIX_SYSV_SIGNAL(sig, reapchild);
errno = save_errno;
return SIGFUNC_RETURN;
}
- /*
-** PUTENV -- emulation of putenv() in terms of setenv()
-**
-** Not needed on Posix-compliant systems.
-** This doesn't have full Posix semantics, but it's good enough
-** for sendmail.
-**
-** Parameter:
-** env -- the environment to put.
-**
-** Returns:
-** none.
-*/
-
-#if NEEDPUTENV
-
-# if NEEDPUTENV == 2 /* no setenv(3) call available */
-
-int
-putenv(str)
- char *str;
-{
- char **current;
- int matchlen, envlen = 0;
- char *tmp;
- char **newenv;
- static bool first = TRUE;
- extern char **environ;
-
- /*
- * find out how much of str to match when searching
- * for a string to replace.
- */
- if ((tmp = strchr(str, '=')) == NULL || tmp == str)
- matchlen = strlen(str);
- else
- matchlen = (int) (tmp - str);
- ++matchlen;
-
- /*
- * Search for an existing string in the environment and find the
- * length of environ. If found, replace and exit.
- */
- for (current = environ; *current; current++)
- {
- ++envlen;
-
- if (strncmp(str, *current, matchlen) == 0)
- {
- /* found it, now insert the new version */
- *current = (char *)str;
- return 0;
- }
- }
-
- /*
- * There wasn't already a slot so add space for a new slot.
- * If this is our first time through, use malloc(), else realloc().
- */
- if (first)
- {
- newenv = (char **) xalloc(sizeof(char *) * (envlen + 2));
- first = FALSE;
- (void) memcpy(newenv, environ, sizeof(char *) * envlen);
- }
- else
- {
- newenv = (char **) xrealloc((char *)environ,
- sizeof(char *) * (envlen + 2));
- }
-
- /* actually add in the new entry */
- environ = newenv;
- environ[envlen] = (char *)str;
- environ[envlen + 1] = NULL;
-
- return 0;
-}
-
-# else /* NEEDPUTENV == 2 */
-
-int
-putenv(env)
- char *env;
-{
- char *p;
- int l;
- char nbuf[100];
-
- p = strchr(env, '=');
- if (p == NULL)
- return 0;
- l = p - env;
- if (l > sizeof nbuf - 1)
- l = sizeof nbuf - 1;
- memmove(nbuf, env, l);
- nbuf[l] = '\0';
- return setenv(nbuf, ++p, 1);
-}
-
-# endif /* NEEDPUTENV == 2 */
-#endif /* NEEDPUTENV */
- /*
-** UNSETENV -- remove a variable from the environment
-**
-** Not needed on newer systems.
-**
-** Parameters:
-** name -- the string name of the environment variable to be
-** deleted from the current environment.
-**
-** Returns:
-** none.
-**
-** Globals:
-** environ -- a pointer to the current environment.
-**
-** Side Effects:
-** Modifies environ.
-*/
-
-#if !HASUNSETENV
-
-void
-unsetenv(name)
- char *name;
-{
- extern char **environ;
- register char **pp;
- int len = strlen(name);
-
- for (pp = environ; *pp != NULL; pp++)
- {
- if (strncmp(name, *pp, len) == 0 &&
- ((*pp)[len] == '=' || (*pp)[len] == '\0'))
- break;
- }
-
- for (; *pp != NULL; pp++)
- *pp = pp[1];
-}
-
-#endif /* !HASUNSETENV */
- /*
+/*
** GETDTABLESIZE -- return number of file descriptors
**
** Only on non-BSD systems
@@ -2943,7 +2700,7 @@ getdtsize()
# endif /* _SC_OPEN_MAX */
# endif /* HASGETDTABLESIZE */
}
- /*
+/*
** UNAME -- get the UUCP name of this system.
*/
@@ -2953,16 +2710,18 @@ int
uname(name)
struct utsname *name;
{
- FILE *file;
+ SM_FILE_T *file;
char *n;
name->nodename[0] = '\0';
/* try /etc/whoami -- one line with the node name */
- if ((file = fopen("/etc/whoami", "r")) != NULL)
+ if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, "/etc/whoami",
+ SM_IO_RDONLY, NULL)) != NULL)
{
- (void) fgets(name->nodename, NODE_LENGTH + 1, file);
- (void) fclose(file);
+ (void) sm_io_fgets(file, SM_TIME_DEFAULT, name->nodename,
+ NODE_LENGTH + 1);
+ (void) sm_io_close(file, SM_TIME_DEFAULT);
n = strchr(name->nodename, '\n');
if (n != NULL)
*n = '\0';
@@ -2971,17 +2730,19 @@ uname(name)
}
/* try /usr/include/whoami.h -- has a #define somewhere */
- if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
+ if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
+ "/usr/include/whoami.h", SM_IO_RDONLY, NULL))
+ != NULL)
{
char buf[MAXLINE];
- while (fgets(buf, MAXLINE, file) != NULL)
+ while (sm_io_fgets(file, SM_TIME_DEFAULT, buf, MAXLINE) != NULL)
{
- if (sscanf(buf, "#define sysname \"%*[^\"]\"",
+ if (sm_io_sscanf(buf, "#define sysname \"%*[^\"]\"",
NODE_LENGTH, name->nodename) > 0)
break;
}
- (void) fclose(file);
+ (void) sm_io_close(file, SM_TIME_DEFAULT);
if (name->nodename[0] != '\0')
return 0;
}
@@ -2994,7 +2755,8 @@ uname(name)
/* try uuname -l to return local name */
if ((file = popen("uuname -l", "r")) != NULL)
{
- (void) fgets(name, NODE_LENGTH + 1, file);
+ (void) sm_io_fgets(file, SM_TIME_DEFAULT, name,
+ NODE_LENGTH + 1);
(void) pclose(file);
n = strchr(name, '\n');
if (n != NULL)
@@ -3007,7 +2769,7 @@ uname(name)
return -1;
}
#endif /* !HASUNAME */
- /*
+/*
** INITGROUPS -- initialize groups
**
** Stub implementation for System V style systems
@@ -3023,7 +2785,7 @@ initgroups(name, basegid)
}
#endif /* !HASINITGROUPS */
- /*
+/*
** SETGROUPS -- set group list
**
** Stub implementation for systems that don't have group lists
@@ -3040,7 +2802,7 @@ setgroups(ngroups, grouplist)
}
#endif /* ! NGROUPS_MAX */
- /*
+/*
** SETSID -- set session id (for non-POSIX systems)
*/
@@ -3062,12 +2824,12 @@ setsid __P ((void))
# ifdef SYS5SETPGRP
return setpgrp();
# else /* SYS5SETPGRP */
- return setpgid(0, getpid());
+ return setpgid(0, CurrentPid);
# endif /* SYS5SETPGRP */
}
#endif /* !HASSETSID */
- /*
+/*
** FSYNC -- dummy fsync
*/
@@ -3085,7 +2847,7 @@ fsync(fd)
}
#endif /* NEEDFSYNC */
- /*
+/*
** DGUX_INET_ADDR -- inet_addr for DG/UX
**
** Data General DG/UX version of inet_addr returns a struct in_addr
@@ -3108,11 +2870,11 @@ dgux_inet_addr(host)
}
#endif /* DGUX_5_4_2 */
- /*
+/*
** GETOPT -- for old systems or systems with bogus implementations
*/
-#if NEEDGETOPT
+#if !SM_CONF_GETOPT
/*
* Copyright (c) 1985 Regents of the University of California.
@@ -3131,8 +2893,8 @@ static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
# endif /* defined(LIBC_SCCS) && !defined(lint) */
/*
- * get option letter from argument vector
- */
+** get option letter from argument vector
+*/
# ifdef _CONVEX_SOURCE
extern int optind, opterr, optopt;
extern char *optarg;
@@ -3145,8 +2907,12 @@ char *optarg = NULL; /* argument associated with option */
# define BADCH (int)'?'
# define EMSG ""
-# define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
- fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
+# define tell(s) if (opterr) \
+ {sm_io_fputs(smioerr, SM_TIME_DEFAULT, *nargv); \
+ (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, s); \
+ (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, optopt); \
+ (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, '\n'); \
+ return BADCH;}
int
getopt(nargc,nargv,ostr)
@@ -3191,52 +2957,11 @@ getopt(nargc,nargv,ostr)
place = EMSG;
++optind;
}
- return(optopt); /* dump back option letter */
-}
-
-#endif /* NEEDGETOPT */
- /*
-** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
-*/
-
-#if NEEDVPRINTF
-
-# define MAXARG 16
-
-vfprintf(fp, fmt, ap)
- FILE *fp;
- char *fmt;
- char **ap;
-{
- char *bp[MAXARG];
- int i = 0;
-
- while (*ap && i < MAXARG)
- bp[i++] = *ap++;
- fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
- bp[4], bp[5], bp[6], bp[7],
- bp[8], bp[9], bp[10], bp[11],
- bp[12], bp[13], bp[14], bp[15]);
-}
-
-vsprintf(s, fmt, ap)
- char *s;
- char *fmt;
- char **ap;
-{
- char *bp[MAXARG];
- int i = 0;
-
- while (*ap && i < MAXARG)
- bp[i++] = *ap++;
- sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
- bp[4], bp[5], bp[6], bp[7],
- bp[8], bp[9], bp[10], bp[11],
- bp[12], bp[13], bp[14], bp[15]);
+ return optopt; /* dump back option letter */
}
-#endif /* NEEDVPRINTF */
- /*
+#endif /* !SM_CONF_GETOPT */
+/*
** USERSHELLOK -- tell if a user's shell is ok for unrestricted use
**
** Parameters:
@@ -3244,8 +2969,8 @@ vsprintf(s, fmt, ap)
** shell -- the user's shell from /etc/passwd
**
** Returns:
-** TRUE -- if it is ok to use this for unrestricted access.
-** FALSE -- if the shell is restricted.
+** true -- if it is ok to use this for unrestricted access.
+** false -- if the shell is restricted.
*/
#if !HASGETUSERSHELL
@@ -3265,9 +2990,13 @@ vsprintf(s, fmt, ap)
static char *DefaultUserShells[] =
{
"/bin/sh", /* standard shell */
+# ifdef MPE
+ "/SYS/PUB/CI",
+# else /* MPE */
"/usr/bin/sh",
"/bin/csh", /* C shell */
"/usr/bin/csh",
+# endif /* MPE */
# ifdef __hpux
# ifdef V4FS
"/usr/bin/rsh", /* restricted Bourne shell */
@@ -3324,7 +3053,7 @@ usershellok(user, shell)
if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
ConfigLevel <= 1)
- return TRUE;
+ return true;
setusershell();
while ((p = getusershell()) != NULL)
@@ -3336,12 +3065,12 @@ usershellok(user, shell)
# if USEGETCONFATTR
auto char *v;
# endif /* USEGETCONFATTR */
- register FILE *shellf;
+ register SM_FILE_T *shellf;
char buf[MAXLINE];
if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
ConfigLevel <= 1)
- return TRUE;
+ return true;
# if USEGETCONFATTR
/*
@@ -3362,14 +3091,15 @@ usershellok(user, shell)
while (*v != '\0')
{
if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
- return TRUE;
+ return true;
v += strlen(v) + 1;
}
- return FALSE;
+ return false;
}
# endif /* USEGETCONFATTR */
- shellf = fopen(_PATH_SHELLS, "r");
+ shellf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_SHELLS,
+ SM_IO_RDONLY, NULL);
if (shellf == NULL)
{
/* no /etc/shells; see if it is one of the std shells */
@@ -3378,17 +3108,17 @@ usershellok(user, shell)
if (errno != ENOENT && LogLevel > 3)
sm_syslog(LOG_ERR, NOQID,
"usershellok: cannot open %s: %s",
- _PATH_SHELLS, errstring(errno));
+ _PATH_SHELLS, sm_errstring(errno));
for (d = DefaultUserShells; *d != NULL; d++)
{
if (strcmp(shell, *d) == 0)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- while (fgets(buf, sizeof buf, shellf) != NULL)
+ while (sm_io_fgets(shellf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
register char *p, *q;
@@ -3403,15 +3133,15 @@ usershellok(user, shell)
*p = '\0';
if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
{
- (void) fclose(shellf);
- return TRUE;
+ (void) sm_io_close(shellf, SM_TIME_DEFAULT);
+ return true;
}
}
- (void) fclose(shellf);
- return FALSE;
+ (void) sm_io_close(shellf, SM_TIME_DEFAULT);
+ return false;
# endif /* HASGETUSERSHELL */
}
- /*
+/*
** FREEDISKSPACE -- see how much free space is on the queue filesystem
**
** Only implemented if you have statfs.
@@ -3430,40 +3160,46 @@ usershellok(user, shell)
*/
/* statfs types */
-#define SFS_NONE 0 /* no statfs implementation */
-#define SFS_USTAT 1 /* use ustat */
-#define SFS_4ARGS 2 /* use four-argument statfs call */
-#define SFS_VFS 3 /* use <sys/vfs.h> implementation */
-#define SFS_MOUNT 4 /* use <sys/mount.h> implementation */
-#define SFS_STATFS 5 /* use <sys/statfs.h> implementation */
-#define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */
-
-#ifndef SFS_TYPE
-# define SFS_TYPE SFS_NONE
-#endif /* ! SFS_TYPE */
-
-#if SFS_TYPE == SFS_USTAT
-# include <ustat.h>
-#endif /* SFS_TYPE == SFS_USTAT */
-#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
-# include <sys/statfs.h>
-#endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
-#if SFS_TYPE == SFS_VFS
-# include <sys/vfs.h>
-#endif /* SFS_TYPE == SFS_VFS */
-#if SFS_TYPE == SFS_MOUNT
-# include <sys/mount.h>
-#endif /* SFS_TYPE == SFS_MOUNT */
-#if SFS_TYPE == SFS_STATVFS
-# include <sys/statvfs.h>
-#endif /* SFS_TYPE == SFS_STATVFS */
+# define SFS_NONE 0 /* no statfs implementation */
+# define SFS_USTAT 1 /* use ustat */
+# define SFS_4ARGS 2 /* use four-argument statfs call */
+# define SFS_VFS 3 /* use <sys/vfs.h> implementation */
+# define SFS_MOUNT 4 /* use <sys/mount.h> implementation */
+# define SFS_STATFS 5 /* use <sys/statfs.h> implementation */
+# define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */
+
+# ifndef SFS_TYPE
+# define SFS_TYPE SFS_NONE
+# endif /* ! SFS_TYPE */
+
+# if SFS_TYPE == SFS_USTAT
+# include <ustat.h>
+# endif /* SFS_TYPE == SFS_USTAT */
+# if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
+# include <sys/statfs.h>
+# endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */
+# if SFS_TYPE == SFS_VFS
+# include <sys/vfs.h>
+# endif /* SFS_TYPE == SFS_VFS */
+# if SFS_TYPE == SFS_MOUNT
+# include <sys/mount.h>
+# endif /* SFS_TYPE == SFS_MOUNT */
+# if SFS_TYPE == SFS_STATVFS
+# include <sys/statvfs.h>
+# endif /* SFS_TYPE == SFS_STATVFS */
long
freediskspace(dir, bsize)
char *dir;
long *bsize;
{
-# if SFS_TYPE != SFS_NONE
+# if SFS_TYPE == SFS_NONE
+ if (bsize != NULL)
+ *bsize = 4096L;
+
+ /* assume free space is plentiful */
+ return (long) LONG_MAX;
+# else /* SFS_TYPE == SFS_NONE */
# if SFS_TYPE == SFS_USTAT
struct ustat fs;
struct stat statbuf;
@@ -3515,69 +3251,51 @@ freediskspace(dir, bsize)
else
return (long) fs.SFS_BAVAIL;
}
-# endif /* SFS_TYPE != SFS_NONE */
return -1;
+# endif /* SFS_TYPE == SFS_NONE */
}
- /*
-** ENOUGHDISKSPACE -- is there enough free space on the queue fs?
-**
-** Only implemented if you have statfs.
+/*
+** ENOUGHDISKSPACE -- is there enough free space on the queue file systems?
**
** Parameters:
** msize -- the size to check against. If zero, we don't yet
** know how big the message will be, so just check for
** a "reasonable" amount.
-** log -- log message?
+** e -- envelope, or NULL -- controls logging
**
** Returns:
-** TRUE if there is enough space.
-** FALSE otherwise.
+** true if in every queue group there is at least one
+** queue directory whose file system contains enough free space.
+** false otherwise.
+**
+** Side Effects:
+** If there is not enough disk space and e != NULL
+** then sm_syslog is called.
*/
bool
-enoughdiskspace(msize, log)
+enoughdiskspace(msize, e)
long msize;
- bool log;
+ ENVELOPE *e;
{
- long bfree;
- long bsize;
+ int i;
if (MinBlocksFree <= 0 && msize <= 0)
{
if (tTd(4, 80))
- dprintf("enoughdiskspace: no threshold\n");
- return TRUE;
+ sm_dprintf("enoughdiskspace: no threshold\n");
+ return true;
}
- bfree = freediskspace(QueueDir, &bsize);
- if (bfree >= 0)
+ filesys_update();
+ for (i = 0; i < NumQueue; ++i)
{
- if (tTd(4, 80))
- dprintf("enoughdiskspace: bavail=%ld, need=%ld\n",
- bfree, msize);
-
- /* convert msize to block count */
- msize = msize / bsize + 1;
- if (MinBlocksFree >= 0)
- msize += MinBlocksFree;
-
- if (bfree < msize)
- {
- if (log && LogLevel > 0)
- sm_syslog(LOG_ALERT, CurEnv->e_id,
- "low on space (have %ld, %s needs %ld in %s)",
- bfree,
- CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
- msize, QueueDir);
- return FALSE;
- }
+ if (pickqdir(Queue[i], msize, e) < 0)
+ return false;
}
- else if (tTd(4, 80))
- dprintf("enoughdiskspace failure: min=%ld, need=%ld: %s\n",
- MinBlocksFree, msize, errstring(errno));
- return TRUE;
+ return true;
}
- /*
+/*
** TRANSIENTERROR -- tell if an error code indicates a transient failure
**
** This looks at an errno value and tells if this is likely to
@@ -3587,8 +3305,8 @@ enoughdiskspace(msize, log)
** err -- the errno code to classify.
**
** Returns:
-** TRUE if this is probably transient.
-** FALSE otherwise.
+** true if this is probably transient.
+** false otherwise.
*/
bool
@@ -3605,9 +3323,7 @@ transienterror(err)
case ENFILE: /* Too many open files in system */
case EMFILE: /* Too many open files */
case ENOSPC: /* No space left on device */
-#ifdef ETIMEDOUT
case ETIMEDOUT: /* Connection timed out */
-#endif /* ETIMEDOUT */
#ifdef ESTALE
case ESTALE: /* Stale NFS file handle */
#endif /* ESTALE */
@@ -3678,13 +3394,13 @@ transienterror(err)
case ENOLCK: /* No locks available */
#endif /* ENOLCK */
case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */
- return TRUE;
+ return true;
}
/* nope, must be permanent */
- return FALSE;
+ return false;
}
- /*
+/*
** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
**
** Parameters:
@@ -3697,8 +3413,8 @@ transienterror(err)
** LOCK_UN -- unlock.
**
** Returns:
-** TRUE if the lock was acquired.
-** FALSE otherwise.
+** true if the lock was acquired.
+** false otherwise.
*/
bool
@@ -3731,7 +3447,7 @@ lockfile(fd, filename, ext, type)
action = F_SETLKW;
if (tTd(55, 60))
- dprintf("lockfile(%s%s, action=%d, type=%d): ",
+ sm_dprintf("lockfile(%s%s, action=%d, type=%d): ",
filename, ext, action, lfd.l_type);
while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
@@ -3739,13 +3455,13 @@ lockfile(fd, filename, ext, type)
if (i >= 0)
{
if (tTd(55, 60))
- dprintf("SUCCESS\n");
- return TRUE;
+ sm_dprintf("SUCCESS\n");
+ return true;
}
save_errno = errno;
if (tTd(55, 60))
- dprintf("(%s) ", errstring(save_errno));
+ sm_dprintf("(%s) ", sm_errstring(save_errno));
/*
** On SunOS, if you are testing using -oQ/tmp/mqueue or
@@ -3759,8 +3475,8 @@ lockfile(fd, filename, ext, type)
if (save_errno == EINVAL)
{
if (tTd(55, 60))
- dprintf("SUCCESS\n");
- return TRUE;
+ sm_dprintf("SUCCESS\n");
+ return true;
}
if (!bitset(LOCK_NB, type) ||
@@ -3773,27 +3489,27 @@ lockfile(fd, filename, ext, type)
# endif /* F_GETFL */
syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename, ext, fd, type, omode, geteuid());
- dumpfd(fd, TRUE, TRUE);
+ dumpfd(fd, true, true);
}
# else /* !HASFLOCK */
if (ext == NULL)
ext = "";
if (tTd(55, 60))
- dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
+ sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
while ((i = flock(fd, type)) < 0 && errno == EINTR)
continue;
if (i >= 0)
{
if (tTd(55, 60))
- dprintf("SUCCESS\n");
- return TRUE;
+ sm_dprintf("SUCCESS\n");
+ return true;
}
save_errno = errno;
if (tTd(55, 60))
- dprintf("(%s) ", errstring(save_errno));
+ sm_dprintf("(%s) ", sm_errstring(save_errno));
if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
{
@@ -3804,15 +3520,15 @@ lockfile(fd, filename, ext, type)
# endif /* F_GETFL */
syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename, ext, fd, type, omode, geteuid());
- dumpfd(fd, TRUE, TRUE);
+ dumpfd(fd, true, true);
}
# endif /* !HASFLOCK */
if (tTd(55, 60))
- dprintf("FAIL\n");
+ sm_dprintf("FAIL\n");
errno = save_errno;
- return FALSE;
+ return false;
}
- /*
+/*
** CHOWNSAFE -- tell if chown is "safe" (executable only by root)
**
** Unfortunately, given that we can't predict other systems on which
@@ -3860,9 +3576,9 @@ lockfile(fd, filename, ext, type)
** safedir -- set if the parent directory is safe.
**
** Returns:
-** TRUE -- if the chown(2) operation is "safe" -- that is,
+** true -- if the chown(2) operation is "safe" -- that is,
** only root can chown the file to an arbitrary user.
-** FALSE -- if an arbitrary user can give away a file.
+** false -- if an arbitrary user can give away a file.
*/
#ifndef IS_SAFE_CHOWN
@@ -3880,7 +3596,7 @@ chownsafe(fd, safedir)
/* give the system administrator a chance to override */
if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
- return TRUE;
+ return true;
/*
** Some systems (e.g., SunOS) seem to have the call and the
@@ -3895,11 +3611,11 @@ chownsafe(fd, safedir)
# else /* SAFENFSPATHCONF */
return safedir && errno == 0 && rval IS_SAFE_CHOWN;
# endif /* SAFENFSPATHCONF */
-# else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
+# else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
-# endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ */
+# endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */
}
- /*
+/*
** RESETLIMITS -- reset system controlled resource limits
**
** This is to avoid denial-of-service attacks
@@ -3942,40 +3658,15 @@ resetlimits()
#endif /* HASSETRLIMIT */
errno = 0;
}
- /*
-** GETCFNAME -- return the name of the .cf file.
-**
-** Some systems (e.g., NeXT) determine this dynamically.
-*/
-
-char *
-getcfname()
-{
-
- if (ConfFile != NULL)
- return ConfFile;
-#if NETINFO
- {
- char *cflocation;
-
- cflocation = ni_propval("/locations", NULL, "sendmail",
- "sendmail.cf", '\0');
- if (cflocation != NULL)
- return cflocation;
- }
-#endif /* NETINFO */
-
- return _PATH_SENDMAILCF;
-}
- /*
+/*
** SETVENDOR -- process vendor code from V configuration line
**
** Parameters:
** vendor -- string representation of vendor.
**
** Returns:
-** TRUE -- if ok.
-** FALSE -- if vendor code could not be processed.
+** true -- if ok.
+** false -- if vendor code could not be processed.
**
** Side Effects:
** It is reasonable to set mode flags here to tweak
@@ -3988,33 +3679,33 @@ bool
setvendor(vendor)
char *vendor;
{
- if (strcasecmp(vendor, "Berkeley") == 0)
+ if (sm_strcasecmp(vendor, "Berkeley") == 0)
{
VendorCode = VENDOR_BERKELEY;
- return TRUE;
+ return true;
}
/* add vendor extensions here */
#ifdef SUN_EXTENSIONS
- if (strcasecmp(vendor, "Sun") == 0)
+ if (sm_strcasecmp(vendor, "Sun") == 0)
{
VendorCode = VENDOR_SUN;
- return TRUE;
+ return true;
}
#endif /* SUN_EXTENSIONS */
#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
- if (strcasecmp(vendor, VENDOR_NAME) == 0)
+ if (sm_strcasecmp(vendor, VENDOR_NAME) == 0)
{
VendorCode = VENDOR_CODE;
- return TRUE;
+ return true;
}
#endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */
- return FALSE;
+ return false;
}
- /*
+/*
** GETVENDOR -- return vendor name based on vendor code
**
** Parameters:
@@ -4041,26 +3732,26 @@ getvendor(vendorcode)
switch (vendorcode)
{
- case VENDOR_BERKELEY:
- return "Berkeley";
+ case VENDOR_BERKELEY:
+ return "Berkeley";
- case VENDOR_SUN:
- return "Sun";
+ case VENDOR_SUN:
+ return "Sun";
- case VENDOR_HP:
- return "HP";
+ case VENDOR_HP:
+ return "HP";
- case VENDOR_IBM:
- return "IBM";
+ case VENDOR_IBM:
+ return "IBM";
- case VENDOR_SENDMAIL:
- return "Sendmail";
+ case VENDOR_SENDMAIL:
+ return "Sendmail";
- default:
- return "Unknown";
+ default:
+ return "Unknown";
}
}
- /*
+/*
** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
**
** Vendor_pre_defaults is called before reading the configuration
@@ -4115,7 +3806,7 @@ vendor_post_defaults(e)
sun_post_defaults(e);
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */
}
- /*
+/*
** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
*/
@@ -4130,11 +3821,11 @@ vendor_daemon_setup(e)
if (getluid() != -1)
{
usrerr("Daemon cannot have LUID");
- finis(FALSE, EX_USAGE);
+ finis(false, true, EX_USAGE);
}
#endif /* SECUREWARE */
}
- /*
+/*
** VENDOR_SET_UID -- do setup for setting a user id
**
** This is called when we are still root.
@@ -4163,7 +3854,7 @@ vendor_set_uid(uid)
(void) setup_secure(uid);
#endif /* SECUREWARE */
}
- /*
+/*
** VALIDATE_CONNECTION -- check connection for rationality
**
** If the connection is rejected, this routine should log an
@@ -4187,61 +3878,69 @@ int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
#endif /* TCPWRAPPERS */
-#if DAEMON
char *
validate_connection(sap, hostname, e)
SOCKADDR *sap;
char *hostname;
ENVELOPE *e;
{
-# if TCPWRAPPERS
+#if TCPWRAPPERS
char *host;
-# endif /* TCPWRAPPERS */
+ char *addr;
+ extern int hosts_ctl();
+#endif /* TCPWRAPPERS */
if (tTd(48, 3))
- dprintf("validate_connection(%s, %s)\n",
+ sm_dprintf("validate_connection(%s, %s)\n",
hostname, anynet_ntoa(sap));
if (rscheck("check_relay", hostname, anynet_ntoa(sap),
- e, TRUE, TRUE, 4, NULL) != EX_OK)
+ e, true, true, 3, NULL, NOQID) != EX_OK)
{
static char reject[BUFSIZ*2];
extern char MsgBuf[];
if (tTd(48, 4))
- dprintf(" ... validate_connection: BAD (rscheck)\n");
+ sm_dprintf(" ... validate_connection: BAD (rscheck)\n");
if (strlen(MsgBuf) >= 3)
- (void) strlcpy(reject, MsgBuf, sizeof reject);
+ (void) sm_strlcpy(reject, MsgBuf, sizeof reject);
else
- (void) strlcpy(reject, "Access denied", sizeof reject);
+ (void) sm_strlcpy(reject, "Access denied", sizeof reject);
return reject;
}
-# if TCPWRAPPERS
+#if TCPWRAPPERS
if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
host = "unknown";
else
host = hostname;
- if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
+ addr = anynet_ntoa(sap);
+
+# if NETINET6
+ /* TCP/Wrappers don't want the IPv6: protocol label */
+ if (addr != NULL && sm_strncasecmp(addr, "IPv6:", 5) == 0)
+ addr += 5;
+# endif /* NETINET6 */
+
+ if (!hosts_ctl("sendmail", host, addr, STRING_UNKNOWN))
{
if (tTd(48, 4))
- dprintf(" ... validate_connection: BAD (tcpwrappers)\n");
- if (LogLevel >= 4)
+ sm_dprintf(" ... validate_connection: BAD (tcpwrappers)\n");
+ if (LogLevel > 3)
sm_syslog(LOG_NOTICE, e->e_id,
- "tcpwrappers (%s, %s) rejection",
- host, anynet_ntoa(sap));
+ "tcpwrappers (%s, %s) rejection",
+ host, addr);
return "Access denied";
}
-# endif /* TCPWRAPPERS */
+#endif /* TCPWRAPPERS */
if (tTd(48, 4))
- dprintf(" ... validate_connection: OK\n");
+ sm_dprintf(" ... validate_connection: OK\n");
return NULL;
}
-#endif /* DAEMON */
- /*
+/*
** STRTOL -- convert string to long integer
**
** For systems that don't have it in the C library.
@@ -4256,11 +3955,11 @@ static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
# endif /* defined(LIBC_SCCS) && !defined(lint) */
/*
- * Convert a string to a long integer.
- *
- * Ignores `locale' stuff. Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
- */
+** Convert a string to a long integer.
+**
+** Ignores `locale' stuff. Assumes that the upper and lower case
+** alphabets and digits are each contiguous.
+*/
long
strtol(nptr, endptr, base)
@@ -4275,10 +3974,10 @@ strtol(nptr, endptr, base)
register int neg = 0, any, cutlim;
/*
- * Skip white space and pick up leading +/- sign if any.
- * If base is 0, allow 0x for hex and 0 for octal, else
- * assume decimal; if base is already 16, allow 0x.
- */
+ ** Skip white space and pick up leading +/- sign if any.
+ ** If base is 0, allow 0x for hex and 0 for octal, else
+ ** assume decimal; if base is already 16, allow 0x.
+ */
do {
c = *s++;
} while (isspace(c));
@@ -4297,25 +3996,25 @@ strtol(nptr, endptr, base)
base = c == '0' ? 8 : 10;
/*
- * Compute the cutoff value between legal numbers and illegal
- * numbers. That is the largest legal value, divided by the
- * base. An input number that is greater than this value, if
- * followed by a legal input character, is too big. One that
- * is equal to this value may be valid or not; the limit
- * between valid and invalid numbers is then based on the last
- * digit. For instance, if the range for longs is
- * [-2147483648..2147483647] and the input base is 10,
- * cutoff will be set to 214748364 and cutlim to either
- * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
- * a value > 214748364, or equal but the next digit is > 7 (or 8),
- * the number is too big, and we will return a range error.
- *
- * Set any if any `digits' consumed; make it negative to indicate
- * overflow.
- */
- cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
- cutlim = cutoff % (unsigned long)base;
- cutoff /= (unsigned long)base;
+ ** Compute the cutoff value between legal numbers and illegal
+ ** numbers. That is the largest legal value, divided by the
+ ** base. An input number that is greater than this value, if
+ ** followed by a legal input character, is too big. One that
+ ** is equal to this value may be valid or not; the limit
+ ** between valid and invalid numbers is then based on the last
+ ** digit. For instance, if the range for longs is
+ ** [-2147483648..2147483647] and the input base is 10,
+ ** cutoff will be set to 214748364 and cutlim to either
+ ** 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ ** a value > 214748364, or equal but the next digit is > 7 (or 8),
+ ** the number is too big, and we will return a range error.
+ **
+ ** Set any if any `digits' consumed; make it negative to indicate
+ ** overflow.
+ */
+ cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long) base;
+ cutoff /= (unsigned long) base;
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c))
c -= '0';
@@ -4344,7 +4043,7 @@ strtol(nptr, endptr, base)
}
#endif /* NEEDSTRTOL */
- /*
+/*
** STRSTR -- find first substring in string
**
** Parameters:
@@ -4381,7 +4080,7 @@ strstr(big, little)
}
#endif /* NEEDSTRSTR */
- /*
+/*
** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
**
** Some operating systems have wierd problems with the gethostbyXXX
@@ -4414,7 +4113,7 @@ getipnodebyname(name, family, flags, err)
int flags;
int *err;
{
- bool resv6 = TRUE;
+ bool resv6 = true;
struct hostent *h;
if (family == AF_INET6)
@@ -4425,9 +4124,9 @@ getipnodebyname(name, family, flags, err)
}
SM_SET_H_ERRNO(0);
h = gethostbyname(name);
- *err = h_errno;
- if (family == AF_INET6 && !resv6)
+ if (!resv6)
_res.options &= ~RES_USE_INET6;
+ *err = h_errno;
return h;
}
@@ -4446,7 +4145,6 @@ getipnodebyaddr(addr, len, family, err)
return h;
}
-# if _FFR_FREEHOSTENT
void
freehostent(h)
struct hostent *h;
@@ -4458,8 +4156,7 @@ freehostent(h)
return;
}
-# endif /* _FFR_FREEHOSTENT */
-#endif /* NEEDSGETIPNODE && NETINET6 */
+#endif /* NETINET6 && NEEDSGETIPNODE */
struct hostent *
sm_gethostbyname(name, family)
@@ -4475,14 +4172,14 @@ sm_gethostbyname(name, family)
extern struct hostent *_switch_gethostbyname_r();
if (tTd(61, 10))
- dprintf("_switch_gethostbyname_r(%s)... ", name);
+ sm_dprintf("_switch_gethostbyname_r(%s)... ", name);
h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
save_errno = errno;
# else /* SOLARIS == 20300 || SOLARIS == 203 */
extern struct hostent *__switch_gethostbyname();
if (tTd(61, 10))
- dprintf("__switch_gethostbyname(%s)... ", name);
+ sm_dprintf("__switch_gethostbyname(%s)... ", name);
h = __switch_gethostbyname(name);
save_errno = errno;
# endif /* SOLARIS == 20300 || SOLARIS == 203 */
@@ -4497,7 +4194,7 @@ sm_gethostbyname(name, family)
char hbuf[MAXNAME];
if (tTd(61, 10))
- dprintf("sm_gethostbyname(%s, %d)... ", name, family);
+ sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family);
# if NETINET6
# if ADDRCONFIG_IS_BROKEN
@@ -4513,7 +4210,7 @@ sm_gethostbyname(name, family)
if (h == NULL)
{
if (tTd(61, 10))
- dprintf("failure\n");
+ sm_dprintf("failure\n");
nmaps = switch_map_find("hosts", maptype, mapreturn);
while (--nmaps >= 0)
@@ -4526,19 +4223,19 @@ sm_gethostbyname(name, family)
if (nmaps >= 0)
{
/* try short name */
- if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
+ if (strlen(name) > sizeof hbuf - 1)
{
errno = save_errno;
return NULL;
}
- (void) strlcpy(hbuf, name, sizeof hbuf);
+ (void) sm_strlcpy(hbuf, name, sizeof hbuf);
(void) shorten_hostname(hbuf);
/* if it hasn't been shortened, there's no point */
if (strcmp(hbuf, name) != 0)
{
if (tTd(61, 10))
- dprintf("sm_gethostbyname(%s, %d)... ",
+ sm_dprintf("sm_gethostbyname(%s, %d)... ",
hbuf, family);
# if NETINET6
@@ -4556,10 +4253,10 @@ sm_gethostbyname(name, family)
if (tTd(61, 10))
{
if (h == NULL)
- dprintf("failure\n");
+ sm_dprintf("failure\n");
else
{
- dprintf("%s\n", h->h_name);
+ sm_dprintf("%s\n", h->h_name);
if (tTd(61, 11))
{
#if NETINET6
@@ -4568,12 +4265,12 @@ sm_gethostbyname(name, family)
#else /* NETINET6 */
struct in_addr ia;
#endif /* NETINET6 */
- int i;
+ size_t i;
if (h->h_aliases != NULL)
for (i = 0; h->h_aliases[i] != NULL;
i++)
- dprintf("\talias: %s\n",
+ sm_dprintf("\talias: %s\n",
h->h_aliases[i]);
for (i = 0; h->h_addr_list[i] != NULL; i++)
{
@@ -4590,7 +4287,7 @@ sm_gethostbyname(name, family)
addr = (char *) inet_ntoa(ia);
#endif /* NETINET6 */
if (addr != NULL)
- dprintf("\taddr: %s\n", addr);
+ sm_dprintf("\taddr: %s\n", addr);
}
}
}
@@ -4648,37 +4345,36 @@ sm_gethostbyaddr(addr, len, type)
#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */
return hp;
}
- /*
+/*
** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
*/
-
struct passwd *
sm_getpwnam(user)
char *user;
{
-# ifdef _AIX4
+#ifdef _AIX4
extern struct passwd *_getpwnam_shadow(const char *, const int);
return _getpwnam_shadow(user, 0);
-# else /* _AIX4 */
+#else /* _AIX4 */
return getpwnam(user);
-# endif /* _AIX4 */
+#endif /* _AIX4 */
}
struct passwd *
sm_getpwuid(uid)
UID_T uid;
{
-# if defined(_AIX4) && 0
+#if defined(_AIX4) && 0
extern struct passwd *_getpwuid_shadow(const int, const int);
return _getpwuid_shadow(uid,0);
-# else /* defined(_AIX4) && 0 */
+#else /* defined(_AIX4) && 0 */
return getpwuid(uid);
-# endif /* defined(_AIX4) && 0 */
+#endif /* defined(_AIX4) && 0 */
}
- /*
+/*
** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
**
** Set up the trusted computing environment for C2 level security
@@ -4713,34 +4409,38 @@ secureware_setup_secure(uid)
switch (rc)
{
case SSI_NO_PRPW_ENTRY:
- syserr("No protected passwd entry, uid = %d", uid);
+ syserr("No protected passwd entry, uid = %d",
+ (int) uid);
break;
case SSI_LOCKED:
- syserr("Account has been disabled, uid = %d", uid);
+ syserr("Account has been disabled, uid = %d",
+ (int) uid);
break;
case SSI_RETIRED:
- syserr("Account has been retired, uid = %d", uid);
+ syserr("Account has been retired, uid = %d",
+ (int) uid);
break;
case SSI_BAD_SET_LUID:
- syserr("Could not set LUID, uid = %d", uid);
+ syserr("Could not set LUID, uid = %d", (int) uid);
break;
case SSI_BAD_SET_PRIVS:
- syserr("Could not set kernel privs, uid = %d", uid);
+ syserr("Could not set kernel privs, uid = %d",
+ (int) uid);
default:
syserr("Unknown return code (%d) from set_secure_info(%d)",
- rc, uid);
+ rc, (int) uid);
break;
}
- finis(FALSE, EX_NOPERM);
+ finis(false, true, EX_NOPERM);
}
}
#endif /* SECUREWARE */
- /*
+/*
** ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address
**
** Add hostnames to class 'w' based on the IP address read from
@@ -4765,28 +4465,28 @@ add_hostnames(sa)
switch (sa->sa.sa_family)
{
#if NETINET
- case AF_INET:
- hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
- sizeof(sa->sin.sin_addr),
- sa->sa.sa_family);
- break;
+ case AF_INET:
+ hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
+ sizeof(sa->sin.sin_addr),
+ sa->sa.sa_family);
+ break;
#endif /* NETINET */
#if NETINET6
- case AF_INET6:
- hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
- sizeof(sa->sin6.sin6_addr),
- sa->sa.sa_family);
- break;
+ case AF_INET6:
+ hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr,
+ sizeof(sa->sin6.sin6_addr),
+ sa->sa.sa_family);
+ break;
#endif /* NETINET6 */
- default:
- /* Give warning about unsupported family */
- if (LogLevel > 3)
- sm_syslog(LOG_WARNING, NOQID,
- "Unsupported address family %d: %.100s",
- sa->sa.sa_family, anynet_ntoa(sa));
- return -1;
+ default:
+ /* Give warning about unsupported family */
+ if (LogLevel > 3)
+ sm_syslog(LOG_WARNING, NOQID,
+ "Unsupported address family %d: %.100s",
+ sa->sa.sa_family, anynet_ntoa(sa));
+ return -1;
}
if (hp == NULL)
@@ -4798,16 +4498,16 @@ add_hostnames(sa)
!(sa->sa.sa_family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) &&
#endif /* NETINET6 */
- TRUE)
+ true)
sm_syslog(LOG_WARNING, NOQID,
- "gethostbyaddr(%.100s) failed: %d\n",
- anynet_ntoa(sa),
+ "gethostbyaddr(%.100s) failed: %d",
+ anynet_ntoa(sa),
#if NAMED_BIND
- h_errno
+ h_errno
#else /* NAMED_BIND */
- -1
+ -1
#endif /* NAMED_BIND */
- );
+ );
errno = save_errno;
return -1;
}
@@ -4817,16 +4517,16 @@ add_hostnames(sa)
{
setclass('w', (char *) hp->h_name);
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", hp->h_name);
+ sm_dprintf("\ta.k.a.: %s\n", hp->h_name);
- if (snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb
+ if (sm_snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb
&& !wordinclass((char *) hnb, 'w'))
setclass('w', hnb);
}
else
{
if (tTd(0, 43))
- dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
+ sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name);
}
/* save all it aliases name */
@@ -4836,8 +4536,8 @@ add_hostnames(sa)
{
setclass('w', *ha);
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", *ha);
- if (snprintf(hnb, sizeof hnb,
+ sm_dprintf("\ta.k.a.: %s\n", *ha);
+ if (sm_snprintf(hnb, sizeof hnb,
"[%s]", *ha) < sizeof hnb &&
!wordinclass((char *) hnb, 'w'))
setclass('w', hnb);
@@ -4845,16 +4545,16 @@ add_hostnames(sa)
else
{
if (tTd(0, 43))
- dprintf("\ta.k.a.: %s (already in $=w)\n",
+ sm_dprintf("\ta.k.a.: %s (already in $=w)\n",
*ha);
}
}
-#if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
freehostent(hp);
-#endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
return 0;
}
- /*
+/*
** LOAD_IF_NAMES -- load interface-specific names into $=w
**
** Parameters:
@@ -4886,36 +4586,63 @@ struct mbuf;
void
load_if_names()
{
-#if NETINET6 && defined(SIOCGLIFCONF)
+# if NETINET6 && defined(SIOCGLIFCONF)
+# ifdef __hpux
+
+ /*
+ ** Unfortunately, HP has changed all of the structures,
+ ** making life difficult for implementors.
+ */
+
+# define lifconf if_laddrconf
+# define lifc_len iflc_len
+# define lifc_buf iflc_buf
+# define lifreq if_laddrreq
+# define lifr_addr iflr_addr
+# define lifr_name iflr_name
+# define lifr_flags iflr_flags
+# define ss_family sa_family
+# undef SIOCGLIFNUM
+# endif /* __hpux */
+
int s;
int i;
+ size_t len;
+ int numifs;
+ char *buf;
struct lifconf lifc;
+# ifdef SIOCGLIFNUM
struct lifnum lifn;
- int numifs;
+# endif /* SIOCGLIFNUM */
s = socket(InetMode, SOCK_DGRAM, 0);
if (s == -1)
return;
/* get the list of known IP address from the kernel */
-# ifdef SIOCGLIFNUM
+# ifdef __hpux
+ i = ioctl(s, SIOCGIFNUM, (char *) &numifs);
+# endif /* __hpux */
+# ifdef SIOCGLIFNUM
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = 0;
- if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
+ i = ioctl(s, SIOCGLIFNUM, (char *)&lifn);
+ numifs = lifn.lifn_count;
+# endif /* SIOCGLIFNUM */
+
+# if defined(__hpux) || defined(SIOCGLIFNUM)
+ if (i < 0)
{
/* can't get number of interfaces -- fall back */
if (tTd(0, 4))
- dprintf("SIOCGLIFNUM failed: %s\n", errstring(errno));
+ sm_dprintf("SIOCGLIFNUM failed: %s\n",
+ sm_errstring(errno));
numifs = -1;
}
- else
- {
- numifs = lifn.lifn_count;
- if (tTd(0, 42))
- dprintf("system has %d interfaces\n", numifs);
- }
+ else if (tTd(0, 42))
+ sm_dprintf("system has %d interfaces\n", numifs);
if (numifs < 0)
-# endif /* SIOCGLIFNUM */
+# endif /* defined(__hpux) || defined(SIOCGLIFNUM) */
numifs = MAXINTERFACES;
if (numifs <= 0)
@@ -4923,37 +4650,43 @@ load_if_names()
(void) close(s);
return;
}
- lifc.lifc_len = numifs * sizeof (struct lifreq);
- lifc.lifc_buf = xalloc(lifc.lifc_len);
+
+ len = lifc.lifc_len = numifs * sizeof (struct lifreq);
+ buf = lifc.lifc_buf = xalloc(lifc.lifc_len);
+# ifndef __hpux
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = 0;
+# endif /* __hpux */
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
{
if (tTd(0, 4))
- dprintf("SIOCGLIFCONF failed: %s\n", errstring(errno));
+ sm_dprintf("SIOCGLIFCONF failed: %s\n",
+ sm_errstring(errno));
(void) close(s);
- sm_free(lifc.lifc_buf);
+ sm_free(buf);
return;
}
/* scan the list of IP address */
if (tTd(0, 40))
- dprintf("scanning for interface specific names, lifc_len=%d\n",
- lifc.lifc_len);
+ sm_dprintf("scanning for interface specific names, lifc_len=%ld\n",
+ (long) len);
- for (i = 0; i < lifc.lifc_len; )
+ for (i = 0; i < len && i >= 0; )
{
- struct lifreq *ifr = (struct lifreq *)&lifc.lifc_buf[i];
+ int flags;
+ struct lifreq *ifr = (struct lifreq *)&buf[i];
SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr;
+ int af = ifr->lifr_addr.ss_family;
char *addr;
+ char *name;
struct in6_addr ia6;
struct in_addr ia;
-# ifdef SIOCGLIFFLAGS
+# ifdef SIOCGLIFFLAGS
struct lifreq ifrf;
-# endif /* SIOCGLIFFLAGS */
+# endif /* SIOCGLIFFLAGS */
char ip_addr[256];
char buf6[INET6_ADDRSTRLEN];
- int af = ifr->lifr_addr.ss_family;
/*
** We must close and recreate the socket each time
@@ -4966,7 +4699,7 @@ load_if_names()
s = socket(af, SOCK_DGRAM, 0);
if (s == -1)
{
- sm_free(lifc.lifc_buf);
+ sm_free(buf); /* XXX */
return;
}
@@ -4975,40 +4708,43 @@ load_if_names()
** don't try to use it.
*/
- if ((lifc.lifc_len - i) < sizeof *ifr)
+ if ((len - i) < sizeof *ifr)
break;
-# ifdef BSD4_4_SOCKADDR
+# ifdef BSD4_4_SOCKADDR
if (sa->sa.sa_len > sizeof ifr->lifr_addr)
i += sizeof ifr->lifr_name + sa->sa.sa_len;
else
-# endif /* BSD4_4_SOCKADDR */
+# endif /* BSD4_4_SOCKADDR */
i += sizeof *ifr;
if (tTd(0, 20))
- dprintf("%s\n", anynet_ntoa(sa));
+ sm_dprintf("%s\n", anynet_ntoa(sa));
if (af != AF_INET && af != AF_INET6)
continue;
-# ifdef SIOCGLIFFLAGS
+# ifdef SIOCGLIFFLAGS
memset(&ifrf, '\0', sizeof(struct lifreq));
- (void) strlcpy(ifrf.lifr_name, ifr->lifr_name,
- sizeof(ifrf.lifr_name));
+ (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name,
+ sizeof(ifrf.lifr_name));
if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0)
{
if (tTd(0, 4))
- dprintf("SIOCGLIFFLAGS failed: %s\n",
- errstring(errno));
+ sm_dprintf("SIOCGLIFFLAGS failed: %s\n",
+ sm_errstring(errno));
continue;
}
- else if (tTd(0, 41))
- dprintf("\tflags: %lx\n",
- (unsigned long)ifrf.lifr_flags);
- if (!bitset(IFF_UP, ifrf.lifr_flags))
+ name = ifr->lifr_name;
+ flags = ifrf.lifr_flags;
+
+ if (tTd(0, 41))
+ sm_dprintf("\tflags: %lx\n", (unsigned long) flags);
+
+ if (!bitset(IFF_UP, flags))
continue;
-# endif /* SIOCGLIFFLAGS */
+# endif /* SIOCGLIFFLAGS */
ip_addr[0] = '\0';
@@ -5035,17 +4771,17 @@ load_if_names()
{
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
message("WARNING: interface %s is UP with %s address",
- ifr->lifr_name,
- addr == NULL ? "(NULL)" : addr);
+ name, addr == NULL ? "(NULL)" : addr);
continue;
}
/* save IP address in text from */
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
if (addr != NULL)
- (void) snprintf(ip_addr, sizeof ip_addr,
- "[%.*s]",
- (int) sizeof ip_addr - 3, addr);
+ (void) sm_snprintf(ip_addr, sizeof ip_addr,
+ "[%.*s]",
+ (int) sizeof ip_addr - 3,
+ addr);
break;
case AF_INET:
@@ -5054,12 +4790,12 @@ load_if_names()
ia.s_addr == INADDR_NONE)
{
message("WARNING: interface %s is UP with %s address",
- ifr->lifr_name, inet_ntoa(ia));
+ name, inet_ntoa(ia));
continue;
}
/* save IP address in text from */
- (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
+ (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
(int) sizeof ip_addr - 3, inet_ntoa(ia));
break;
}
@@ -5071,20 +4807,21 @@ load_if_names()
{
setclass('w', ip_addr);
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", ip_addr);
+ sm_dprintf("\ta.k.a.: %s\n", ip_addr);
}
-# ifdef SIOCGLIFFLAGS
+# ifdef SIOCGLIFFLAGS
/* skip "loopback" interface "lo" */
- if (bitset(IFF_LOOPBACK, ifrf.lifr_flags))
+ if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
+ bitset(IFF_LOOPBACK, flags))
continue;
-# endif /* SIOCGLIFFLAGS */
+# endif /* SIOCGLIFFLAGS */
(void) add_hostnames(sa);
}
- sm_free(lifc.lifc_buf);
+ sm_free(buf); /* XXX */
(void) close(s);
-#else /* NETINET6 && defined(SIOCGLIFCONF) */
-# if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
+# else /* NETINET6 && defined(SIOCGLIFCONF) */
+# if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
int s;
int i;
struct ifconf ifc;
@@ -5095,18 +4832,19 @@ load_if_names()
return;
/* get the list of known IP address from the kernel */
-# if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
+# if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
{
/* can't get number of interfaces -- fall back */
if (tTd(0, 4))
- dprintf("SIOCGIFNUM failed: %s\n", errstring(errno));
+ sm_dprintf("SIOCGIFNUM failed: %s\n",
+ sm_errstring(errno));
numifs = -1;
}
else if (tTd(0, 42))
- dprintf("system has %d interfaces\n", numifs);
+ sm_dprintf("system has %d interfaces\n", numifs);
if (numifs < 0)
-# endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
+# endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */
numifs = MAXINTERFACES;
if (numifs <= 0)
@@ -5119,18 +4857,18 @@ load_if_names()
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
{
if (tTd(0, 4))
- dprintf("SIOCGIFCONF failed: %s\n", errstring(errno));
+ sm_dprintf("SIOCGIFCONF failed: %s\n",
+ sm_errstring(errno));
(void) close(s);
- sm_free(ifc.ifc_buf);
return;
}
/* scan the list of IP address */
if (tTd(0, 40))
- dprintf("scanning for interface specific names, ifc_len=%d\n",
+ sm_dprintf("scanning for interface specific names, ifc_len=%d\n",
ifc.ifc_len);
- for (i = 0; i < ifc.ifc_len; )
+ for (i = 0; i < ifc.ifc_len && i >= 0; )
{
int af;
struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
@@ -5164,7 +4902,7 @@ load_if_names()
i += sizeof *ifr;
if (tTd(0, 20))
- dprintf("%s\n", anynet_ntoa(sa));
+ sm_dprintf("%s\n", anynet_ntoa(sa));
af = ifr->ifr_addr.sa_family;
if (af != AF_INET
@@ -5176,11 +4914,11 @@ load_if_names()
# ifdef SIOCGIFFLAGS
memset(&ifrf, '\0', sizeof(struct ifreq));
- (void) strlcpy(ifrf.ifr_name, ifr->ifr_name,
+ (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name,
sizeof(ifrf.ifr_name));
(void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
if (tTd(0, 41))
- dprintf("\tflags: %lx\n",
+ sm_dprintf("\tflags: %lx\n",
(unsigned long) ifrf.ifr_flags);
# define IFRFREF ifrf
# else /* SIOCGIFFLAGS */
@@ -5206,7 +4944,7 @@ load_if_names()
}
/* save IP address in text from */
- (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
+ (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
(int) sizeof ip_addr - 3,
inet_ntoa(ia));
break;
@@ -5240,9 +4978,10 @@ load_if_names()
/* save IP address in text from */
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
if (addr != NULL)
- (void) snprintf(ip_addr, sizeof ip_addr,
- "[%.*s]",
- (int) sizeof ip_addr - 3, addr);
+ (void) sm_snprintf(ip_addr, sizeof ip_addr,
+ "[%.*s]",
+ (int) sizeof ip_addr - 3,
+ addr);
break;
# endif /* NETINET6 */
@@ -5255,30 +4994,31 @@ load_if_names()
{
setclass('w', ip_addr);
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", ip_addr);
+ sm_dprintf("\ta.k.a.: %s\n", ip_addr);
}
/* skip "loopback" interface "lo" */
- if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
+ if (DontProbeInterfaces == DPI_SKIPLOOPBACK &&
+ bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
continue;
(void) add_hostnames(sa);
}
- sm_free(ifc.ifc_buf);
+ sm_free(ifc.ifc_buf); /* XXX */
(void) close(s);
-# undef IFRFREF
-# endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
-#endif /* NETINET6 && defined(SIOCGLIFCONF) */
+# undef IFRFREF
+# endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */
+# endif /* NETINET6 && defined(SIOCGLIFCONF) */
}
- /*
+/*
** ISLOOPBACK -- is socket address in the loopback net?
**
** Parameters:
** sa -- socket address.
**
** Returns:
-** TRUE -- is socket address in the loopback net?
-** FALSE -- otherwise
+** true -- is socket address in the loopback net?
+** false -- otherwise
**
*/
@@ -5288,16 +5028,16 @@ isloopback(sa)
{
#if NETINET6
if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr))
- return TRUE;
+ return true;
#else /* NETINET6 */
/* XXX how to correctly extract IN_LOOPBACKNET part? */
if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET)
>> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
- return TRUE;
+ return true;
#endif /* NETINET6 */
- return FALSE;
+ return false;
}
- /*
+/*
** GET_NUM_PROCS_ONLINE -- return the number of processors currently online
**
** Parameters:
@@ -5321,7 +5061,7 @@ get_num_procs_online()
mib[1] = HW_NCPU;
sz = (size_t) sizeof nproc;
(void) sysctl(mib, 2, &nproc, &sz, NULL, 0);
-# endif /* defined(CTL_HW) && defined(HW_NCPUS) */
+# endif /* defined(CTL_HW) && defined(HW_NCPU) */
#else /* USESYSCTL */
# ifdef _SC_NPROCESSORS_ONLN
nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
@@ -5340,7 +5080,7 @@ get_num_procs_online()
nproc = 1;
return nproc;
}
- /*
+/*
** SEED_RANDOM -- seed the random number generator
**
** Parameters:
@@ -5359,7 +5099,7 @@ seed_random()
long seed;
struct timeval t;
- seed = (long) getpid();
+ seed = (long) CurrentPid;
if (gettimeofday(&t, NULL) >= 0)
seed += t.tv_sec + t.tv_usec;
@@ -5370,7 +5110,7 @@ seed_random()
# endif /* HASRANDOM */
#endif /* HASSRANDOMDEV */
}
- /*
+/*
** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
**
** Parameters:
@@ -5402,17 +5142,23 @@ sm_syslog(level, id, fmt, va_alist)
int seq = 1;
int idlen;
char buf0[MAXLINE];
- extern int SnprfOverflow;
- extern int SyslogErrno;
- extern char *DoprEnd;
- VA_LOCAL_DECL
+ char *newstring;
+ extern int SyslogPrefixLen;
+ SM_VA_LOCAL_DECL
- save_errno = SyslogErrno = errno;
+ save_errno = errno;
if (id == NULL)
+ {
id = "NOQUEUE";
+ idlen = strlen(id) + SyslogPrefixLen;
+ }
else if (strcmp(id, NOQID) == 0)
+ {
id = "";
- idlen = strlen(id);
+ idlen = SyslogPrefixLen;
+ }
+ else
+ idlen = strlen(id) + SyslogPrefixLen;
if (buf == NULL)
{
@@ -5422,38 +5168,43 @@ sm_syslog(level, id, fmt, va_alist)
for (;;)
{
- /* do a virtual vsnprintf into buf */
- VA_START(fmt);
- buf[0] = 0;
- DoprEnd = buf + bufsize - 1;
- SnprfOverflow = 0;
- sm_dopr(buf, fmt, ap);
- *DoprEnd = '\0';
- VA_END;
- /* end of virtual vsnprintf */
-
- if (SnprfOverflow == 0)
+ int n;
+
+ /* print log message into buf */
+ SM_VA_START(ap, fmt);
+ n = sm_vsnprintf(buf, bufsize, fmt, ap);
+ SM_VA_END(ap);
+ SM_ASSERT(n > 0);
+ if (n < bufsize)
break;
/* String too small, redo with correct size */
- bufsize += SnprfOverflow + 1;
+ bufsize = n + 1;
if (buf != buf0)
+ {
sm_free(buf);
- buf = xalloc(bufsize * sizeof (char));
+ buf = NULL;
+ }
+ buf = sm_malloc_x(bufsize);
}
- if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
+
+ /* clean up buf after it has been expanded with args */
+ newstring = str2prt(buf);
+ if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE)
{
#if LOG
if (*id == '\0')
- syslog(level, "%s", buf);
+ syslog(level, "%s", newstring);
else
- syslog(level, "%s: %s", id, buf);
+ syslog(level, "%s: %s", id, newstring);
#else /* LOG */
/*XXX should do something more sensible */
if (*id == '\0')
- fprintf(stderr, "%s\n", buf);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
+ newstring);
else
- fprintf(stderr, "%s: %s\n", id, buf);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s\n", id, newstring);
#endif /* LOG */
if (buf == buf0)
buf = NULL;
@@ -5461,18 +5212,26 @@ sm_syslog(level, id, fmt, va_alist)
return;
}
- begin = buf;
+/*
+** additional length for splitting: " ..." + 3, where 3 is magic to
+** have some data for the next entry.
+*/
+
+#define SL_SPLIT 7
+
+ begin = newstring;
+ idlen += 5; /* strlen("[999]"), see below */
while (*begin != '\0' &&
- (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
+ (strlen(begin) + idlen) > SYSLOG_BUFSIZE)
{
char save;
- if (seq == 999)
+ if (seq >= 999)
{
/* Too many messages */
break;
}
- end = begin + SYSLOG_BUFSIZE - idlen - 12;
+ end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
while (end > begin)
{
/* Break on comma or space */
@@ -5485,36 +5244,38 @@ sm_syslog(level, id, fmt, va_alist)
}
/* No separator, break midstring... */
if (end == begin)
- end = begin + SYSLOG_BUFSIZE - idlen - 12;
+ end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT;
save = *end;
*end = 0;
#if LOG
syslog(level, "%s[%d]: %s ...", id, seq++, begin);
#else /* LOG */
- fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s[%d]: %s ...\n", id, seq++, begin);
#endif /* LOG */
*end = save;
begin = end;
}
- if (seq == 999)
+ if (seq >= 999)
#if LOG
syslog(level, "%s[%d]: log terminated, too many parts",
id, seq);
#else /* LOG */
- fprintf(stderr, "%s[%d]: log terminated, too many parts\n",
- id, seq);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s[%d]: log terminated, too many parts\n", id, seq);
#endif /* LOG */
else if (*begin != '\0')
#if LOG
syslog(level, "%s[%d]: %s", id, seq, begin);
#else /* LOG */
- fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s[%d]: %s\n", id, seq, begin);
#endif /* LOG */
if (buf == buf0)
buf = NULL;
errno = save_errno;
}
- /*
+/*
** HARD_SYSLOG -- call syslog repeatedly until it works
**
** Needed on HP-UX, which apparently doesn't guarantee that
@@ -5545,11 +5306,11 @@ hard_syslog(pri, msg, va_alist)
{
int i;
char buf[SYSLOG_BUFSIZE];
- VA_LOCAL_DECL;
+ SM_VA_LOCAL_DECL
- VA_START(msg);
- vsnprintf(buf, sizeof buf, msg, ap);
- VA_END;
+ SM_VA_START(ap, msg);
+ (void) sm_vsnprintf(buf, sizeof buf, msg, ap);
+ SM_VA_END(ap);
for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
continue;
@@ -5558,7 +5319,7 @@ hard_syslog(pri, msg, va_alist)
# undef CAST
#endif /* defined(__hpux) && !defined(HPUX11) */
#if NEEDLOCAL_HOSTNAME_LENGTH
- /*
+/*
** LOCAL_HOSTNAME_LENGTH
**
** This is required to get sendmail to compile against BIND 4.9.x
@@ -5573,14 +5334,14 @@ int
local_hostname_length(hostname)
char *hostname;
{
- int len_host, len_domain;
+ size_t len_host, len_domain;
if (!*_res.defdname)
res_init();
len_host = strlen(hostname);
len_domain = strlen(_res.defdname);
if (len_host > len_domain &&
- (strcasecmp(hostname + len_host - len_domain,
+ (sm_strcasecmp(hostname + len_host - len_domain,
_res.defdname) == 0) &&
hostname[len_host - len_domain - 1] == '.')
return len_host - len_domain - 1;
@@ -5589,36 +5350,150 @@ local_hostname_length(hostname)
}
#endif /* NEEDLOCAL_HOSTNAME_LENGTH */
- /*
+#if NEEDLINK
+/*
+** LINK -- clone a file
+**
+** Some OS's lacks link() and hard links. Since sendmail is using
+** link() as an efficient way to clone files, this implementation
+** will simply do a file copy.
+**
+** NOTE: This link() replacement is not a generic replacement as it
+** does not handle all of the semantics of the real link(2).
+**
+** Parameters:
+** source -- pathname of existing file.
+** target -- pathname of link (clone) to be created.
+**
+** Returns:
+** 0 -- success.
+** -1 -- failure, see errno for details.
+*/
+
+int
+link(source, target)
+ const char *source;
+ const char *target;
+{
+ int save_errno;
+ int sff;
+ int src = -1, dst = -1;
+ ssize_t readlen;
+ ssize_t writelen;
+ char buf[BUFSIZ];
+ struct stat st;
+
+ sff = SFF_REGONLY|SFF_OPENASROOT;
+ if (DontLockReadFiles)
+ sff |= SFF_NOLOCK;
+
+ /* Open the original file */
+ src = safeopen((char *)source, O_RDONLY, 0, sff);
+ if (src < 0)
+ goto fail;
+
+ /* Obtain the size and the mode */
+ if (fstat(src, &st) < 0)
+ goto fail;
+
+ /* Create the duplicate copy */
+ sff &= ~SFF_NOLOCK;
+ sff |= SFF_CREAT;
+ dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY,
+ st.st_mode, sff);
+ if (dst < 0)
+ goto fail;
+
+ /* Copy all of the bytes one buffer at a time */
+ while ((readlen = read(src, &buf, sizeof(buf))) > 0)
+ {
+ ssize_t left = readlen;
+ char *p = buf;
+
+ while (left > 0 &&
+ (writelen = write(dst, p, (size_t) left)) >= 0)
+ {
+ left -= writelen;
+ p += writelen;
+ }
+ if (writeln < 0)
+ break;
+ }
+
+ /* Any trouble reading? */
+ if (readlen < 0 || writelen < 0)
+ goto fail;
+
+ /* Close the input file */
+ if (close(src) < 0)
+ {
+ src = -1;
+ goto fail;
+ }
+ src = -1;
+
+ /* Close the output file */
+ if (close(dst) < 0)
+ {
+ /* don't set dst = -1 here so we unlink the file */
+ goto fail;
+ }
+
+ /* Success */
+ return 0;
+
+ fail:
+ save_errno = errno;
+ if (src >= 0)
+ (void) close(src);
+ if (dst >= 0)
+ {
+ (void) unlink(target);
+ (void) close(dst);
+ }
+ errno = save_errno;
+ return -1;
+}
+#endif /* NEEDLINK */
+
+/*
** Compile-Time options
*/
char *CompileOptions[] =
{
+#if NAMED_BIND
+# if DNSMAP
+ "DNSMAP",
+# endif /* DNSMAP */
+#endif /* NAMED_BIND */
#if EGD
"EGD",
#endif /* EGD */
-#ifdef HESIOD
+#if HESIOD
"HESIOD",
#endif /* HESIOD */
#if HES_GETMAILHOST
"HES_GETMAILHOST",
#endif /* HES_GETMAILHOST */
-#ifdef LDAPMAP
+#if LDAPMAP
"LDAPMAP",
#endif /* LDAPMAP */
-#ifdef MAP_NSD
+#if LOG
+ "LOG",
+#endif /* LOG */
+#if MAP_NSD
"MAP_NSD",
#endif /* MAP_NSD */
-#ifdef MAP_REGEX
+#if MAP_REGEX
"MAP_REGEX",
#endif /* MAP_REGEX */
-#if LOG
- "LOG",
-#endif /* LOG */
#if MATCHGECOS
"MATCHGECOS",
#endif /* MATCHGECOS */
+#if MILTER
+ "MILTER",
+#endif /* MILTER */
#if MIME7TO8
"MIME7TO8",
#endif /* MIME7TO8 */
@@ -5628,7 +5503,7 @@ char *CompileOptions[] =
#if NAMED_BIND
"NAMED_BIND",
#endif /* NAMED_BIND */
-#ifdef NDBM
+#if NDBM
"NDBM",
#endif /* NDBM */
#if NETINET
@@ -5652,52 +5527,58 @@ char *CompileOptions[] =
#if NETX25
"NETX25",
#endif /* NETX25 */
-#ifdef NEWDB
+#if NEWDB
"NEWDB",
#endif /* NEWDB */
-#ifdef NIS
+#if NIS
"NIS",
#endif /* NIS */
-#ifdef NISPLUS
+#if NISPLUS
"NISPLUS",
#endif /* NISPLUS */
-#ifdef PH_MAP
+#if NO_DH
+ "NO_DH",
+#endif /* NO_DH */
+#if PH_MAP
"PH_MAP",
#endif /* PH_MAP */
-#if QUEUE
- "QUEUE",
-#endif /* QUEUE */
+#ifdef PICKY_HELO_CHECK
+ "PICKY_HELO_CHECK",
+#endif /* PICKY_HELO_CHECK */
+#if PIPELINING
+ "PIPELINING",
+#endif /* PIPELINING */
#if SASL
"SASL",
#endif /* SASL */
#if SCANF
"SCANF",
#endif /* SCANF */
-#if SFIO
- "SFIO",
-#endif /* SFIO */
-#if SMTP
- "SMTP",
-#endif /* SMTP */
#if SMTPDEBUG
"SMTPDEBUG",
#endif /* SMTPDEBUG */
#if STARTTLS
"STARTTLS",
#endif /* STARTTLS */
-#ifdef SUID_ROOT_FILES_OK
+#if SUID_ROOT_FILES_OK
"SUID_ROOT_FILES_OK",
#endif /* SUID_ROOT_FILES_OK */
#if TCPWRAPPERS
"TCPWRAPPERS",
#endif /* TCPWRAPPERS */
+#if TLS_NO_RSA
+ "TLS_NO_RSA",
+#endif /* TLS_NO_RSA */
+#if TLS_VRFY_PER_CTX
+ "TLS_VRFY_PER_CTX",
+#endif /* TLS_VRFY_PER_CTX */
#if USERDB
"USERDB",
#endif /* USERDB */
#if XDEBUG
"XDEBUG",
#endif /* XDEBUG */
-#ifdef XLA
+#if XLA
"XLA",
#endif /* XLA */
NULL
@@ -5710,9 +5591,27 @@ char *CompileOptions[] =
char *OsCompileOptions[] =
{
+#if ADDRCONFIG_IS_BROKEN
+ "ADDRCONFIG_IS_BROKEN",
+#endif /* ADDRCONFIG_IS_BROKEN */
+#ifdef AUTO_NETINFO_HOSTS
+ "AUTO_NETINFO_HOSTS",
+#endif /* AUTO_NETINFO_HOSTS */
+#ifdef AUTO_NIS_ALIASES
+ "AUTO_NIS_ALIASES",
+#endif /* AUTO_NIS_ALIASES */
+#if BROKEN_RES_SEARCH
+ "BROKEN_RES_SEARCH",
+#endif /* BROKEN_RES_SEARCH */
+#ifdef BSD4_4_SOCKADDR
+ "BSD4_4_SOCKADDR",
+#endif /* BSD4_4_SOCKADDR */
#if BOGUS_O_EXCL
"BOGUS_O_EXCL",
#endif /* BOGUS_O_EXCL */
+#if DEC_OSF_BROKEN_GETPWENT
+ "DEC_OSF_BROKEN_GETPWENT",
+#endif /* DEC_OSF_BROKEN_GETPWENT */
#if FAST_PID_RECYCLE
"FAST_PID_RECYCLE",
#endif /* FAST_PID_RECYCLE */
@@ -5737,12 +5636,27 @@ char *OsCompileOptions[] =
#if HASLSTAT
"HASLSTAT",
#endif /* HASLSTAT */
+#if HASNICE
+ "HASNICE",
+#endif /* HASNICE */
#if HASRANDOM
"HASRANDOM",
#endif /* HASRANDOM */
+#if HASRRESVPORT
+ "HASRRESVPORT",
+#endif /* HASRRESVPORT */
+#if HASSETEGID
+ "HASSETEGID",
+#endif /* HASSETEGID */
#if HASSETLOGIN
"HASSETLOGIN",
#endif /* HASSETLOGIN */
+#if HASSETREGID
+ "HASSETREGID",
+#endif /* HASSETREGID */
+#if HASSETRESGID
+ "HASSETRESGID",
+#endif /* HASSETRESGID */
#if HASSETREUID
"HASSETREUID",
#endif /* HASSETREUID */
@@ -5758,9 +5672,6 @@ char *OsCompileOptions[] =
#if HASSETVBUF
"HASSETVBUF",
#endif /* HASSETVBUF */
-#if HASSNPRINTF
- "HASSNPRINTF",
-#endif /* HASSNPRINTF */
#if HAS_ST_GEN
"HAS_ST_GEN",
#endif /* HAS_ST_GEN */
@@ -5797,9 +5708,30 @@ char *OsCompileOptions[] =
#if NEEDFSYNC
"NEEDFSYNC",
#endif /* NEEDFSYNC */
+#if NEEDLINK
+ "NEEDLINK",
+#endif /* NEEDLINK */
+#if NEEDLOCAL_HOSTNAME_LENGTH
+ "NEEDLOCAL_HOSTNAME_LENGTH",
+#endif /* NEEDLOCAL_HOSTNAME_LENGTH */
+#if NEEDSGETIPNODE
+ "NEEDSGETIPNODE",
+#endif /* NEEDSGETIPNODE */
+#if NEEDSTRSTR
+ "NEEDSTRSTR",
+#endif /* NEEDSTRSTR */
+#if NEEDSTRTOL
+ "NEEDSTRTOL",
+#endif /* NEEDSTRTOL */
+#ifdef NO_GETSERVBYNAME
+ "NO_GETSERVBYNAME",
+#endif /* NO_GETSERVBYNAME */
#if NOFTRUNCATE
"NOFTRUNCATE",
#endif /* NOFTRUNCATE */
+#if REQUIRES_DIR_FSYNC
+ "REQUIRES_DIR_FSYNC",
+#endif /* REQUIRES_DIR_FSYNC */
#if RLIMIT_NEEDS_SYS_TIME_H
"RLIMIT_NEEDS_SYS_TIME_H",
#endif /* RLIMIT_NEEDS_SYS_TIME_H */
@@ -5830,15 +5762,167 @@ char *OsCompileOptions[] =
#if SYSTEM5
"SYSTEM5",
#endif /* SYSTEM5 */
+#if USE_DOUBLE_FORK
+ "USE_DOUBLE_FORK",
+#endif /* USE_DOUBLE_FORK */
+#if USE_ENVIRON
+ "USE_ENVIRON",
+#endif /* USE_ENVIRON */
#if USE_SA_SIGACTION
"USE_SA_SIGACTION",
#endif /* USE_SA_SIGACTION */
#if USE_SIGLONGJMP
"USE_SIGLONGJMP",
#endif /* USE_SIGLONGJMP */
+#if USEGETCONFATTR
+ "USEGETCONFATTR",
+#endif /* USEGETCONFATTR */
#if USESETEUID
"USESETEUID",
#endif /* USESETEUID */
+#ifdef USESYSCTL
+ "USESYSCTL",
+#endif /* USESYSCTL */
+#if USING_NETSCAPE_LDAP
+ "USING_NETSCAPE_LDAP",
+#endif /* USING_NETSCAPE_LDAP */
+#ifdef WAITUNION
+ "WAITUNION",
+#endif /* WAITUNION */
+ NULL
+};
+
+/*
+** FFR compile options.
+*/
+
+char *FFRCompileOptions[] =
+{
+#if _FFR_ADAPTIVE_EOL
+ "_FFR_ADAPTIVE_EOL",
+#endif /* _FFR_ADAPTIVE_EOL */
+#if _FFR_ALLOW_SASLINFO
+ "_FFR_ALLOW_SASLINFO",
+#endif /* _FFR_ALLOW_SASLINFO */
+#if _FFR_BESTMX_BETTER_TRUNCATION
+ "_FFR_BESTMX_BETTER_TRUNCATION",
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+#if _FFR_CACHE_LPC
+/* Christophe Wolfhugel of France Telecom Oleane */
+ "_FFR_CACHE_LPC",
+#endif /* _FFR_CACHE_LPC */
+#if _FFR_CATCH_BROKEN_MTAS
+ "_FFR_CATCH_BROKEN_MTAS",
+#endif /* _FFR_CATCH_BROKEN_MTAS */
+#if _FFR_CHECK_EOM
+ "_FFR_CHECK_EOM",
+#endif /* _FFR_CHECK_EOM */
+#if _FFR_CONTROL_MSTAT
+ "_FFR_CONTROL_MSTAT",
+#endif /* _FFR_CONTROL_MSTAT */
+#if _FFR_DAEMON_NETUNIX
+ "_FFR_DAEMON_NETUNIX",
+#endif /* _FFR_DAEMON_NETUNIX */
+#if _FFR_DEPRECATE_MAILER_FLAG_I
+ "_FFR_DEPRECATE_MAILER_FLAG_I",
+#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
+#if _FFR_DNSMAP_BASE
+ "_FFR_DNSMAP_BASE",
+#endif /* _FFR_DNSMAP_BASE */
+#if _FFR_DNSMAP_MULTI
+ "_FFR_DNSMAP_MULTI",
+# if _FFR_DNSMAP_MULTILIMIT
+ "_FFR_DNSMAP_MULTILIMIT",
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+#endif /* _FFR_DNSMAP_MULTI */
+#if _FFR_DONTLOCKFILESFORREAD_OPTION
+ "_FFR_DONTLOCKFILESFORREAD_OPTION",
+#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */
+#if _FFR_DOTTED_USERNAMES
+ "_FFR_DOTTED_USERNAMES",
+#endif /* _FFR_DOTTED_USERNAMES */
+#if _FFR_DROP_TRUSTUSER_WARNING
+ "_FFR_DROP_TRUSTUSER_WARNING",
+#endif /* _FFR_DROP_TRUSTUSER_WARNING */
+#if _FFR_FIX_DASHT
+ "_FFR_FIX_DASHT",
+#endif /* _FFR_FIX_DASHT */
+#if _FFR_FORWARD_SYSERR
+ "_FFR_FORWARD_SYSERR",
+#endif /* _FFR_FORWARD_SYSERR */
+#if _FFR_GEN_ORCPT
+ "_FFR_GEN_ORCPT",
+#endif /* _FFR_GEN_ORCPT */
+#if _FFR_GROUPREADABLEAUTHINFOFILE
+ "_FFR_GROUPREADABLEAUTHINFOFILE",
+#endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
+#if _FFR_HDR_TYPE
+ "_FFR_HDR_TYPE",
+#endif /* _FFR_HDR_TYPE */
+#if _FFR_HPUX_NSSWITCH
+ "_FFR_HPUX_NSSWITCH",
+#endif /* _FFR_HPUX_NSSWITCH */
+#if _FFR_IGNORE_EXT_ON_HELO
+ "_FFR_IGNORE_EXT_ON_HELO",
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
+#if _FFR_LDAP_RECURSION
+ "_FFR_LDAP_RECURSION",
+#endif /* _FFR_LDAP_RECURSION */
+#if _FFR_MAX_FORWARD_ENTRIES
+/* Randall S. Winchester of the University of Maryland */
+ "_FFR_MAX_FORWARD_ENTRIES",
+#endif /* _FFR_MAX_FORWARD_ENTRIES */
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+ "_FFR_MILTER_PERDAEMON",
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
+#if _FFR_NODELAYDSN_ON_HOLD
+/* Steven Pitzl */
+ "_FFR_NODELAYDSN_ON_HOLD",
+#endif /* _FFR_NODELAYDSN_ON_HOLD */
+#if _FFR_NO_PIPE
+ "_FFR_NO_PIPE",
+#endif /* _FFR_NO_PIPE */
+#if _FFR_QUARANTINE
+ "_FFR_QUARANTINE",
+#endif /* _FFR_QUARANTINE */
+#if _FFR_QUEUEDELAY
+ "_FFR_QUEUEDELAY",
+#endif /* _FFR_QUEUEDELAY */
+#if _FFR_QUEUE_MACRO
+ "_FFR_QUEUE_MACRO",
+#endif /* _FFR_QUEUE_MACRO */
+#if _FFR_QUEUE_SCHED_DBG
+ "_FFR_QUEUE_SCHED_DBG",
+#endif /* _FFR_QUEUE_SCHED_DBG */
+#if _FFR_REDIRECTEMPTY
+ "_FFR_REDIRECTEMPTY",
+#endif /* _FFR_REDIRECTEMPTY */
+#if _FFR_RESET_MACRO_GLOBALS
+ "_FFR_RESET_MACRO_GLOBALS",
+#endif /* _FFR_RESET_MACRO_GLOBALS */
+#if _FFR_RHS
+ "_FFR_RHS",
+#endif /* _FFR_RHS */
+#if _FFR_SHM_STATUS
+ "_FFR_SHM_STATUS",
+#endif /* _FFR_SHM_STATUS */
+#if _FFR_SMTP_SSL
+ "_FFR_SMTP_SSL",
+#endif /* _FFR_SMTP_SSL */
+#if _FFR_SOFT_BOUNCE
+ "_FFR_SOFT_BOUNCE",
+#endif /* _FFR_SOFT_BOUNCE */
+#if _FFR_TIMERS
+ "_FFR_TIMERS",
+#endif /* _FFR_TIMERS */
+#if _FFR_TLS_1
+ "_FFR_TLS_1",
+#endif /* _FFR_TLS_1 */
+#if _FFR_TRUSTED_QF
+ "_FFR_TRUSTED_QF",
+#endif /* _FFR_TRUSTED_QF */
NULL
};
diff --git a/contrib/sendmail/src/conf.h b/contrib/sendmail/src/conf.h
index 7957473..86a4b24 100644
--- a/contrib/sendmail/src/conf.h
+++ b/contrib/sendmail/src/conf.h
@@ -10,7 +10,7 @@
* the sendmail distribution.
*
*
- * $Id: conf.h,v 8.496.4.54 2001/07/31 22:30:24 gshapiro Exp $
+ * $Id: conf.h,v 8.557 2001/10/05 03:49:41 ca Exp $
*/
/*
@@ -29,9 +29,6 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
# include <sys/param.h>
# include <sys/types.h>
-# if SFIO && defined(SF_APPEND)
-# undef SF_APPEND /* Both sfio/stdio.h and sys/stat.h define it */
-# endif /* SFIO && defined(SF_APPEND) */
# include <sys/stat.h>
# ifndef __QNX__
/* in QNX this grabs bogus LOCK_* manifests */
@@ -59,6 +56,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
/**********************************************************************
** Table sizes, etc....
** There shouldn't be much need to change these....
+** If you do, be careful, none should be set anywhere near INT_MAX
**********************************************************************/
#define MAXLINE 2048 /* max line length */
@@ -72,19 +70,26 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#define MAXKEY 128 /* maximum size of a database key */
#define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */
#define MAXUSERENVIRON 100 /* max envars saved, must be >= 3 */
-#define MAXALIASDB 12 /* max # of alias databases */
#define MAXMAPSTACK 12 /* max # of stacked or sequenced maps */
-#if _FFR_MILTER
+#if MILTER
# define MAXFILTERS 25 /* max # of milter filters */
-# define MAXFILTERMACROS 50 /* max # of macros per milter cmd */
-#endif /* _FFR_MILTER */
+# define MAXFILTERMACROS 50 /* max # of macros per milter cmd */
+#endif /* MILTER */
#define MAXSMTPARGS 20 /* max # of ESMTP args for MAIL/RCPT */
#define MAXTOCLASS 8 /* max # of message timeout classes */
#define MAXRESTOTYPES 3 /* max # of resolver timeout types */
#define MAXMIMEARGS 20 /* max args in Content-Type: */
#define MAXMIMENESTING 20 /* max MIME multipart nesting */
#define QUEUESEGSIZE 1000 /* increment for queue size */
-#define MAXQFNAME 21 /* max qf file name length */
+
+/*
+** MAXQFNAME == 2 (size of "qf", "df" prefix)
+** + 8 (base 60 encoded date, time & sequence number)
+** + 10 (base 10 encoded 32 bit process id)
+** + 1 (terminating NUL character).
+*/
+
+#define MAXQFNAME 21 /* max qf file name length + 1 */
#define MACBUFSIZE 4096 /* max expanded macro buffer size */
#define TOBUFSIZE SM_ARG_MAX /* max buffer to hold address list */
#define MAXSHORTSTR 203 /* max short string length */
@@ -102,28 +107,32 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
# define MAXSYMLINKS 32 /* max number of symlinks in a path */
#endif /* ! MAXSYMLINKS */
#define MAXLINKPATHLEN (MAXPATHLEN * MAXSYMLINKS) /* max link-expanded file */
-#define DATA_PROGRESS_TIMEOUT 300 /* how ofter to check DATA progress */
+#define DATA_PROGRESS_TIMEOUT 300 /* how often to check DATA progress */
#define ENHSCLEN 10 /* max len of enhanced status code */
-#if _FFR_DYNAMIC_TOBUF
-# define DEFAULT_MAX_RCPT 100 /* max number of RCPTs per envelope */
-#endif /* _FFR_DYNAMIC_TOBUF */
+#define DEFAULT_MAX_RCPT 100 /* max number of RCPTs per envelope */
+#define MAXQUEUEGROUPS 50 /* max # of queue groups */
+ /* must be less than BITMAPBITS for DoQueueRun */
+#define MAXWORKGROUPS 50 /* max # of work groups */
+#define MAXFILESYS BITMAPBITS /* max # of queue file systems
+ * must be <= BITMAPBITS */
+#ifndef FILESYS_UPDATE_INTERVAL
+# define FILESYS_UPDATE_INTERVAL 300 /* how often to update FileSys table */
+#endif /* FILESYS_UPDATE_INTERVAL */
+
+#ifndef SM_DEFAULT_TTL
+# define SM_DEFAULT_TTL 3600 /* default TTL for services that don't have one */
+#endif /* SM_DEFAULT_TTL */
#if SASL
# ifndef AUTH_MECHANISMS
-# if STARTTLS && _FFR_EXT_MECH
+# if STARTTLS
# define AUTH_MECHANISMS "EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
-# else /* STARTTLS && _FFR_EXT_MECH */
+# else /* STARTTLS */
# define AUTH_MECHANISMS "GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5"
-# endif /* STARTTLS && _FFR_EXT_MECH */
+# endif /* STARTTLS */
# endif /* ! AUTH_MECHANISMS */
#endif /* SASL */
-#ifdef LDAPMAP
-# define LDAPMAP_MAX_ATTR 64
-# define LDAPMAP_MAX_FILTER 1024
-# define LDAPMAP_MAX_PASSWD 256
-#endif /* LDAPMAP */
-
/**********************************************************************
** Compilation options.
** #define these to 1 if they are available;
@@ -171,2680 +180,20 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
# define MIME7TO8 1 /* 7->8 bit MIME conversions */
#endif /* ! MIME7TO8 */
-/**********************************************************************
-** "Hard" compilation options.
-** #define these if they are available; comment them out otherwise.
-** These cannot be overridden from the Makefile, and should really not
-** be turned off unless absolutely necessary.
-**********************************************************************/
+#if NAMED_BIND
+# ifndef DNSMAP
+# define DNSMAP 1 /* DNS map type */
+# endif /* ! DNSMAP */
+#endif /* NAMED_BIND */
-#define LOG 1 /* enable logging -- don't turn off */
+#ifndef PIPELINING
+# define PIPELINING 1 /* SMTP PIPELINING */
+#endif /* PIPELINING */
/**********************************************************************
** End of site-specific configuration.
**********************************************************************/
- /*
-** General "standard C" defines.
-**
-** These may be undone later, to cope with systems that claim to
-** be Standard C but aren't. Gcc is the biggest offender -- it
-** doesn't realize that the library is part of the language.
-**
-** Life would be much easier if we could get rid of this sort
-** of bozo problems.
-*/
-
-#ifdef __STDC__
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-#endif /* __STDC__ */
-
-/*
-** Assume you have standard calls; can be #undefed below if necessary.
-*/
-
-#ifndef HASLSTAT
-# define HASLSTAT 1 /* has lstat(2) call */
-#endif /* ! HASLSTAT */
- /**********************************************************************
-** Operating system configuration.
-**
-** Unless you are porting to a new OS, you shouldn't have to
-** change these.
-**********************************************************************/
-
-/*
-** HP-UX -- tested for 8.07, 9.00, and 9.01.
-**
-** If V4FS is defined, compile for HP-UX 10.0.
-** 11.x support from Richard Allen <ra@hp.is>.
-*/
-
-#ifdef __hpux
- /* common definitions for HP-UX 9.x and 10.x */
-# undef m_flags /* conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h on HP 300 */
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
-# define seteuid(e) setresuid(-1, e, -1)
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define LA_TYPE LA_HPUX
-# define SPT_TYPE SPT_PSTAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define GIDSET_T gid_t
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
-# endif /* ! HASGETUSERSHELL */
-# ifdef HPUX11
-# define HASFCHOWN 1 /* has fchown(2) */
-# define HASSNPRINTF 1 /* has snprintf(3) */
-# ifndef BROKEN_RES_SEARCH
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
-# endif /* ! BROKEN_RES_SEARCH */
-# else /* HPUX11 */
-# ifndef NOT_SENDMAIL
-# define syslog hard_syslog
-# endif /* ! NOT_SENDMAIL */
-# endif /* HPUX11 */
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-
-# ifdef V4FS
- /* HP-UX 10.x */
-# define _PATH_UNIX "/stand/vmunix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# ifndef IDENTPROTO
-# define IDENTPROTO 1 /* TCP/IP implementation fixed in 10.0 */
-# endif /* ! IDENTPROTO */
-# include <sys/mpctl.h> /* for mpctl() in get_num_procs_online() */
-# else /* V4FS */
- /* HP-UX 9.x */
-# define _PATH_UNIX "/hp-ux"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# ifdef __STDC__
-extern void hard_syslog(int, char *, ...);
-# else /* __STDC__ */
-extern void hard_syslog();
-# endif /* __STDC__ */
-# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
-# endif /* V4FS */
-
-#endif /* __hpux */
-
-
-/*
-** IBM AIX 4.x
-*/
-
-#ifdef _AIX4
-# define _AIX3 1 /* pull in AIX3 stuff */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define USESETEUID 1 /* seteuid(2) works */
-# define TZ_TYPE TZ_NAME /* use tzname[] vector */
-# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
-# if _AIX4 >= 40200
-# define HASSETREUID 1 /* setreuid(2) works as of AIX 4.2 */
-# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
-# endif /* _AIX4 >= 40200 */
-# if _AIX4 >= 40300
-# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
-# endif /* _AIX4 >= 40300 */
-# if defined(_ILS_MACROS) /* IBM versions aren't side-effect clean */
-# undef isascii
-# define isascii(c) !(c & ~0177)
-# undef isdigit
-# define isdigit(__a) (_IS(__a,_ISDIGIT))
-# undef isspace
-# define isspace(__a) (_IS(__a,_ISSPACE))
-# endif /* defined(_ILS_MACROS) */
-#endif /* _AIX4 */
-
-
-/*
-** IBM AIX 3.x -- actually tested for 3.2.3
-*/
-
-#ifdef _AIX3
-# include <paths.h>
-# include <sys/machine.h> /* to get byte order */
-# include <sys/select.h>
-# define HASFCHOWN 1 /* has fchown(2) */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define GIDSET_T gid_t
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define LA_TYPE LA_INT
-# define FSHIFT 16
-# define LA_AVENRUN "avenrun"
-#endif /* _AIX3 */
-
-
-/*
-** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773
-**
-** From Mark Whetzel <markw@wg.waii.com>.
-*/
-
-#ifdef AIX /* AIX/RT compiler pre-defines this */
-# include <paths.h>
-# include <sys/time.h> /* AIX/RT resource.h does NOT include this */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASFCHMOD 0 /* does not have fchmod(2) syscall */
-# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */
-# define HASSETVBUF 1 /* use setvbuf(2) system call */
-# define HASSETRLIMIT 0 /* does not have setrlimit call */
-# define HASFLOCK 0 /* does not have flock call - use fcntl */
-# define HASULIMIT 1 /* use ulimit instead of setrlimit call */
-# define NEEDGETOPT 1 /* Do we need theirs or ours */
-# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */
-# define GIDSET_T int
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# define ARBPTR_T int *
-# define void int
-typedef int pid_t;
-/* RTisms for BSD compatibility, specified in the Makefile
- define BSD 1
- define BSD_INCLUDES 1
- define BSD_REMAP_SIGNAL_TO_SIGVEC
- RTisms needed above */
-/* make this sendmail in a completely different place */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/local/newmail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* AIX */
-
-
-/*
-** Silicon Graphics IRIX
-**
-** Compiles on 4.0.1.
-**
-** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0).
-** Use IRIX5 instead of IRIX for IRIX 5.x.
-**
-** This version tries to be adaptive using _MIPS_SIM:
-** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2
-** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2
-** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2
-**
-** _MIPS_SIM is 1 also on IRIX 5.3
-**
-** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>.
-** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
-** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
-*/
-
-#if defined(__sgi)
-# ifndef IRIX
-# define IRIX
-# endif /* ! IRIX */
-# if _MIPS_SIM > 0 && !defined(IRIX5)
-# define IRIX5 /* IRIX5 or IRIX6 */
-# endif /* _MIPS_SIM > 0 && !defined(IRIX5) */
-# if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64)
-# define IRIX6 /* IRIX6 */
-# endif /* _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64) */
-#endif /* defined(__sgi) */
-
-#ifdef IRIX
-# define SYSTEM5 1 /* this is a System-V derived system */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define setpgid BSDsetpgrp
-# define GIDSET_T gid_t
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define SYSLOG_BUFSIZE 512
-# ifdef IRIX6
-# define STAT64 1
-# define QUAD_T unsigned long long
-# define LA_TYPE LA_IRIX6 /* figure out at run time */
-# define SAFENFSPATHCONF 0 /* pathconf(2) lies on NFS filesystems */
-# else /* IRIX6 */
-# define LA_TYPE LA_INT
-
-# ifdef IRIX64
-# define STAT64 1
-# define QUAD_T unsigned long long
-# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */
-# else /* IRIX64 */
-# define STAT64 0
-# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
-# endif /* IRIX64 */
-# endif /* IRIX6 */
-# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# include <sys/cdefs.h>
-# include <paths.h>
-# define ARGV_T char *const *
-# define HASFCHOWN 1 /* has fchown(2) */
-# define HASSETRLIMIT 1 /* has setrlimit(2) syscall */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# else /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
-# define ARGV_T const char **
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
-#endif /* IRIX */
-
-
-/*
-** SunOS and Solaris
-**
-** Tested on SunOS 4.1.x (a.k.a. Solaris 1.1.x) and
-** Solaris 2.4 (a.k.a. SunOS 5.4).
-*/
-
-#if defined(sun) && !defined(BSD)
-
-# include <sys/time.h>
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-# ifndef HASFCHOWN
-# define HASFCHOWN 1 /* fchown(2) */
-# endif /* ! HASFCHOWN */
-
-# ifdef SOLARIS_2_3
-# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */
-# endif /* SOLARIS_2_3 */
-
-# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4))
-# define SOLARIS 1 /* unknown Solaris version */
-# endif /* defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4)) */
-
-# ifdef SOLARIS
- /* Solaris 2.x (a.k.a. SunOS 5.x) */
-# ifndef __svr4__
-# define __svr4__ /* use all System V Release 4 defines below */
-# endif /* ! __svr4__ */
-# define GIDSET_T gid_t
-# define USE_SA_SIGACTION 1 /* use sa_sigaction field */
-# define HASSTRERROR 1 /* has strerror(3) */
-# if _FFR_MILTER
-# define BROKEN_PTHREAD_SLEEP 1 /* sleep after pthread_create() fails */
-# endif /* _FFR_MILTER */
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/dev/ksyms"
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# ifndef _PATH_HOSTS
-# define _PATH_HOSTS "/etc/inet/hosts"
-# endif /* ! _PATH_HOSTS */
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
-# endif /* ! SYSLOG_BUFSIZE */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME
-# endif /* ! TZ_TYPE */
-# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
-# define USESETEUID 1 /* seteuid works as of 2.3 */
-# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
-# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205)
-# define HASSETREUID 1 /* setreuid works as of 2.5 */
-# if SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700)
-# ifndef LA_TYPE
-# define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */
-# endif /* ! LA_TYPE */
-# ifndef RANDOMSHIFT /* random() doesn't work well (sometimes) */
-# define RANDOMSHIFT 8
-# endif /* RANDOMSHIFT */
-# endif /* SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700) */
-# else /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
-# ifndef HASRANDOM
-# define HASRANDOM 0 /* doesn't have random(3) */
-# endif /* ! HASRANDOM */
-# endif /* SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) */
-# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
-# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-# else /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
-# if _FFR_MILTER
-# define SM_INT32 int /* 32bit integer */
-# endif /* _FFR_MILTER */
-# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
-# if SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207)
-# ifndef LA_TYPE
-# include <sys/loadavg.h>
-# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209)
-# include <sys/pset.h>
-# define LA_TYPE LA_PSET /* pset_getloadavg(3c) appears in 2.9 */
-# else
-# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */
-# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */
-# endif /* ! LA_TYPE */
-# define HASGETUSERSHELL 1 /* getusershell(3c) bug fixed in 2.7 */
-# endif /* SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207) */
-# if SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208)
-# define HASSTRL 1 /* str*(3) added in 2.8 */
-# undef _PATH_SENDMAILPID /* tmpfs /var/run added in 2.8 */
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# endif /* SOLARIS >= 20800 || (SOLARIS < 10000 && SOLARIS >= 208) */
-# if SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209)
-# define HASURANDOMDEV 1 /* /dev/[u]random added in S9 */
-# endif /* SOLARIS >= 20900 || (SOLARIS < 10000 && SOLARIS >= 209) */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */
-# endif /* ! HASGETUSERSHELL */
-
-# else /* SOLARIS */
- /* SunOS 4.0.3 or 4.1.x */
-# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# include <memory.h>
-# include <vfork.h>
-# ifdef __GNUC__
-# define strtoul strtol /* gcc library bogosity */
-# endif /* __GNUC__ */
-# define memmove(d, s, l) (bcopy((s), (d), (l)))
-
-# ifdef SUNOS403
- /* special tweaking for SunOS 4.0.3 */
-# include <malloc.h>
-# define BSD4_3 1 /* 4.3 BSD-based */
-# define NEEDSTRSTR 1 /* need emulation of strstr(3) routine */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# undef WIFEXITED
-# undef WEXITSTATUS
-# undef HASUNAME
-# define setpgid setpgrp
-# define MODE_T int
-typedef int pid_t;
-extern char *getenv();
-
-# else /* SUNOS403 */
- /* 4.1.x specifics */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-
-# endif /* SUNOS403 */
-# endif /* SOLARIS */
-
-# ifndef LA_TYPE
-# define LA_TYPE LA_INT
-# endif /* ! LA_TYPE */
-
-#endif /* defined(sun) && !defined(BSD) */
-
-/*
-** DG/UX
-**
-** Tested on 5.4.2 and 5.4.3. Use DGUX_5_4_2 to get the
-** older support.
-** 5.4.3 changes from Mark T. Robinson <mtr@ornl.gov>.
-*/
-
-#ifdef DGUX_5_4_2
-# define DGUX 1
-#endif /* DGUX_5_4_2 */
-
-#ifdef DGUX
-# define SYSTEM5 1
-# define LA_TYPE LA_DGUX
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) */
-# define HASSNPRINTF 1 /* has snprintf(3) */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-
-/* these include files must be included early on DG/UX */
-# include <netinet/in.h>
-# include <arpa/inet.h>
-
-/* compiler doesn't understand const? */
-# define const
-
-# ifdef DGUX_5_4_2
-# define inet_addr dgux_inet_addr
-extern long dgux_inet_addr();
-# endif /* DGUX_5_4_2 */
-#endif /* DGUX */
-
-
-/*
-** Digital Ultrix 4.2A or 4.3
-**
-** Apparently, fcntl locking is broken on 4.2A, in that locks are
-** not dropped when the process exits. This causes major problems,
-** so flock is the only alternative.
-*/
-
-#ifdef ultrix
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFCHOWN 1 /* has fchown(2) syscall */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# ifndef BROKEN_RES_SEARCH
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
-# endif /* ! BROKEN_RES_SEARCH */
-# if !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621
-# define NEEDLOCAL_HOSTNAME_LENGTH 1 /* see sendmail/README */
-# endif /* !defined(NEEDLOCAL_HOSTNAME_LENGTH) && NAMED_BIND && __RES >= 19931104 && __RES < 19950621 */
-# ifdef vax
-# define LA_TYPE LA_FLOAT
-# else /* vax */
-# define LA_TYPE LA_INT
-# define LA_AVENRUN "avenrun"
-# endif /* vax */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* pre-4.4 TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# define SYSLOG_BUFSIZE 256
-#endif /* ultrix */
-
-
-/*
-** OSF/1 for KSR.
-**
-** Contributed by Todd C. Miller <Todd.Miller@cs.colorado.edu>
-*/
-
-#ifdef __ksr__
-# define __osf__ 1 /* get OSF/1 defines below */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif /* ! TZ_TYPE */
-#endif /* __ksr__ */
-
-
-/*
-** OSF/1 for Intel Paragon.
-**
-** Contributed by Jeff A. Earickson <jeff@ssd.intel.com>
-** of Intel Scalable Systems Divison.
-*/
-
-#ifdef __PARAGON__
-# define __osf__ 1 /* get OSF/1 defines below */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif /* ! TZ_TYPE */
-# define GIDSET_T gid_t
-# define MAXNAMLEN NAME_MAX
-#endif /* __PARAGON__ */
-
-
-/*
-** Tru64 UNIX, formerly known as Digital UNIX, formerly known as DEC OSF/1
-**
-** Tested for 3.2 and 4.0.
-*/
-
-#ifdef __osf__
-# define HASUNAME 1 /* has uname(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFCHOWN 1 /* has fchown(2) syscall */
-# define HASSETLOGIN 1 /* has setlogin(2) */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define GIDSET_T gid_t
-# if _FFR_MILTER
-# define SM_INT32 int /* 32bit integer */
-# endif /* _FFR_MILTER */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define LA_TYPE LA_ALPHAOSF
-# define SFS_TYPE SFS_STATVFS /* use <sys/statvfs.h> statfs() impl */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* __osf__ */
-
-
-/*
-** NeXTstep
-*/
-
-#ifdef NeXT
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define NEEDPUTENV 2 /* need putenv(3) call; no setenv(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define UID_T int /* compiler gripes on uid_t */
-# define GID_T int /* ditto for gid_t */
-# define MODE_T int /* and mode_t */
-# define setpgid setpgrp
-# ifndef NOT_SENDMAIL
-# define sleep sleepX
-# endif /* ! NOT_SENDMAIL */
-# ifndef LA_TYPE
-# define LA_TYPE LA_MACH
-# endif /* ! LA_TYPE */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef _POSIX_SOURCE
-typedef int pid_t;
-# undef WEXITSTATUS
-# undef WIFEXITED
-# undef WIFSTOPPED
-# undef WTERMSIG
-# endif /* ! _POSIX_SOURCE */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/sendmail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-
-# ifdef TCPWRAPPERS
-# ifndef HASUNSETENV
-# define HASUNSETENV 1
-# endif /* ! HASUNSETENV */
-# undef NEEDPUTENV
-# endif /* TCPWRAPPERS */
-
-#endif /* NeXT */
-
-/*
-** Apple Rhapsody
-** Contributed by Wilfredo Sanchez <wsanchez@apple.com>
-**
-** Also used for Apple Darwin support.
-*/
-
-#if defined(DARWIN)
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFLOCK 1 /* has flock(2) syscall */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASUNSETENV 1
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define HASINITGROUPS 1
-# define HASSETVBUF 1
-# define HASSETREUID 1
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASLSTAT 1
-# define HASSETRLIMIT 1
-# define HASWAITPID 1
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HASGETDTABLESIZE 1
-# define HASGETUSERSHELL 1
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_SUBR /* use getloadavg(3) */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# define SPT_TYPE SPT_PSSTRINGS
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-#endif /* DARWIN */
-
-
-/*
-** 4.4 BSD
-**
-** See also BSD defines.
-*/
-
-#if defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__)
-# include <paths.h>
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
-# define NETLINK 1 /* supports AF_LINK */
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif /* ! LA_TYPE */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# define SPT_TYPE SPT_PSSTRINGS /* use PS_STRINGS pointer */
-#endif /* defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__) */
-
-
-/*
-** BSD/OS (was BSD/386) (all versions)
-** From Tony Sanders, BSDI
-*/
-
-#ifdef __bsdi__
-# include <paths.h>
-# define HASUNSETENV 1 /* has the unsetenv(3) call */
-# define HASSETREUID 0 /* BSD-OS has broken setreuid(2) emulation */
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFCHOWN 1 /* has fchown(2) syscall */
-# define HASSETLOGIN 1 /* has setlogin(2) */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif /* ! LA_TYPE */
-# define GIDSET_T gid_t
-# define QUAD_T quad_t
-# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312
- /* version 1.1 or later */
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# else /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
- /* version 1.0 or earlier */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312 */
-# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 /* on 3.x */
-# define HASSETUSERCONTEXT 1 /* has setusercontext */
-# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 */
-# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199910 /* on 4.x */
-# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
-# endif /* defined(_BSDI_VERSION) && _BSDI_VERSION >= 199910 */
-#endif /* __bsdi__ */
-
-
-/*
-** QNX 4.2x
-** Contributed by Glen McCready <glen@qnx.com>.
-**
-** Should work with all versions of QNX.
-*/
-
-#if defined(__QNX__)
-# include <unix.h>
-# include <sys/select.h>
-# undef NGROUPS_MAX
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HASFLOCK 0
-# undef HASINITGROUPS /* has initgroups(3) call */
-# define NEEDGETOPT 1 /* use sendmail's getopt */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define TZ_TYPE TZ_TMNAME /* use tmname variable */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_NONE
-# define SPT_TYPE SPT_REUSEARGV
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define HASGETUSERSHELL 0
-# define E_PSEUDOBASE 512
-# define _FILE_H_INCLUDED
-#endif /* defined(__QNX__) */
-
-
-/*
-** FreeBSD / NetBSD / OpenBSD (all architectures, all versions)
-**
-** 4.3BSD clone, closer to 4.4BSD for FreeBSD 1.x and NetBSD 0.9x
-** 4.4BSD-Lite based for FreeBSD 2.x and NetBSD 1.x
-**
-** See also BSD defines.
-*/
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-# include <paths.h>
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFCHOWN 1 /* fchown(2) */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-# define GIDSET_T gid_t
-# define QUAD_T unsigned long long
-# define SFIO_STDIO_COMPAT 1 /* can use RES_DEBUG */
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif /* ! LA_TYPE */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1)
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# endif /* defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) */
-# if defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3))
-# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
-# endif /* defined(__NetBSD__) && ((__NetBSD_Version__ > 102070000) || (NetBSD1_2 > 8) || defined(NetBSD1_4) || defined(NetBSD1_3)) */
-# if defined(__FreeBSD__)
-# define HASSETLOGIN 1 /* has setlogin(2) */
-# if __FreeBSD_version >= 227001
-# define HASSRANDOMDEV 1 /* has srandomdev(3) */
-# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
-# endif /* __FreeBSD_version >= 227001 */
-# undef SPT_TYPE
-# if __FreeBSD__ >= 2
-# include <osreldate.h>
-# if __FreeBSD_version >= 199512 /* 2.2-current when it appeared */
-# include <libutil.h>
-# define SPT_TYPE SPT_BUILTIN
-# endif /* __FreeBSD_version >= 199512 */
-# if __FreeBSD_version >= 222000 /* 2.2.2-release and later */
-# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
-# endif /* __FreeBSD_version >= 222000 */
-# if __FreeBSD_version >= 330000 /* 3.3.0-release and later */
-# ifndef HASSTRL
-# define HASSTRL 1 /* has strlc{py,at}(3) functions */
-# endif /* HASSTRL */
-# endif /* __FreeBSD_version >= 330000 */
-# define USESYSCTL 1 /* use sysctl(3) for getting ncpus */
-# include <sys/sysctl.h>
-# endif /* __FreeBSD__ >= 2 */
-# ifndef SPT_TYPE
-# define SPT_TYPE SPT_REUSEARGV
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# endif /* ! SPT_TYPE */
-# endif /* defined(__FreeBSD__) */
-# if defined(__OpenBSD__)
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# define HASSETLOGIN 1 /* has setlogin(2) */
-# define HASSETREUID 0 /* OpenBSD has broken setreuid(2) emulation */
-# define HASURANDOMDEV 1 /* has /dev/urandom(4) */
-# if OpenBSD < 199912
-# define HASSTRL 0 /* strlcat(3) is broken in 2.5 and earlier */
-# else /* OpenBSD < 199912 */
-# define HASSTRL 1 /* has strlc{py,at}(3) functions */
-# if OpenBSD >= 200006
-# define HASSRANDOMDEV 1 /* has srandomdev(3) */
-# endif
-# if OpenBSD >= 200012
-# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
-# endif
-# endif /* OpenBSD < 199912 */
-# endif /* defined(__OpenBSD__) */
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) */
-
-
-/*
-** Mach386
-**
-** For mt Xinu's Mach386 system.
-*/
-
-#if defined(MACH) && defined(i386) && !defined(__GNU__)
-# define MACH386 1
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDSTRTOL 1 /* need the strtol() function */
-# define setpgid setpgrp
-# ifndef LA_TYPE
-# define LA_TYPE LA_FLOAT
-# endif /* ! LA_TYPE */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# undef WEXITSTATUS
-# undef WIFEXITED
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* defined(MACH) && defined(i386) && !defined(__GNU__) */
-
-
-
-/*
-** GNU OS (hurd)
-** Largely BSD & posix compatible.
-** Port contributed by Miles Bader <miles@gnu.ai.mit.edu>.
-** Updated by Mark Kettenis <kettenis@wins.uva.nl>.
-*/
-
-#if defined(__GNU__) && !defined(NeXT)
-# include <paths.h>
-# define HASFCHMOD 1 /* has fchmod(2) call */
-# define HASFCHOWN 1 /* has fchown(2) call */
-# define HASUNAME 1 /* has uname(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define GIDSET_T gid_t
-# define SOCKADDR_LEN_T socklen_t
-# define SOCKOPT_LEN_T socklen_t
-# if (__GLIBC__ == 2 && __GLIBC_MINOR__ > 1) || __GLIBC__ > 2
-# define LA_TYPE LA_SUBR
-# else
-# define LA_TYPE LA_MACH
- /* GNU uses mach[34], which renames some rpcs from mach2.x. */
-# define host_self mach_host_self
-# endif
-# define SFS_TYPE SFS_STATFS
-# define SPT_TYPE SPT_CHANGEARGV
-# define ERRLIST_PREDEFINED 1 /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR 1 /* has sa_len */
-# define SIOCGIFCONF_IS_BROKEN 1 /* SIOCGFCONF doesn't work */
-# define HAS_IN_H 1 /* GNU has netinet/in.h. */
-/* GNU has no MAXPATHLEN; ideally the code should be changed to not use it. */
-# define MAXPATHLEN 2048
-#endif /* defined(__GNU__) && !defined(NeXT) */
-
-/*
-** 4.3 BSD -- this is for very old systems
-**
-** Should work for mt Xinu MORE/BSD and Mips UMIPS-BSD 2.1.
-**
-** You'll also have to install a new resolver library.
-** I don't guarantee that support for this environment is complete.
-*/
-
-#if defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd)
-# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define ARBPTR_T char *
-# define setpgid setpgrp
-# ifndef LA_TYPE
-# define LA_TYPE LA_FLOAT
-# endif /* ! LA_TYPE */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# undef WEXITSTATUS
-# undef WIFEXITED
-typedef short pid_t;
-#endif /* defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) */
-
-
-/*
-** SCO Unix
-**
-** This includes three parts:
-**
-** The first is for SCO OpenServer 5.
-** (Contributed by Keith Reynolds <keithr@sco.COM>).
-**
-** SCO OpenServer 5 has a compiler version number macro,
-** which we can use to figure out what version we're on.
-** This may have to change in future releases.
-**
-** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0.
-** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>).
-**
-** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier.
-*/
-
-/* SCO OpenServer 5 */
-#if _SCO_DS >= 1
-# include <paths.h>
-# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM returns bogus value */
-# define HASSNPRINTF 1 /* has snprintf(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) call */
-# define HASFCHOWN 1 /* has fchown(2) call */
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# define USESETEUID 1 /* has seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# define RLIMIT_NEEDS_SYS_TIME_H 1
-# ifndef LA_TYPE
-# define LA_TYPE LA_DEVSHORT
-# endif /* ! LA_TYPE */
-# define _PATH_AVENRUN "/dev/table/avenrun"
-# ifndef _SCO_unix_4_2
-# define _SCO_unix_4_2
-# else /* ! _SCO_unix_4_2 */
-# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
-# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
-# endif /* ! _SCO_unix_4_2 */
-#endif /* _SCO_DS >= 1 */
-
-/* SCO UNIX 3.2v4.2/Open Desktop 3.0 */
-#ifdef _SCO_unix_4_2
-# define _SCO_unix_
-# define HASSETREUID 1 /* has setreuid(2) call */
-#endif /* _SCO_unix_4_2 */
-
-/* SCO UNIX 3.2v4.0 Open Desktop 2.0 and earlier */
-#ifdef _SCO_unix_
-# include <sys/stream.h> /* needed for IP_SRCROUTE */
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define NOFTRUNCATE 0 /* has (simulated) ftruncate call */
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-# define MAXPATHLEN PATHSIZE
-# define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define SPT_TYPE SPT_SCO /* write kernel u. area */
-# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */
-# define UID_T uid_t
-# define GID_T gid_t
-# define GIDSET_T gid_t
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-
-/* stuff fixed in later releases */
-# ifndef _SCO_unix_4_2
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# endif /* ! _SCO_unix_4_2 */
-
-# ifndef _SCO_DS
-# define ftruncate chsize /* use chsize(2) to emulate ftruncate */
-# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
-# define NETUNIX 0 /* no unix domain socket support */
-# define LA_TYPE LA_SHORT
-# endif /* ! _SCO_DS */
-
-#endif /* _SCO_unix_ */
-
-
-/*
-** ISC (SunSoft) Unix.
-**
-** Contributed by J.J. Bailey <jjb@jagware.bcc.com>
-*/
-
-#ifdef ISC_UNIX
-# include <net/errno.h>
-# include <sys/stream.h> /* needed for IP_SRCROUTE */
-# include <sys/bsdtypes.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
-# define NETUNIX 0 /* no unix domain socket support */
-# define MAXPATHLEN 1024
-# define LA_TYPE LA_SHORT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* ISC_UNIX */
-
-
-/*
-** Altos System V (5.3.1)
-** Contributed by Tim Rice <tim@trr.metro.net>.
-*/
-
-#ifdef ALTOS_SYSTEM_V
-# include <sys/stream.h>
-# include <limits.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define NEEDFSYNC 1 /* no fsync(2) in system library */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
-# define MAXPATHLEN PATH_MAX
-# define LA_TYPE LA_SHORT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# define NETUNIX 0 /* no unix domain socket support */
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define strtoul strtol /* gcc library bogosity */
-
-typedef unsigned short uid_t;
-typedef unsigned short gid_t;
-typedef short pid_t;
-typedef unsigned long mode_t;
-
-/* some stuff that should have been in the include files */
-extern char *malloc();
-extern struct passwd *getpwent();
-extern struct passwd *getpwnam();
-extern struct passwd *getpwuid();
-extern char *getenv();
-extern struct group *getgrgid();
-extern struct group *getgrnam();
-
-#endif /* ALTOS_SYSTEM_V */
-
-
-/*
-** ConvexOS 11.0 and later
-**
-** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this
-** works on 9.1 as well.
-**
-** ConvexOS 11.5 and later, should work on 11.0 as defined.
-** For pre-ConvexOOS 11.0, define NEEDGETOPT, undef IDENTPROTO
-**
-** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp.
-** (now the CONVEX Technologies Center of Hewlett Packard)
-*/
-
-#ifdef _CONVEX_SOURCE
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */
-# define HASINITGROUPS 1 /* has initgroups(3) */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETSID 1 /* has POSIX setsid(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) */
-# define HASFLOCK 1 /* has flock(2) */
-# define HASSETRLIMIT 1 /* has setrlimit(2) */
-# define HASSETREUID 1 /* has setreuid(2) */
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */
-# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */
-# define NEEDGETOPT 0 /* need replacement for getopt(3) */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define LA_TYPE LA_FLOAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef S_IREAD
-# define S_IREAD _S_IREAD
-# define S_IWRITE _S_IWRITE
-# define S_IEXEC _S_IEXEC
-# define S_IFMT _S_IFMT
-# define S_IFCHR _S_IFCHR
-# define S_IFBLK _S_IFBLK
-# endif /* ! S_IREAD */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TIMEZONE
-# endif /* ! TZ_TYPE */
-# ifndef IDENTPROTO
-# define IDENTPROTO 1
-# endif /* ! IDENTPROTO */
-# ifndef SHARE_V1
-# define SHARE_V1 1 /* version 1 of the fair share scheduler */
-# endif /* ! SHARE_V1 */
-# if !defined(__GNUC__ )
-# define UID_T int /* GNUC gets it right, ConvexC botches */
-# define GID_T int /* GNUC gets it right, ConvexC botches */
-# endif /* !defined(__GNUC__ ) */
-# if SECUREWARE
-# define FORK fork /* SecureWare wants the real fork! */
-# else /* SECUREWARE */
-# define FORK vfork /* the rest of the OS versions don't care */
-# endif /* SECUREWARE */
-#endif /* _CONVEX_SOURCE */
-
-
-/*
-** RISC/os 4.52
-**
-** Gives a ton of warning messages, but otherwise compiles.
-*/
-
-#ifdef RISCOS
-
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDPUTENV 1 /* need putenv(3) call */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define LA_TYPE LA_INT
-# define LA_AVENRUN "avenrun"
-# define _PATH_UNIX "/unix"
-# undef WIFEXITED
-
-# define setpgid setpgrp
-
-typedef int pid_t;
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-typedef int (*sigfunc_t)();
-extern char *getenv();
-extern void *malloc();
-
-/* added for RISC/os 4.01...which is dumber than 4.50 */
-# ifdef RISCOS_4_0
-# ifndef ARBPTR_T
-# define ARBPTR_T char *
-# endif /* ! ARBPTR_T */
-# undef HASFLOCK
-# define HASFLOCK 0
-# endif /* RISCOS_4_0 */
-
-# include <sys/time.h>
-
-#endif /* RISCOS */
-
-
-/*
-** Linux 0.99pl10 and above...
-**
-** Thanks to, in reverse order of contact:
-**
-** John Kennedy <warlock@csuchico.edu>
-** Andrew Pam <avatar@aus.xanadu.com>
-** Florian La Roche <rzsfl@rz.uni-sb.de>
-** Karl London <karl@borg.demon.co.uk>
-**
-** Last compiled against: [07/21/98 @ 11:47:34 AM (Tuesday)]
-** sendmail 8.9.1 bind-8.1.2 db-2.4.14
-** gcc-2.8.1 glibc-2.0.94 linux-2.1.109
-**
-** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style
-** file locking is no longer allowed. In particular, make sure
-** your DBM library and sendmail are both using either flock(2)
-** *or* fcntl(2) file locking, but not both.
-*/
-
-#ifdef __linux__
-# include <linux/version.h>
-# if !defined(KERNEL_VERSION) /* not defined in 2.0.x kernel series */
-# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-# endif /* KERNEL_VERSION */
-# define BSD 1 /* include BSD defines */
-# define USESETEUID 0 /* Have it due to POSIX, but doesn't work */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# ifndef HASSNPRINTF
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# endif /* ! HASSNPRINTF */
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define GIDSET_T gid_t /* from <linux/types.h> */
-# define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */
-# ifndef IP_SRCROUTE
-# define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */
-# endif /* ! IP_SRCROUTE */
-# ifndef HAS_IN_H
-# define HAS_IN_H 1 /* use netinet/in.h */
-# endif /* ! HAS_IN_H */
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-# ifndef HASFLOCK
-# if LINUX_VERSION_CODE < 66399
-# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */
-# else /* LINUX_VERSION_CODE < 66399 */
-# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */
-# endif /* LINUX_VERSION_CODE < 66399 */
-# endif /* ! HASFLOCK */
-# ifndef LA_TYPE
-# define LA_TYPE LA_PROCSTR
-# endif /* ! LA_TYPE */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,0))
-# ifndef HASURANDOMDEV
-# define HASURANDOMDEV 1 /* 2.0 (at least) has linux/drivers/char/random.c */
-# endif /* ! HASURANDOMDEV */
-# endif /* LINUX_VERSION_CODE */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_NONE /* no standard for Linux */
-# endif /* ! TZ_TYPE */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# include <sys/sysmacros.h>
-# undef atol /* wounded in <stdlib.h> */
-# if NETINET6
- /*
- ** Linux doesn't have a good way to tell userland what interfaces are
- ** IPv6-capable. Therefore, the BIND resolver can not determine if there
- ** are IPv6 interfaces to honor AI_ADDRCONFIG. Unfortunately, it assumes
- ** that none are present. (Excuse the macro name ADDRCONFIG_IS_BROKEN.)
- */
-# define ADDRCONFIG_IS_BROKEN 1
-
- /*
- ** Indirectly included from glibc's <feature.h>. IPv6 support is native
- ** in 2.1 and later, but the APIs appear before the functions.
- */
-# if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
-# define GLIBC_VERSION ((__GLIBC__ << 8) + __GLIBC_MINOR__)
-# if (GLIBC_VERSION >= 0x201)
-# undef IPPROTO_ICMPV6 /* linux #defines, glibc enums */
-# else /* (GLIBC_VERSION >= 0x201) */
-# include <linux/in6.h> /* IPv6 support */
-# endif /* (GLIBC_VERSION >= 0x201) */
-# if (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE))
- /* Have APIs in <netdb.h>, but no support in glibc */
-# define NEEDSGETIPNODE 1
-# endif /* (GLIBC_VERSION >= 0x201 && !defined(NEEDSGETIPNODE)) */
-# undef GLIBC_VERSION
-# endif /* defined(__GLIBC__) && defined(__GLIBC_MINOR__) */
-# endif /* NETINET6 */
-# ifndef HASFCHOWN
-# define HASFCHOWN 1 /* fchown(2) */
-# endif /* ! HASFCHOWN */
-#endif /* __linux__ */
-
-
-/*
-** DELL SVR4 Issue 2.2, and others
-** From Kimmo Suominen <kim@grendel.lut.fi>
-**
-** It's on #ifdef DELL_SVR4 because Solaris also gets __svr4__
-** defined, and the definitions conflict.
-**
-** Peter Wemm <peter@perth.DIALix.oz.au> claims that the setreuid
-** trick works on DELL 2.2 (SVR4.0/386 version 4.0) and ESIX 4.0.3A
-** (SVR4.0/386 version 3.0).
-*/
-
-#ifdef DELL_SVR4
- /* no changes necessary */
- /* see general __svr4__ defines below */
-#endif /* DELL_SVR4 */
-
-
-/*
-** Apple A/UX 3.0
-*/
-
-#ifdef _AUX_SOURCE
-# include <sys/sysmacros.h>
-# define BSD /* has BSD routines */
-# define HASSETRLIMIT 0 /* ... but not setrlimit(2) */
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
-# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASSETVBUF 1 /* has setvbuf(3) in libc */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define SIGFUNC_DEFINED /* sigfunc_t already defined */
-# define SIGFUNC_RETURN /* POSIX-mode */
-# define SIGFUNC_DECL void /* POSIX-mode */
-# define ERRLIST_PREDEFINED 1
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# ifndef LA_TYPE
-# define LA_TYPE LA_INT
-# define FSHIFT 16
-# endif /* ! LA_TYPE */
-# define LA_AVENRUN "avenrun"
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define TZ_TYPE TZ_TZNAME
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix" /* should be in <paths.h> */
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif /* _AUX_SOURCE */
-
-
-/*
-** Encore UMAX V
-**
-** Not extensively tested.
-*/
-
-#ifdef UMAXV
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define MAXPATHLEN PATH_MAX
-extern struct passwd *getpwent(), *getpwnam(), *getpwuid();
-extern struct group *getgrent(), *getgrnam(), *getgrgid();
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif /* UMAXV */
-
-
-/*
-** Stardent Titan 3000 running TitanOS 4.2.
-**
-** Must be compiled in "cc -43" mode.
-**
-** From Kate Hedstrom <kate@ahab.rutgers.edu>.
-**
-** Note the tweaking below after the BSD defines are set.
-*/
-
-#ifdef titan
-# define setpgid setpgrp
-typedef int pid_t;
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif /* titan */
-
-
-/*
-** Sequent DYNIX 3.2.0
-**
-** From Jim Davis <jdavis@cs.arizona.edu>.
-*/
-
-#ifdef sequent
-
-# define BSD 1
-# define HASUNSETENV 1
-# define BSD4_3 1 /* to get signal() in conf.c */
-# define WAITUNION 1
-# define LA_TYPE LA_FLOAT
-# ifdef _POSIX_VERSION
-# undef _POSIX_VERSION /* set in <unistd.h> */
-# endif /* _POSIX_VERSION */
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# define setpgid setpgrp
-
-/* Have to redefine WIFEXITED to take an int, to work with waitfor() */
-# undef WIFEXITED
-# define WIFEXITED(s) (((union wait*)&(s))->w_stopval != WSTOPPED && \
- ((union wait*)&(s))->w_termsig == 0)
-# define WEXITSTATUS(s) (((union wait*)&(s))->w_retcode)
-typedef int pid_t;
-# define isgraph(c) (isprint(c) && (c != ' '))
-
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/dynix"
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-#endif /* sequent */
-
-
-/*
-** Sequent DYNIX/ptx v2.0 (and higher)
-**
-** For DYNIX/ptx v1.x, undefine HASSETREUID.
-**
-** From Tim Wright <timw@sequent.com>.
-** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995,
-** for DYNIX/ptx 4.0.2.
-*/
-
-#ifdef _SEQUENT_
-# include <sys/stream.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASSETSID 1 /* has POSIX setsid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_INT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* _SEQUENT_ */
-
-
-/*
-** Cray Unicos
-**
-** Ported by David L. Kensiski, Sterling Sofware <kensiski@nas.nasa.gov>
-*/
-
-#ifdef UNICOS
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define MAXPATHLEN PATHSIZE
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-#endif /* UNICOS */
-
-
-/*
-** Apollo DomainOS
-**
-** From Todd Martin <tmartint@tus.ssi1.com> & Don Lewis <gdonl@gv.ssi1.com>
-**
-** 15 Jan 1994; updated 2 Aug 1995
-**
-*/
-
-#ifdef apollo
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(2) call */
-# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# define LA_TYPE LA_SUBR /* use getloadavg.c */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define TZ_TYPE TZ_TZNAME
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# undef S_IFSOCK /* S_IFSOCK and S_IFIFO are the same */
-# undef S_IFIFO
-# define S_IFIFO 0010000
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# define RLIMIT_NEEDS_SYS_TIME_H 1
-# if defined(NGROUPS_MAX) && !NGROUPS_MAX
-# undef NGROUPS_MAX
-# endif /* defined(NGROUPS_MAX) && !NGROUPS_MAX */
-#endif /* apollo */
-
-/*
-** System V Rel 5.x (a.k.a Unixware7 w/o BSD-Compatibility Libs ie. native)
-**
-** Contributed by Paul Gampe <paulg@apnic.net>
-*/
-
-#ifdef __svr5__
-# include <sys/mkdev.h>
-# define __svr4__
-# define SYS5SIGNALS 1
-# define HASFCHOWN 1 /* has fchown(2) call */
-# define HASSETSID 1
-# define HASSNPRINTF 1
-# define HASSETREUID 1
-# define HASWAITPID 1
-# define HASGETDTABLESIZE 1
-# define GIDSET_T gid_t
-# define SOCKADDR_LEN_T size_t
-# define SOCKOPT_LEN_T size_t
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/stand/unix"
-# endif /* ! _PATH_UNIX */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024 /* unsure */
-# endif /* SYSLOG_BUFSIZE */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
-#if !defined(SM_SET_H_ERRNO) && defined(_REENTRANT)
-# define SM_SET_H_ERRNO(err) set_h_errno((err))
-#endif /* ! SM_SET_H_ERRNO && _REENTRANT */
-#endif /* __svr5__ */
-
-/* ###################################################################### */
-
-/*
-** UnixWare 2.x
-*/
-
-#ifdef UNIXWARE2
-# define UNIXWARE 1
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
-#endif /* UNIXWARE2 */
-
-
-/*
-** UnixWare 1.1.2.
-**
-** Updated by Petr Lampa <lampa@fee.vutbr.cz>.
-** From Evan Champion <evanc@spatial.synapse.org>.
-*/
-
-#ifdef UNIXWARE
-# include <sys/mkdev.h>
-# define SYSTEM5 1
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASSETREUID 1
-# define HASSETSID 1
-# define HASINITGROUPS 1
-# define GIDSET_T gid_t
-# define SLEEP_T unsigned
-# define SFS_TYPE SFS_STATVFS
-# define LA_TYPE LA_ZERO
-# undef WIFEXITED
-# undef WEXITSTATUS
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix"
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# define SYSLOG_BUFSIZE 128
-#endif /* UNIXWARE */
-
-
-/*
-** Intergraph CLIX 3.1
-**
-** From Paul Southworth <pauls@locust.cic.net>
-*/
-
-#ifdef CLIX
-# define SYSTEM5 1 /* looks like System V */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# endif /* ! HASGETUSERSHELL */
-# define DEV_BSIZE 512 /* device block size not defined */
-# define GIDSET_T gid_t
-# undef LOG /* syslog not available */
-# define NEEDFSYNC 1 /* no fsync in system library */
-# define GETSHORT _getshort
-#endif /* CLIX */
-
-
-/*
-** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP
-**
-** From Kevin Darcy <kevin@tech.mis.cfc.com>.
-*/
-
-#ifdef NCR_MP_RAS2
-# include <sys/sockio.h>
-# define __svr4__
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define SYSLOG_BUFSIZE 1024
-# define SPT_TYPE SPT_NONE
-#endif /* NCR_MP_RAS2 */
-
-
-/*
-** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP
-**
-** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
-*/
-
-#ifdef NCR_MP_RAS3
-# define __svr4__
-# define HASFCHOWN 1 /* has fchown(2) call */
-# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM has non-std interface */
-# define SO_REUSEADDR_IS_BROKEN 1 /* doesn't work if accept() fails */
-# define SYSLOG_BUFSIZE 1024
-# define SPT_TYPE SPT_NONE
-# ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE
-# define _XOPEN_SOURCE_EXTENDED 1
-# include <sys/resource.h>
-# undef _XOPEN_SOURCE
-# undef _XOPEN_SOURCE_EXTENDED
-# endif /* ! _XOPEN_SOURCE */
-#endif /* NCR_MP_RAS3 */
-
-
-/*
-** Tandem NonStop-UX SVR4
-**
-** From Rick McCarty <mccarty@mpd.tandem.com>.
-*/
-
-#ifdef NonStop_UX_BXX
-# define __svr4__
-#endif /* NonStop_UX_BXX */
-
-
-/*
-** Hitachi 3050R/3050RX and 3500 Workstations running HI-UX/WE2.
-**
-** Tested for 1.04, 1.03
-** From Akihiro Hashimoto ("Hash") <hash@dominic.ipc.chiba-u.ac.jp>.
-**
-** Tested for 4.02, 6.10 and 7.10
-** From Motonori NAKAMURA <motonori@media.kyoto-u.ac.jp>.
-*/
-
-#if !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE))
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define setreuid(r, e) setresuid(r, e, -1)
-# define LA_TYPE LA_FLOAT
-# define SPT_TYPE SPT_PSTAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef HASSETVBUF
-# define HASSETVBUF /* HI-UX has no setlinebuf */
-# endif /* ! HASSETVBUF */
-# ifndef GIDSET_T
-# define GIDSET_T gid_t
-# endif /* ! GIDSET_T */
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/HI-UX"
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
-# endif /* ! HASGETUSERSHELL */
-# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
-
-/*
-** avoid m_flags conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h
-** on HIUX 3050
-*/
-# undef m_flags
-
-# ifdef __STDC__
-extern int syslog(int, char *, ...);
-# else /* __STDC__ */
-extern int syslog();
-# endif /* __STDC__ */
-
-#endif /* !defined(__hpux) && (defined(_H3050R) || defined(_HIUX_SOURCE)) */
-
-
-/*
-** Amdahl UTS System V 2.1.5 (SVr3-based)
-**
-** From: Janet Jackson <janet@dialix.oz.au>.
-*/
-
-#ifdef _UTS
-# include <sys/sysmacros.h>
-# undef HASLSTAT /* has symlinks, but they cause problems */
-# define NEEDFSYNC 1 /* system fsync(2) fails on non-EFS filesys */
-# define SYS5SIGNALS 1 /* System V signal semantics */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASINITGROUPS 1 /* has initgroups(3) function */
-# define HASSETVBUF 1 /* has setvbuf(3) function */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) function */
-# endif /* ! HASGETUSERSHELL */
-# define GIDSET_T gid_t /* type of 2nd arg to getgroups(2) isn't int */
-# define LA_TYPE LA_ZERO /* doesn't have load average */
-# define SFS_TYPE SFS_4ARGS /* use 4-arg statfs() */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-#endif /* _UTS */
-
-/*
-** Cray Computer Corporation's CSOS
-**
-** From Scott Bolte <scott@craycos.com>.
-*/
-
-#ifdef _CRAYCOM
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define NEEDFSYNC 1 /* no fsync in system library */
-# define MAXPATHLEN PATHSIZE
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _POSIX_CHOWN_RESTRICTED -1
-extern struct group *getgrent(), *getgrnam(), *getgrgid();
-#endif /* _CRAYCOM */
-
-
-/*
-** Sony NEWS-OS 4.2.1R and 6.0.3
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#ifdef sony_news
-# ifndef __svr4
- /* NEWS-OS 4.2.1R */
-# ifndef BSD
-# define BSD /* has BSD routines */
-# endif /* ! BSD */
-# define HASUNSETENV 1 /* has unsetenv(2) call */
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define LA_TYPE LA_INT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# define setpgid setpgrp
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define MODE_T int /* system include files have no mode_t */
-typedef int pid_t;
-typedef int (*sigfunc_t)();
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-
-# else /* ! __svr4 */
- /* NEWS-OS 6.0.3 with /bin/cc */
-# ifndef __svr4__
-# define __svr4__ /* use all System V Release 4 defines below */
-# endif /* ! __svr4__ */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
-# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
-# ifndef SPT_TYPE
-# define SPT_TYPE SPT_SYSMIPS /* use sysmips() (OS 6.0.2 or later) */
-# endif /* ! SPT_TYPE */
-# define GIDSET_T gid_t
-# undef WIFEXITED
-# undef WEXITSTATUS
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 256
-# endif /* ! SYSLOG_BUFSIZE */
-# define _PATH_UNIX "/stand/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-
-# endif /* ! __svr4 */
-#endif /* sony_news */
-
-
-/*
-** Omron LUNA/UNIOS-B 3.0, LUNA2/Mach and LUNA88K Mach
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#ifdef luna
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-# define HASUNSETENV 1 /* has unsetenv(2) call */
-# define NEEDPUTENV 1 /* need putenv(3) call */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# ifdef uniosb
-# include <sys/time.h>
-# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
-# define LA_TYPE LA_INT
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# endif /* uniosb */
-# ifdef luna2
-# define LA_TYPE LA_SUBR
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# endif /* luna2 */
-# ifdef luna88k
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define LA_TYPE LA_INT
-# endif /* luna88k */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define setpgid setpgrp
-# undef WIFEXITED
-# undef WEXITSTATUS
-typedef int pid_t;
-typedef int (*sigfunc_t)();
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-extern char *getenv();
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-#endif /* luna */
-
-
-/*
-** NEC EWS-UX/V 4.2 (with /usr/ucb/cc)
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#if defined(nec_ews_svr4) || defined(_nec_ews_svr4)
-# ifndef __svr4__
-# define __svr4__ /* use all System V Release 4 defines below */
-# endif /* ! __svr4__ */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define LA_TYPE LA_READKSYM /* use MIOC_READSYM ioctl */
-# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
-# define GIDSET_T gid_t
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
-# endif /* ! SYSLOG_BUFSIZE */
-#endif /* defined(nec_ews_svr4) || defined(_nec_ews_svr4) */
-
-
-/*
-** Fujitsu/ICL UXP/DS (For the DS/90 Series)
-**
-** From Diego R. Lopez <drlopez@cica.es>.
-** Additional changes from Fumio Moriya and Toshiaki Nomura of the
-** Fujitsu Fresoftware group <dsfrsoft@oai6.yk.fujitsu.co.jp>.
-*/
-
-#ifdef __uxp__
-# include <arpa/nameser.h>
-# include <sys/sysmacros.h>
-# include <sys/mkdev.h>
-# define __svr4__
-# define HASGETUSERSHELL 0
-# define HASFLOCK 0
-# if UXPDS == 10
-# define HASSNPRINTF 0 /* no snprintf(3) or vsnprintf(3) */
-# else /* UXPDS == 10 */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# endif /* UXPDS == 10 */
-# define _PATH_UNIX "/stand/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-#endif /* __uxp__ */
-
-/*
-** Pyramid DC/OSx
-**
-** From Earle Ake <akee@wpdiss1.wpafb.af.mil>.
-*/
-
-#ifdef DCOSx
-# define GIDSET_T gid_t
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif /* ! IDENTPROTO */
-#endif /* DCOSx */
-
-/*
-** Concurrent Computer Corporation Maxion
-**
-** From Donald R. Laster Jr. <laster@access.digex.net>.
-*/
-
-#ifdef __MAXION__
-
-# include <sys/stream.h>
-# define __svr4__ 1 /* SVR4.2MP */
-# define HASSETREUID 1 /* have setreuid(2) */
-# define HASLSTAT 1 /* have lstat(2) */
-# define HASSETRLIMIT 1 /* have setrlimit(2) */
-# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */
-# define HASSNPRINTF 1 /* have snprintf(3) */
-# define HASGETUSERSHELL 1 /* have getusershell(3) */
-# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
-# define SLEEP_T unsigned
-# define SFS_TYPE SFS_STATVFS
-# define SFS_BAVAIL f_bavail
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */
-# endif /* ! SYSLOG_BUFSIZE */
-
-# undef WUNTRACED
-# undef WIFEXITED
-# undef WIFSIGNALED
-# undef WIFSTOPPED
-# undef WEXITSTATUS
-# undef WTERMSIG
-# undef WSTOPSIG
-
-#endif /* __MAXION__ */
-
-/*
-** Harris Nighthawk PowerUX (nh6000 box)
-**
-** Contributed by Bob Miorelli, Pratt & Whitney <miorelli@pweh.com>
-*/
-
-#ifdef _PowerUX
-# ifndef __svr4__
-# define __svr4__
-# endif /* ! __svr4__ */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# define SYSLOG_BUFSIZE 1024
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define LA_TYPE LA_ZERO
-typedef struct msgb mblk_t;
-# undef offsetof /* avoid stddefs.h and sys/sysmacros.h conflict */
-#endif /* _PowerUX */
-
-/*
-** Siemens Nixdorf Informationssysteme AG SINIX
-**
-** Contributed by Gerald Rinske <Gerald.Rinske@mch.sni.de>
-** of Siemens Business Services VAS.
-*/
-#ifdef sinix
-# define HASRANDOM 0 /* has random(3) */
-# define SYSLOG_BUFSIZE 1024
-#endif /* sinix */
-
-/*
-** CRAY T3E
-**
-** Contributed by Manu Mahonen <mailadm@csc.fi>
-** of Center for Scientific Computing.
-*/
-#ifdef _CRAY
-# define GET_IPOPT_DST(dst) *(struct in_addr *)&(dst)
-#endif /* _CRAY */
-
-/*
-** Motorola 922, MC88110, UNIX SYSTEM V/88 Release 4.0 Version 4.3
-**
-** Contributed by Sergey Rusanov <rsm@utfoms.udmnet.ru>
-*/
-
-#ifdef MOTO
-# define HASFCHMOD 1
-# define HASSETRLIMIT 0
-# define HASSETSID 1
-# define HASSETREUID 1
-# define HASULIMIT 1
-# define HASWAITPID 1
-# define HASGETDTABLESIZE 1
-# define HASGETUSERSHELL 1
-# define IP_SRCROUTE 0
-# define IDENTPROTO 0
-# define RES_DNSRCH_VARIABLE _res_dnsrch
-# define _PATH_UNIX "/unix"
-# define _PATH_VENDOR_CF "/etc/sendmail.cf"
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-#endif /* MOTO */
-
-
-/**********************************************************************
-** End of Per-Operating System defines
-**********************************************************************/
- /**********************************************************************
-** More general defines
-**********************************************************************/
-
-/* general BSD defines */
-#ifdef BSD
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# ifndef HASSETREUID
-# define HASSETREUID 1 /* has setreuid(2) call */
-# endif /* ! HASSETREUID */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# ifndef IP_SRCROUTE
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# endif /* ! IP_SRCROUTE */
-# ifndef HASSETRLIMIT
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# endif /* ! HASSETRLIMIT */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif /* ! HASFLOCK */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone variable */
-# endif /* ! TZ_TYPE */
-#endif /* BSD */
-
-/* general System V Release 4 defines */
-#ifdef __svr4__
-# define SYSTEM5 1
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define BSD_COMP 1 /* get BSD ioctl calls */
-# ifndef HASSETRLIMIT
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# endif /* ! HASSETRLIMIT */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# endif /* ! HASGETUSERSHELL */
-# ifndef HASFCHMOD
-# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */
-# endif /* ! HASFCHMOD */
-
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix"
-# endif /* ! _PATH_UNIX */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif /* ! _PATH_VENDOR_CF */
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif /* ! _PATH_SENDMAILPID */
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 128
-# endif /* ! SYSLOG_BUFSIZE */
-# ifndef SFS_TYPE
-# define SFS_TYPE SFS_STATVFS
-# endif /* ! SFS_TYPE */
-
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-#endif /* __svr4__ */
-
-/* general System V defines */
-#ifdef SYSTEM5
-# include <sys/sysmacros.h>
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-# ifndef HASULIMIT
-# define HASULIMIT 1 /* has the ulimit(2) syscall */
-# endif /* ! HASULIMIT */
-# ifndef LA_TYPE
-# ifdef MIOC_READKSYM
-# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
-# else /* MIOC_READKSYM */
-# define LA_TYPE LA_INT /* assume integer load average */
-# endif /* MIOC_READKSYM */
-# endif /* ! LA_TYPE */
-# ifndef SFS_TYPE
-# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
-# endif /* ! SFS_TYPE */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif /* ! TZ_TYPE */
-#endif /* SYSTEM5 */
-
-/* general POSIX defines */
-#ifdef _POSIX_VERSION
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASWAITPID 1 /* has Posix waitpid(2) call */
-# if _POSIX_VERSION >= 199500 && !defined(USESETEUID)
-# define USESETEUID 1 /* has usable seteuid(2) call */
-# endif /* _POSIX_VERSION >= 199500 && !defined(USESETEUID) */
-#endif /* _POSIX_VERSION */
- /*
-** Tweaking for systems that (for example) claim to be BSD or POSIX
-** but don't have all the standard BSD or POSIX routines (boo hiss).
-*/
-
-#ifdef titan
-# undef HASINITGROUPS /* doesn't have initgroups(3) call */
-#endif /* titan */
-
-#ifdef _CRAYCOM
-# undef HASSETSID /* despite POSIX claim, doesn't have setsid */
-#endif /* _CRAYCOM */
-
-#ifdef MOTO
-# undef USESETEUID
-#endif /* MOTO */
-
-/*
-** Due to a "feature" in some operating systems such as Ultrix 4.3 and
-** HPUX 8.0, if you receive a "No route to host" message (ICMP message
-** ICMP_UNREACH_HOST) on _any_ connection, all connections to that host
-** are closed. Some firewalls return this error if you try to connect
-** to the IDENT port (113), so you can't receive email from these hosts
-** on these systems. The firewall really should use a more specific
-** message such as ICMP_UNREACH_PROTOCOL or _PORT or _FILTER_PROHIB. If
-** not explicitly set to zero above, default it on.
-*/
-
-#ifndef IDENTPROTO
-# define IDENTPROTO 1 /* use IDENT proto (RFC 1413) */
-#endif /* ! IDENTPROTO */
-
-#ifndef IP_SRCROUTE
-# define IP_SRCROUTE 1 /* Detect IP source routing */
-#endif /* ! IP_SRCROUTE */
-
-#ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 1 /* libc has getusershell(3) call */
-#endif /* ! HASGETUSERSHELL */
-
-#ifndef NETUNIX
-# define NETUNIX 1 /* include unix domain support */
-#endif /* ! NETUNIX */
-
-#ifndef HASRANDOM
-# define HASRANDOM 1 /* has random(3) support */
-#endif /* ! HASRANDOM */
-
-#ifndef HASFLOCK
-# define HASFLOCK 0 /* assume no flock(2) support */
-#endif /* ! HASFLOCK */
-
-#ifndef HASSETREUID
-# define HASSETREUID 0 /* assume no setreuid(2) call */
-#endif /* ! HASSETREUID */
-
-#ifndef HASFCHMOD
-# define HASFCHMOD 0 /* assume no fchmod(2) syscall */
-#endif /* ! HASFCHMOD */
-
-#ifndef USESETEUID
-# define USESETEUID 0 /* assume no seteuid(2) call or no saved ids */
-#endif /* ! USESETEUID */
-
-#ifndef HASSETRLIMIT
-# define HASSETRLIMIT 0 /* assume no setrlimit(2) support */
-#endif /* ! HASSETRLIMIT */
-
-#ifndef HASULIMIT
-# define HASULIMIT 0 /* assume no ulimit(2) support */
-#endif /* ! HASULIMIT */
-
-#ifndef SECUREWARE
-# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */
-#endif /* ! SECUREWARE */
-
-#ifndef USE_SIGLONGJMP
-# define USE_SIGLONGJMP 0 /* assume setjmp handles signals properly */
-#endif /* ! USE_SIGLONGJMP */
-
-#ifndef FDSET_CAST
-# define FDSET_CAST /* (empty) cast for fd_set arg to select */
-#endif /* ! FDSET_CAST */
-
-/*
-** Pick a mailer setuid method for changing the current uid
-*/
-
-#define USE_SETEUID 0
-#define USE_SETREUID 1
-#define USE_SETUID 2
-
-#if USESETEUID
-# define MAILER_SETUID_METHOD USE_SETEUID
-#else /* USESETEUID */
-# if HASSETREUID
-# define MAILER_SETUID_METHOD USE_SETREUID
-# else /* HASSETREUID */
-# define MAILER_SETUID_METHOD USE_SETUID
-# endif /* HASSETREUID */
-#endif /* USESETEUID */
-
-/*
-** If no type for argument two of getgroups call is defined, assume
-** it's an integer -- unfortunately, there seem to be several choices
-** here.
-*/
-
-#ifndef GIDSET_T
-# define GIDSET_T int
-#endif /* ! GIDSET_T */
-
-#ifndef UID_T
-# define UID_T uid_t
-#endif /* ! UID_T */
-
-#ifndef GID_T
-# define GID_T gid_t
-#endif /* ! GID_T */
-
-#ifndef SIZE_T
-# define SIZE_T size_t
-#endif /* ! SIZE_T */
-
-#ifndef MODE_T
-# define MODE_T mode_t
-#endif /* ! MODE_T */
-
-#ifndef ARGV_T
-# define ARGV_T char **
-#endif /* ! ARGV_T */
-
-#ifndef SOCKADDR_LEN_T
-# define SOCKADDR_LEN_T int
-#endif /* ! SOCKADDR_LEN_T */
-
-#ifndef SOCKOPT_LEN_T
-# define SOCKOPT_LEN_T int
-#endif /* ! SOCKOPT_LEN_T */
-
-#ifndef QUAD_T
-# define QUAD_T unsigned long
-#endif /* ! QUAD_T */
- /**********************************************************************
-** Remaining definitions should never have to be changed. They are
-** primarily to provide back compatibility for older systems -- for
-** example, it includes some POSIX compatibility definitions
-**********************************************************************/
-
-/* System 5 compatibility */
-#ifndef S_ISREG
-# define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG)
-#endif /* ! S_ISREG */
-#ifndef S_ISDIR
-# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR)
-#endif /* ! S_ISDIR */
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK)
-#endif /* !defined(S_ISLNK) && defined(S_IFLNK) */
-#if !defined(S_ISFIFO)
-# if defined(S_IFIFO)
-# define S_ISFIFO(foo) ((foo & S_IFMT) == S_IFIFO)
-# else /* defined(S_IFIFO) */
-# define S_ISFIFO(foo) FALSE
-# endif /* defined(S_IFIFO) */
-#endif /* !defined(S_ISFIFO) */
-#ifndef S_IRUSR
-# define S_IRUSR 0400
-#endif /* ! S_IRUSR */
-#ifndef S_IWUSR
-# define S_IWUSR 0200
-#endif /* ! S_IWUSR */
-#ifndef S_IRGRP
-# define S_IRGRP 0040
-#endif /* ! S_IRGRP */
-#ifndef S_IWGRP
-# define S_IWGRP 0020
-#endif /* ! S_IWGRP */
-#ifndef S_IROTH
-# define S_IROTH 0004
-#endif /* ! S_IROTH */
-#ifndef S_IWOTH
-# define S_IWOTH 0002
-#endif /* ! S_IWOTH */
-
-#ifndef O_ACCMODE
-# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif /* ! O_ACCMODE */
-
-/* close-on-exec flag */
-#ifndef FD_CLOEXEC
-# define FD_CLOEXEC 1
-#endif /* ! FD_CLOEXEC */
-
-/*
-** Older systems don't have this error code -- it should be in
-** /usr/include/sysexits.h.
-*/
-
-#ifndef EX_CONFIG
-# define EX_CONFIG 78 /* configuration error */
-#endif /* ! EX_CONFIG */
-
-/* pseudo-codes */
-#define EX_QUIT 22 /* drop out of server immediately */
-#define EX_RESTART 23 /* restart sendmail daemon */
-#define EX_SHUTDOWN 24 /* shutdown sendmail daemon */
-
-/* pseudo-code used for mci_setstat */
-#define EX_NOTSTICKY -5 /* don't save persistent status */
-
-
-/*
-** An "impossible" file mode to indicate that the file does not exist.
-*/
-
-#define ST_MODE_NOFILE 0171147 /* unlikely to occur */
-
-
-/* type of arbitrary pointer */
-#ifndef ARBPTR_T
-# define ARBPTR_T void *
-#endif /* ! ARBPTR_T */
-
-#ifndef __P
-# include "sendmail/cdefs.h"
-#endif /* ! __P */
-
-#if HESIOD && !defined(NAMED_BIND)
-# define NAMED_BIND 1 /* not one without the other */
-#endif /* HESIOD && !defined(NAMED_BIND) */
-
-# if NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno )
-extern int h_errno;
-# endif /* NAMED_BIND && !defined( __ksr__ ) && !defined( h_errno ) */
-
-#ifdef LDAPMAP
-# include <sys/time.h>
-# include <lber.h>
-# include <ldap.h>
-
-/* Some LDAP constants */
-# define LDAPMAP_FALSE 0
-# define LDAPMAP_TRUE 1
-
-/*
-** ldap_init(3) is broken in Umich 3.x and OpenLDAP 1.0/1.1.
-** Use the lack of LDAP_OPT_SIZELIMIT to detect old API implementations
-** and assume (falsely) that all old API implementations are broken.
-** (OpenLDAP 1.2 and later have a working ldap_init(), add -DUSE_LDAP_INIT)
-*/
-
-# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT)
-# define USE_LDAP_INIT 1
-# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT) */
-
-/*
-** LDAP_OPT_SIZELIMIT is not defined under Umich 3.x nor OpenLDAP 1.x,
-** hence ldap_set_option() must not exist.
-*/
-
-# if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION)
-# define USE_LDAP_SET_OPTION 1
-# endif /* defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION) */
-
-#endif /* LDAPMAP */
-
-/*
-** Do some required dependencies
-*/
-
-#if NETINET || NETINET6 || NETISO
-# ifndef SMTP
-# define SMTP 1 /* enable user and server SMTP */
-# endif /* ! SMTP */
-# ifndef QUEUE
-# define QUEUE 1 /* enable queueing */
-# endif /* ! QUEUE */
-# ifndef DAEMON
-# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */
-# endif /* ! DAEMON */
-#endif /* NETINET || NETINET6 || NETISO */
-
-
-/*
-** Arrange to use either varargs or stdargs
-*/
-
-#ifdef __STDC__
-
-# include <stdarg.h>
-
-# define VA_LOCAL_DECL va_list ap;
-# define VA_START(f) va_start(ap, f)
-# define VA_END va_end(ap)
-
-#else /* __STDC__ */
-
-# include <varargs.h>
-
-# define VA_LOCAL_DECL va_list ap;
-# define VA_START(f) va_start(ap)
-# define VA_END va_end(ap)
-
-#endif /* __STDC__ */
-
-#if HASUNAME
-# include <sys/utsname.h>
-# ifdef newstr
-# undef newstr
-# endif /* newstr */
-#else /* HASUNAME */
-# define NODE_LENGTH 32
-struct utsname
-{
- char nodename[NODE_LENGTH + 1];
-};
-#endif /* HASUNAME */
-
-#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V)
-# define MAXHOSTNAMELEN 256
-#endif /* !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V) */
-
-#if !defined(SIGCHLD) && defined(SIGCLD)
-# define SIGCHLD SIGCLD
-#endif /* !defined(SIGCHLD) && defined(SIGCLD) */
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif /* ! STDIN_FILENO */
-
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif /* ! STDOUT_FILENO */
-
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif /* ! STDERR_FILENO */
-
-#ifndef LOCK_SH
-# define LOCK_SH 0x01 /* shared lock */
-# define LOCK_EX 0x02 /* exclusive lock */
-# define LOCK_NB 0x04 /* non-blocking lock */
-# define LOCK_UN 0x08 /* unlock */
-#endif /* ! LOCK_SH */
-
-#ifndef S_IXOTH
-# define S_IXOTH (S_IEXEC >> 6)
-#endif /* ! S_IXOTH */
-
-#ifndef S_IXGRP
-# define S_IXGRP (S_IEXEC >> 3)
-#endif /* ! S_IXGRP */
-
-#ifndef S_IXUSR
-# define S_IXUSR (S_IEXEC)
-#endif /* ! S_IXUSR */
-
-#ifndef SEEK_SET
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-#endif /* ! SEEK_SET */
-
-#ifndef SIG_ERR
-# define SIG_ERR ((void (*)()) -1)
-#endif /* ! SIG_ERR */
-
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(st) (((st) >> 8) & 0377)
-#endif /* ! WEXITSTATUS */
-#ifndef WIFEXITED
-# define WIFEXITED(st) (((st) & 0377) == 0)
-#endif /* ! WIFEXITED */
-#ifndef WIFSTOPPED
-# define WIFSTOPPED(st) (((st) & 0100) == 0)
-#endif /* ! WIFSTOPPED */
-#ifndef WCOREDUMP
-# define WCOREDUMP(st) (((st) & 0200) != 0)
-#endif /* ! WCOREDUMP */
-#ifndef WTERMSIG
-# define WTERMSIG(st) (((st) & 0177))
-#endif /* ! WTERMSIG */
-
-#ifndef SIGFUNC_DEFINED
-typedef void (*sigfunc_t) __P((int));
-#endif /* ! SIGFUNC_DEFINED */
-#ifndef SIGFUNC_RETURN
-# define SIGFUNC_RETURN
-#endif /* ! SIGFUNC_RETURN */
-#ifndef SIGFUNC_DECL
-# define SIGFUNC_DECL void
-#endif /* ! SIGFUNC_DECL */
-
-/* size of syslog buffer */
-#ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024
-#endif /* ! SYSLOG_BUFSIZE */
-
-/*
-** Size of prescan buffer.
-** Despite comments in the _sendmail_ book, this probably should
-** not be changed; there are some hard-to-define dependencies.
-*/
-
-#define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */
-
-/* fork routine -- set above using #ifdef _osname_ or in Makefile */
-#ifndef FORK
-# define FORK fork /* function to call to fork mailer */
-#endif /* ! FORK */
-
-/* setting h_errno */
-#ifndef SM_SET_H_ERRNO
-# define SM_SET_H_ERRNO(err) h_errno = (err)
-#endif /* SM_SET_H_ERRNO */
-
-/* random routine -- set above using #ifdef _osname_ or in Makefile */
-#if HASRANDOM
-# define get_random() random()
-#else /* HASRANDOM */
-# define get_random() ((long) rand())
-# ifndef RANDOMSHIFT
-# define RANDOMSHIFT 8
-# endif /* RANDOMSHIFT */
-#endif /* HASRANDOM */
-
-/*
-** Default to using scanf in readcf.
-*/
-
-#ifndef SCANF
-# define SCANF 1
-#endif /* ! SCANF */
-
-#if _FFR_MILTER
-/* 32 bit type */
-# ifndef SM_INT32
-# define SM_INT32 int32_t
-# endif /* SM_INT32 */
-#endif /* _FFR_MILTER */
-
-/*
-** SVr4 and similar systems use different routines for setjmp/longjmp
-** with signal support
-*/
-
-#if USE_SIGLONGJMP
-# ifdef jmp_buf
-# undef jmp_buf
-# endif /* jmp_buf */
-# define jmp_buf sigjmp_buf
-# ifdef setjmp
-# undef setjmp
-# endif /* setjmp */
-# define setjmp(env) sigsetjmp(env, 1)
-# ifdef longjmp
-# undef longjmp
-# endif /* longjmp */
-# define longjmp(env, val) siglongjmp(env, val)
-#endif /* USE_SIGLONGJMP */
-
-#if !defined(NGROUPS_MAX) && defined(NGROUPS)
-# define NGROUPS_MAX NGROUPS /* POSIX naming convention */
-#endif /* !defined(NGROUPS_MAX) && defined(NGROUPS) */
-
-/*
-** Some snprintf() implementations are rumored not to NUL terminate.
-*/
-#if SNPRINTF_IS_BROKEN
-# ifdef snprintf
-# undef snprintf
-# endif /* snprintf */
-# define snprintf sm_snprintf
-# ifdef vsnprintf
-# undef vsnprintf
-# endif /* vsnprintf */
-# define vsnprintf sm_vsnprintf
-#endif /* SNPRINTF_IS_BROKEN */
-
-/*
-** If we don't have a system syslog, simulate it.
-*/
-
-#if !LOG
-# define LOG_EMERG 0 /* system is unusable */
-# define LOG_ALERT 1 /* action must be taken immediately */
-# define LOG_CRIT 2 /* critical conditions */
-# define LOG_ERR 3 /* error conditions */
-# define LOG_WARNING 4 /* warning conditions */
-# define LOG_NOTICE 5 /* normal but significant condition */
-# define LOG_INFO 6 /* informational */
-# define LOG_DEBUG 7 /* debug-level messages */
-#endif /* !LOG */
-
-#if SFIO
-# ifdef ERRLIST_PREDEFINED
-# undef ERRLIST_PREDEFINED
-# endif /* ERRLIST_PREDEFINED */
-# if !HASSNPRINTF
-# define HASSNPRINTF 1 /* sfio includes snprintf() */
-# endif /* !HASSNPRINTF */
-#endif /* SFIO */
-#ifndef SFIO_STDIO_COMPAT
-# define SFIO_STDIO_COMPAT 0
-#endif /* ! SFIO_STDIO_COMPAT */
+#include <sm/conf.h>
-#endif /* CONF_H */
+#endif /* ! CONF_H */
diff --git a/contrib/sendmail/src/control.c b/contrib/sendmail/src/control.c
index b30c63f..c319192 100644
--- a/contrib/sendmail/src/control.c
+++ b/contrib/sendmail/src/control.c
@@ -8,18 +8,20 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: control.c,v 8.44.14.20 2001/05/03 17:24:03 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: control.c,v 8.116 2001/12/13 21:51:38 gshapiro Exp $")
+
/* values for cmd_code */
-# define CMDERROR 0 /* bad command */
-# define CMDRESTART 1 /* restart daemon */
-# define CMDSHUTDOWN 2 /* end daemon */
-# define CMDHELP 3 /* help */
-# define CMDSTATUS 4 /* daemon status */
+#define CMDERROR 0 /* bad command */
+#define CMDRESTART 1 /* restart daemon */
+#define CMDSHUTDOWN 2 /* end daemon */
+#define CMDHELP 3 /* help */
+#define CMDSTATUS 4 /* daemon status */
+#define CMDMEMDUMP 5 /* dump memory, to find memory leaks */
+#if _FFR_CONTROL_MSTAT
+# define CMDMSTAT 6 /* daemon status, more info, tagged data */
+#endif /* _FFR_CONTROL_MSTAT */
struct cmd
{
@@ -33,13 +35,18 @@ static struct cmd CmdTab[] =
{ "restart", CMDRESTART },
{ "shutdown", CMDSHUTDOWN },
{ "status", CMDSTATUS },
+ { "memdump", CMDMEMDUMP },
+#if _FFR_CONTROL_MSTAT
+ { "mstat", CMDMSTAT },
+#endif /* _FFR_CONTROL_MSTAT */
{ NULL, CMDERROR }
};
+
int ControlSocket = -1;
- /*
+/*
** OPENCONTROLSOCKET -- create/open the daemon control named socket
**
** Creates and opens a named socket for external control over
@@ -55,13 +62,13 @@ int ControlSocket = -1;
int
opencontrolsocket()
{
-#if NETUNIX
+# if NETUNIX
int save_errno;
int rval;
long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
struct sockaddr_un controladdr;
- if (ControlSocketName == NULL)
+ if (ControlSocketName == NULL || *ControlSocketName == '\0')
return 0;
if (strlen(ControlSocketName) >= sizeof controladdr.sun_path)
@@ -87,8 +94,8 @@ opencontrolsocket()
(void) unlink(ControlSocketName);
memset(&controladdr, '\0', sizeof controladdr);
controladdr.sun_family = AF_UNIX;
- (void) strlcpy(controladdr.sun_path, ControlSocketName,
- sizeof controladdr.sun_path);
+ (void) sm_strlcpy(controladdr.sun_path, ControlSocketName,
+ sizeof controladdr.sun_path);
if (bind(ControlSocket, (struct sockaddr *) &controladdr,
sizeof controladdr) < 0)
@@ -115,11 +122,11 @@ opencontrolsocket()
sm_syslog(LOG_ALERT, NOQID,
"ownership change on %s to uid %d failed: %s",
ControlSocketName, (int) u,
- errstring(save_errno));
+ sm_errstring(save_errno));
message("050 ownership change on %s to uid %d failed: %s",
ControlSocketName, (int) u,
- errstring(save_errno));
- closecontrolsocket(TRUE);
+ sm_errstring(save_errno));
+ closecontrolsocket(true);
errno = save_errno;
return -1;
}
@@ -128,7 +135,7 @@ opencontrolsocket()
if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0)
{
save_errno = errno;
- closecontrolsocket(TRUE);
+ closecontrolsocket(true);
errno = save_errno;
return -1;
}
@@ -136,14 +143,14 @@ opencontrolsocket()
if (listen(ControlSocket, 8) < 0)
{
save_errno = errno;
- closecontrolsocket(TRUE);
+ closecontrolsocket(true);
errno = save_errno;
return -1;
}
-#endif /* NETUNIX */
+# endif /* NETUNIX */
return 0;
}
- /*
+/*
** CLOSECONTROLSOCKET -- close the daemon control named socket
**
** Close a named socket.
@@ -160,7 +167,7 @@ void
closecontrolsocket(fullclose)
bool fullclose;
{
-#if NETUNIX
+# if NETUNIX
long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
if (ControlSocket >= 0)
@@ -184,14 +191,14 @@ closecontrolsocket(fullclose)
{
sm_syslog(LOG_WARNING, NOQID,
"Could not remove control socket: %s",
- errstring(errno));
+ sm_errstring(errno));
return;
}
}
-#endif /* NETUNIX */
+# endif /* NETUNIX */
return;
}
- /*
+/*
** CLRCONTROL -- reset the control connection
**
** Parameters:
@@ -207,16 +214,13 @@ closecontrolsocket(fullclose)
void
clrcontrol()
{
-#if NETUNIX
+# if NETUNIX
if (ControlSocket >= 0)
(void) close(ControlSocket);
ControlSocket = -1;
-#endif /* NETUNIX */
+# endif /* NETUNIX */
}
-
-#ifndef NOT_SENDMAIL
-
- /*
+/*
** CONTROL_COMMAND -- read and process command from named socket
**
** Read and process the command from the opened socket.
@@ -232,6 +236,7 @@ clrcontrol()
static jmp_buf CtxControlTimeout;
+/* ARGSUSED0 */
static void
controltimeout(timeout)
time_t timeout;
@@ -252,17 +257,17 @@ control_command(sock, e)
ENVELOPE *e;
{
volatile int exitstat = EX_OK;
- FILE *s = NULL;
- EVENT *ev = NULL;
- FILE *traffic;
- FILE *oldout;
+ SM_FILE_T *s = NULL;
+ SM_EVENT *ev = NULL;
+ SM_FILE_T *traffic;
+ SM_FILE_T *oldout;
char *cmd;
char *p;
struct cmd *c;
char cmdbuf[MAXLINE];
char inp[MAXLINE];
- sm_setproctitle(FALSE, e, "control cmd read");
+ sm_setproctitle(false, e, "control cmd read");
if (TimeOuts.to_control > 0)
{
@@ -274,11 +279,12 @@ control_command(sock, e)
"timeout waiting for input during control command");
exit(EX_IOERR);
}
- ev = setevent(TimeOuts.to_control, controltimeout,
- TimeOuts.to_control);
+ ev = sm_setevent(TimeOuts.to_control, controltimeout,
+ TimeOuts.to_control);
}
- s = fdopen(sock, "r+");
+ s = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &sock,
+ SM_IO_RDWR, NULL);
if (s == NULL)
{
int save_errno = errno;
@@ -287,19 +293,20 @@ control_command(sock, e)
errno = save_errno;
exit(EX_IOERR);
}
- setbuf(s, NULL);
+ (void) sm_io_setvbuf(s, SM_TIME_DEFAULT, NULL,
+ SM_IO_NBF, SM_IO_BUFSIZ);
- if (fgets(inp, sizeof inp, s) == NULL)
+ if (sm_io_fgets(s, SM_TIME_DEFAULT, inp, sizeof inp) == NULL)
{
- (void) fclose(s);
+ (void) sm_io_close(s, SM_TIME_DEFAULT);
exit(EX_IOERR);
}
- (void) fflush(s);
+ (void) sm_io_flush(s, SM_TIME_DEFAULT);
/* clean up end of line */
- fixcrlf(inp, TRUE);
+ fixcrlf(inp, true);
- sm_setproctitle(FALSE, e, "control: %s", inp);
+ sm_setproctitle(false, e, "control: %s", inp);
/* break off command */
for (p = inp; isascii(*p) && isspace(*p); p++)
@@ -318,7 +325,7 @@ control_command(sock, e)
/* decode command */
for (c = CmdTab; c->cmd_name != NULL; c++)
{
- if (strcasecmp(c->cmd_name, cmdbuf) == 0)
+ if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0)
break;
}
@@ -335,45 +342,87 @@ control_command(sock, e)
break;
case CMDRESTART: /* restart the daemon */
- fprintf(s, "OK\r\n");
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n");
exitstat = EX_RESTART;
break;
case CMDSHUTDOWN: /* kill the daemon */
- fprintf(s, "OK\r\n");
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n");
exitstat = EX_SHUTDOWN;
break;
case CMDSTATUS: /* daemon status */
proc_list_probe();
{
+ int qgrp;
long bsize;
long free;
- free = freediskspace(QueueDir, &bsize);
+ /* XXX need to deal with different partitions */
+ qgrp = e->e_qgrp;
+ if (!ISVALIDQGRP(qgrp))
+ qgrp = 0;
+ free = freediskspace(Queue[qgrp]->qg_qdir, &bsize);
/*
** Prevent overflow and don't lose
** precision (if bsize == 512)
*/
- free = (long)((double)free * ((double)bsize / 1024));
+ if (free > 0)
+ free = (long)((double) free *
+ ((double) bsize / 1024));
- fprintf(s, "%d/%d/%ld/%d\r\n",
- CurChildren, MaxChildren,
- free, sm_getla(NULL));
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "%d/%d/%ld/%d\r\n",
+ CurChildren, MaxChildren,
+ free, getla());
}
- proc_list_display(s);
+ proc_list_display(s, "");
+ break;
+
+# if _FFR_CONTROL_MSTAT
+ case CMDMSTAT: /* daemon status, extended, tagged format */
+ proc_list_probe();
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "C:%d\r\nM:%d\r\nL:%d\r\n",
+ CurChildren, MaxChildren,
+ getla());
+ printnqe(s, "Q:");
+ disk_status(s, "D:");
+ proc_list_display(s, "P:");
+ break;
+# endif /* _FFR_CONTROL_MSTAT */
+
+ case CMDMEMDUMP: /* daemon memory dump, to find memory leaks */
+# if SM_HEAP_CHECK
+ /* dump the heap, if we are checking for memory leaks */
+ if (sm_debug_active(&SmHeapCheck, 2))
+ {
+ sm_heap_report(s, sm_debug_level(&SmHeapCheck) - 1);
+ }
+ else
+ {
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "Memory dump unavailable.\r\n");
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "To fix, run sendmail with -dsm_check_heap.4\r\n");
+ }
+# else /* SM_HEAP_CHECK */
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "Memory dump unavailable.\r\n");
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "To fix, rebuild with -DSM_HEAP_CHECK\r\n");
+# endif /* SM_HEAP_CHECK */
break;
case CMDERROR: /* unknown command */
- fprintf(s, "Bad command (%s)\r\n", cmdbuf);
+ (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
+ "Bad command (%s)\r\n", cmdbuf);
break;
}
- (void) fclose(s);
+ (void) sm_io_close(s, SM_TIME_DEFAULT);
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
exit(exitstat);
}
-#endif /* ! NOT_SENDMAIL */
-
diff --git a/contrib/sendmail/src/convtime.c b/contrib/sendmail/src/convtime.c
index 9bed853..36edc1a 100644
--- a/contrib/sendmail/src/convtime.c
+++ b/contrib/sendmail/src/convtime.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,12 +11,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: convtime.c,v 8.25 1999/06/16 21:11:26 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: convtime.c,v 8.39 2001/09/11 04:05:13 gshapiro Exp $")
+
/*
** CONVTIME -- convert time
**
@@ -47,10 +45,16 @@ convtime(p, units)
{
register time_t t, r;
register char c;
+ bool pos = true;
r = 0;
- if (strcasecmp(p, "now") == 0)
+ if (sm_strcasecmp(p, "now") == 0)
return NOW;
+ if (*p == '-')
+ {
+ pos = false;
+ ++p;
+ }
while (*p != '\0')
{
t = 0;
@@ -92,14 +96,14 @@ convtime(p, units)
r += t;
}
- return r;
+ return pos ? r : -r;
}
- /*
+/*
** PINTVL -- produce printable version of a time interval
**
** Parameters:
** intvl -- the interval to be converted
-** brief -- if TRUE, print this in an extremely compact form
+** brief -- if true, print this in an extremely compact form
** (basically used for logging).
**
** Returns:
@@ -154,38 +158,43 @@ pintvl(intvl, brief)
{
if (dy > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), "%d+", dy);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "%d+", dy);
p += strlen(p);
}
- (void) snprintf(p, SPACELEFT(buf, p), "%02d:%02d:%02d",
- hr, mi, se);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "%02d:%02d:%02d",
+ hr, mi, se);
return buf;
}
/* use the verbose form */
if (wk > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), ", %d week%s", wk, PLURAL(wk));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), ", %d week%s", wk,
+ PLURAL(wk));
p += strlen(p);
}
if (dy > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), ", %d day%s", dy, PLURAL(dy));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), ", %d day%s", dy,
+ PLURAL(dy));
p += strlen(p);
}
if (hr > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), ", %d hour%s", hr, PLURAL(hr));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), ", %d hour%s", hr,
+ PLURAL(hr));
p += strlen(p);
}
if (mi > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), ", %d minute%s", mi, PLURAL(mi));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), ", %d minute%s", mi,
+ PLURAL(mi));
p += strlen(p);
}
if (se > 0)
{
- (void) snprintf(p, SPACELEFT(buf, p), ", %d second%s", se, PLURAL(se));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), ", %d second%s", se,
+ PLURAL(se));
p += strlen(p);
}
diff --git a/contrib/sendmail/src/daemon.c b/contrib/sendmail/src/daemon.c
index 954d253..c3e8dcc 100644
--- a/contrib/sendmail/src/daemon.c
+++ b/contrib/sendmail/src/daemon.c
@@ -13,20 +13,13 @@
#include <sendmail.h>
-
-#ifndef lint
-# ifdef DAEMON
-static char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (with daemon mode)";
-# else /* DAEMON */
-static char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (without daemon mode)";
-# endif /* DAEMON */
-#endif /* ! lint */
+SM_RCSID("@(#)$Id: daemon.c,v 8.603 2001/12/31 19:46:38 gshapiro Exp $")
#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
# define USE_SOCK_STREAM 1
#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
-#if DAEMON || defined(USE_SOCK_STREAM)
+#if defined(USE_SOCK_STREAM)
# if NETINET || NETINET6
# include <arpa/inet.h>
# endif /* NETINET || NETINET6 */
@@ -35,42 +28,42 @@ static char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro
# define NO_DATA NO_ADDRESS
# endif /* ! NO_DATA */
# endif /* NAMED_BIND */
-#endif /* DAEMON || defined(USE_SOCK_STREAM) */
-
-#if DAEMON
-
-# if STARTTLS
-# include <openssl/rand.h>
-# endif /* STARTTLS */
-
-# include <sys/time.h>
-
-# if IP_SRCROUTE && NETINET
-# include <netinet/in_systm.h>
-# include <netinet/ip.h>
-# if HAS_IN_H
-# include <netinet/in.h>
-# ifndef IPOPTION
-# define IPOPTION ip_opts
-# define IP_LIST ip_opts
-# define IP_DST ip_dst
-# endif /* ! IPOPTION */
-# else /* HAS_IN_H */
-# include <netinet/ip_var.h>
-# ifndef IPOPTION
-# define IPOPTION ipoption
-# define IP_LIST ipopt_list
-# define IP_DST ipopt_dst
-# endif /* ! IPOPTION */
-# endif /* HAS_IN_H */
-# endif /* IP_SRCROUTE && NETINET */
-
-/* structure to describe a daemon */
+#endif /* defined(USE_SOCK_STREAM) */
+
+#if STARTTLS
+# include <openssl/rand.h>
+#endif /* STARTTLS */
+
+#include <sys/time.h>
+
+#if IP_SRCROUTE && NETINET
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# if HAS_IN_H
+# include <netinet/in.h>
+# ifndef IPOPTION
+# define IPOPTION ip_opts
+# define IP_LIST ip_opts
+# define IP_DST ip_dst
+# endif /* ! IPOPTION */
+# else /* HAS_IN_H */
+# include <netinet/ip_var.h>
+# ifndef IPOPTION
+# define IPOPTION ipoption
+# define IP_LIST ipopt_list
+# define IP_DST ipopt_dst
+# endif /* ! IPOPTION */
+# endif /* HAS_IN_H */
+#endif /* IP_SRCROUTE && NETINET */
+
+#include <sm/fdset.h>
+
+/* structure to describe a daemon or a client */
struct daemon
{
int d_socket; /* fd for socket */
SOCKADDR d_addr; /* socket for incoming */
- u_short d_port; /* port number */
+ unsigned short d_port; /* port number */
int d_listenqueue; /* size of listen queue */
int d_tcprcvbufsize; /* size of TCP receive buffer */
int d_tcpsndbufsize; /* size of TCP send buffer */
@@ -80,15 +73,20 @@ struct daemon
BITMAP256 d_flags; /* flags; see sendmail.h */
char *d_mflags; /* flags for use in macro */
char *d_name; /* user-supplied name */
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+ char *d_inputfilterlist;
+ struct milter *d_inputfilters[MAXFILTERS];
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
};
typedef struct daemon DAEMON_T;
-static void connecttimeout __P((void));
-static int opendaemonsocket __P((struct daemon *, bool));
-static u_short setupdaemon __P((SOCKADDR *));
-static SIGFUNC_DECL sighup __P((int));
-static void restart_daemon __P((void));
+static void connecttimeout __P((void));
+static int opendaemonsocket __P((DAEMON_T *, bool));
+static unsigned short setupdaemon __P((SOCKADDR *));
+static void getrequests_checkdiskspace __P((ENVELOPE *e));
/*
** DAEMON.C -- routines to use when running as a daemon.
@@ -110,24 +108,20 @@ static void restart_daemon __P((void));
** etc., to avoid having extra file descriptors during
** the queue run and to avoid confusing the network
** code (if it cares).
-** makeconnection(host, port, outfile, infile, e)
+** makeconnection(host, port, mci, e, enough)
** Make a connection to the named host on the given
-** port. Set *outfile and *infile to the files
-** appropriate for communication. Returns zero on
-** success, else an exit status describing the
-** error.
+** port. Returns zero on success, else an exit status
+** describing the error.
** host_map_lookup(map, hbuf, avp, pstat)
** Convert the entry in hbuf into a canonical form.
*/
static DAEMON_T Daemons[MAXDAEMONS];
-static int ndaemons = 0; /* actual number of daemons */
+static int NDaemons = 0; /* actual number of daemons */
-/* options for client */
-static int TcpRcvBufferSize = 0; /* size of TCP receive buffer */
-static int TcpSndBufferSize = 0; /* size of TCP send buffer */
+static time_t NextDiskSpaceCheck = 0;
- /*
+/*
** GETREQUESTS -- open mail IPC port and get requests.
**
** Parameters:
@@ -143,6 +137,8 @@ static int TcpSndBufferSize = 0; /* size of TCP send buffer */
** routine is always in the child. The file pointers
** "InChannel" and "OutChannel" should be set to point
** to the communication channel.
+** May restart persistent queue runners if they have ended
+** for some reason.
*/
BITMAP256 *
@@ -150,12 +146,11 @@ getrequests(e)
ENVELOPE *e;
{
int t;
- time_t last_disk_space_check = 0;
int idx, curdaemon = -1;
int i, olddaemon = 0;
-# if XDEBUG
+#if XDEBUG
bool j_has_dot;
-# endif /* XDEBUG */
+#endif /* XDEBUG */
char status[MAXLINE];
SOCKADDR sa;
SOCKADDR_LEN_T len = sizeof sa;
@@ -163,12 +158,13 @@ getrequests(e)
extern int ControlSocket;
# endif /* NETUNIX */
extern ENVELOPE BlankEnvelope;
+ extern bool refuseconnections __P((char *, ENVELOPE *, int, bool));
- for (idx = 0; idx < ndaemons; idx++)
+ for (idx = 0; idx < NDaemons; idx++)
{
Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
- Daemons[idx].d_firsttime = TRUE;
+ Daemons[idx].d_firsttime = true;
Daemons[idx].d_refuse_connections_until = (time_t) 0;
}
@@ -178,48 +174,45 @@ getrequests(e)
if (tTd(15, 1))
{
- for (idx = 0; idx < ndaemons; idx++)
+ for (idx = 0; idx < NDaemons; idx++)
{
- dprintf("getrequests: daemon %s: port %d\n",
- Daemons[idx].d_name,
- ntohs(Daemons[idx].d_port));
+ sm_dprintf("getrequests: daemon %s: port %d\n",
+ Daemons[idx].d_name,
+ ntohs(Daemons[idx].d_port));
}
}
/* get a socket for the SMTP connection */
- for (idx = 0; idx < ndaemons; idx++)
- Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], TRUE);
+ for (idx = 0; idx < NDaemons; idx++)
+ Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true);
if (opencontrolsocket() < 0)
sm_syslog(LOG_WARNING, NOQID,
"daemon could not open control socket %s: %s",
- ControlSocketName, errstring(errno));
+ ControlSocketName, sm_errstring(errno));
- (void) setsignal(SIGCHLD, reapchild);
- (void) setsignal(SIGHUP, sighup);
+ /* If there are any queue runners released reapchild() co-ord's */
+ (void) sm_signal(SIGCHLD, reapchild);
- /* workaround: can't seem to release the signal in the parent */
- (void) releasesignal(SIGHUP);
-
- /* write the pid to file */
+ /* write the pid to file, command line args to syslog */
log_sendmail_pid(e);
-# if XDEBUG
+#if XDEBUG
{
char jbuf[MAXHOSTNAMELEN];
expand("\201j", jbuf, sizeof jbuf, e);
j_has_dot = strchr(jbuf, '.') != NULL;
}
-# endif /* XDEBUG */
+#endif /* XDEBUG */
/* Add parent process as first item */
- proc_list_add(getpid(), "Sendmail daemon", PROC_DAEMON);
+ proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1);
if (tTd(15, 1))
{
- for (idx = 0; idx < ndaemons; idx++)
- dprintf("getrequests: daemon %s: %d\n",
+ for (idx = 0; idx < NDaemons; idx++)
+ sm_dprintf("getrequests: daemon %s: %d\n",
Daemons[idx].d_name,
Daemons[idx].d_socket);
}
@@ -228,60 +221,39 @@ getrequests(e)
{
register pid_t pid;
auto SOCKADDR_LEN_T lotherend;
- bool timedout = FALSE;
- bool control = FALSE;
+ bool timedout = false;
+ bool control = false;
int save_errno;
int pipefd[2];
- time_t timenow;
-# if STARTTLS
+ time_t now;
+#if STARTTLS
long seed;
-# endif /* STARTTLS */
- extern bool refuseconnections __P((char *, ENVELOPE *, int));
+#endif /* STARTTLS */
/* see if we are rejecting connections */
- (void) blocksignal(SIGALRM);
+ (void) sm_blocksignal(SIGALRM);
if (ShutdownRequest != NULL)
shutdown_daemon();
else if (RestartRequest != NULL)
restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
- timenow = curtime();
-
- /*
- ** Use ConnRateThrottle only if the
- ** last pass was for a connection
- */
-
- if (ConnRateThrottle > 0 && curdaemon >= 0)
+ for (idx = 0; idx < NDaemons; idx++)
{
- static int conncnt = 0;
- static time_t lastconn = 0;
-
- if (timenow != lastconn)
- {
- lastconn = timenow;
- conncnt = 1;
- }
- else if (++conncnt > ConnRateThrottle)
- {
- /* sleep to flatten out connection load */
- sm_setproctitle(TRUE, e,
- "deferring connections: %d per second",
- ConnRateThrottle);
- if (LogLevel >= 9)
- sm_syslog(LOG_INFO, NOQID,
- "deferring connections: %d per second",
- ConnRateThrottle);
- (void) sleep(1);
- }
- }
+ /*
+ ** XXX do this call outside the loop?
+ ** no: refuse_connections may sleep().
+ */
- for (idx = 0; idx < ndaemons; idx++)
- {
- if (timenow < Daemons[idx].d_refuse_connections_until)
+ now = curtime();
+ if (now < Daemons[idx].d_refuse_connections_until)
continue;
- if (refuseconnections(Daemons[idx].d_name, e, idx))
+ if (bitnset(D_DISABLE, Daemons[idx].d_flags))
+ continue;
+ if (refuseconnections(Daemons[idx].d_name, e, idx,
+ curdaemon == idx))
{
if (Daemons[idx].d_socket >= 0)
{
@@ -291,19 +263,19 @@ getrequests(e)
}
/* refuse connections for next 15 seconds */
- Daemons[idx].d_refuse_connections_until = timenow + 15;
+ Daemons[idx].d_refuse_connections_until = now + 15;
}
else if (Daemons[idx].d_socket < 0 ||
Daemons[idx].d_firsttime)
{
- if (!Daemons[idx].d_firsttime && LogLevel >= 9)
+ if (!Daemons[idx].d_firsttime && LogLevel > 8)
sm_syslog(LOG_INFO, NOQID,
"accepting connections again for daemon %s",
Daemons[idx].d_name);
/* arrange to (re)open the socket if needed */
- (void) opendaemonsocket(&Daemons[idx], FALSE);
- Daemons[idx].d_firsttime = FALSE;
+ (void) opendaemonsocket(&Daemons[idx], false);
+ Daemons[idx].d_firsttime = false;
}
}
@@ -312,58 +284,12 @@ getrequests(e)
shutdown_daemon();
else if (RestartRequest != NULL)
restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
- if (timenow >= last_disk_space_check)
- {
- bool logged = FALSE;
-
- if (!enoughdiskspace(MinBlocksFree + 1, FALSE))
- {
- for (idx = 0; idx < ndaemons; idx++)
- {
- if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
- {
- /* log only if not logged before */
- if (!logged)
- {
- if (LogLevel >= 9)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting new messages: min free: %ld",
- MinBlocksFree);
- logged = TRUE;
- sm_setproctitle(TRUE, e,
- "rejecting new messages: min free: %ld",
- MinBlocksFree);
- }
- setbitn(D_ETRNONLY, Daemons[idx].d_flags);
- }
- }
- }
- else
- {
- for (idx = 0; idx < ndaemons; idx++)
- {
- if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
- {
- /* log only if not logged before */
- if (!logged)
- {
- if (LogLevel >= 9)
- sm_syslog(LOG_INFO, NOQID,
- "accepting new messages (again)");
- logged = TRUE;
- }
-
- /* title will be set below */
- clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
- }
- }
- }
- /* only check disk space once a minute */
- last_disk_space_check = timenow + 60;
- }
+ getrequests_checkdiskspace(e);
-# if XDEBUG
+#if XDEBUG
/* check for disaster */
{
char jbuf[MAXHOSTNAMELEN];
@@ -384,9 +310,9 @@ getrequests(e)
abort();
}
}
-# endif /* XDEBUG */
+#endif /* XDEBUG */
-# if 0
+#if 0
/*
** Andrew Sun <asun@ieps-sun.ml.com> claims that this will
** fix the SVr4 problem. But it seems to have gone away,
@@ -394,14 +320,14 @@ getrequests(e)
*/
if (DaemonSocket >= 0 &&
- SetNonBlocking(DaemonSocket, FALSE) < 0)
+ SetNonBlocking(DaemonSocket, false) < 0)
log an error here;
-# endif /* 0 */
- (void) releasesignal(SIGALRM);
+#endif /* 0 */
+ (void) sm_releasesignal(SIGALRM);
for (;;)
{
- bool setproc = FALSE;
+ bool setproc = false;
int highest = -1;
fd_set readfds;
struct timeval timeout;
@@ -410,10 +336,12 @@ getrequests(e)
shutdown_daemon();
else if (RestartRequest != NULL)
restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
FD_ZERO(&readfds);
- for (idx = 0; idx < ndaemons; idx++)
+ for (idx = 0; idx < NDaemons; idx++)
{
/* wait for a connection */
if (Daemons[idx].d_socket >= 0)
@@ -422,24 +350,25 @@ getrequests(e)
!bitnset(D_ETRNONLY,
Daemons[idx].d_flags))
{
- sm_setproctitle(TRUE, e,
+ sm_setproctitle(true, e,
"accepting connections");
- setproc = TRUE;
+ setproc = true;
}
if (Daemons[idx].d_socket > highest)
highest = Daemons[idx].d_socket;
- FD_SET((u_int)Daemons[idx].d_socket, &readfds);
+ SM_FD_SET(Daemons[idx].d_socket,
+ &readfds);
}
}
-# if NETUNIX
+#if NETUNIX
if (ControlSocket >= 0)
{
if (ControlSocket > highest)
highest = ControlSocket;
- FD_SET(ControlSocket, &readfds);
+ SM_FD_SET(ControlSocket, &readfds);
}
-# endif /* NETUNIX */
+#endif /* NETUNIX */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
@@ -452,29 +381,32 @@ getrequests(e)
shutdown_daemon();
else if (RestartRequest != NULL)
restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
- if (DoQueueRun)
- (void) runqueue(TRUE, FALSE);
-
curdaemon = -1;
+ if (doqueuerun())
+ (void) runqueue(true, false, false, false);
+
if (t <= 0)
{
- timedout = TRUE;
+ timedout = true;
break;
}
- control = FALSE;
+ control = false;
errno = 0;
/* look "round-robin" for an active socket */
- if ((idx = olddaemon + 1) >= ndaemons)
+ if ((idx = olddaemon + 1) >= NDaemons)
idx = 0;
- for (i = 0; i < ndaemons; i++)
+ for (i = 0; i < NDaemons; i++)
{
if (Daemons[idx].d_socket >= 0 &&
- FD_ISSET(Daemons[idx].d_socket, &readfds))
+ SM_FD_ISSET(Daemons[idx].d_socket,
+ &readfds))
{
lotherend = Daemons[idx].d_socksize;
memset(&RealHostAddr, '\0',
@@ -503,12 +435,12 @@ getrequests(e)
olddaemon = curdaemon = idx;
break;
}
- if (++idx >= ndaemons)
+ if (++idx >= NDaemons)
idx = 0;
}
-# if NETUNIX
+#if NETUNIX
if (curdaemon == -1 && ControlSocket >= 0 &&
- FD_ISSET(ControlSocket, &readfds))
+ SM_FD_ISSET(ControlSocket, &readfds))
{
struct sockaddr_un sa_un;
@@ -536,26 +468,25 @@ getrequests(e)
errno = EINVAL;
}
if (t >= 0)
- control = TRUE;
+ control = true;
}
-# else /* NETUNIX */
+#else /* NETUNIX */
if (curdaemon == -1)
{
/* No daemon to service */
continue;
}
-# endif /* NETUNIX */
+#endif /* NETUNIX */
if (t >= 0 || errno != EINTR)
break;
}
if (timedout)
{
- timedout = FALSE;
+ timedout = false;
continue;
}
save_errno = errno;
- timenow = curtime();
- (void) blocksignal(SIGALRM);
+ (void) sm_blocksignal(SIGALRM);
if (t < 0)
{
errno = save_errno;
@@ -564,15 +495,15 @@ getrequests(e)
/* arrange to re-open the socket next time around */
(void) close(Daemons[curdaemon].d_socket);
Daemons[curdaemon].d_socket = -1;
-# if SO_REUSEADDR_IS_BROKEN
+#if SO_REUSEADDR_IS_BROKEN
/*
** Give time for bound socket to be released.
** This creates a denial-of-service if you can
** force accept() to fail on affected systems.
*/
- Daemons[curdaemon].d_refuse_connections_until = timenow + 15;
-# endif /* SO_REUSEADDR_IS_BROKEN */
+ Daemons[curdaemon].d_refuse_connections_until = curtime() + 15;
+#endif /* SO_REUSEADDR_IS_BROKEN */
continue;
}
@@ -582,49 +513,58 @@ getrequests(e)
switch (Daemons[curdaemon].d_addr.sa.sa_family)
{
case AF_UNSPEC:
- define(macid("{daemon_family}", NULL),
- "unspec", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "unspec");
break;
-# if NETINET
+#if _FFR_DAEMON_NETUNIX
+# if NETUNIX
+ case AF_UNIX:
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "local");
+ break;
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
+#if NETINET
case AF_INET:
- define(macid("{daemon_family}", NULL),
- "inet", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "inet");
break;
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
case AF_INET6:
- define(macid("{daemon_family}", NULL),
- "inet6", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "inet6");
break;
-# endif /* NETINET6 */
-# if NETISO
+#endif /* NETINET6 */
+#if NETISO
case AF_ISO:
- define(macid("{daemon_family}", NULL),
- "iso", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "iso");
break;
-# endif /* NETISO */
-# if NETNS
+#endif /* NETISO */
+#if NETNS
case AF_NS:
- define(macid("{daemon_family}", NULL),
- "ns", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "ns");
break;
-# endif /* NETNS */
-# if NETX25
+#endif /* NETNS */
+#if NETX25
case AF_CCITT:
- define(macid("{daemon_family}", NULL),
- "x.25", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_family}"), "x.25");
break;
-# endif /* NETX25 */
+#endif /* NETX25 */
}
- define(macid("{daemon_name}", NULL),
- Daemons[curdaemon].d_name, &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_name}"),
+ Daemons[curdaemon].d_name);
if (Daemons[curdaemon].d_mflags != NULL)
- define(macid("{daemon_flags}", NULL),
- Daemons[curdaemon].d_mflags,
- &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_flags}"),
+ Daemons[curdaemon].d_mflags);
else
- define(macid("{daemon_flags}", NULL),
- "", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_flags}"), "");
}
/*
@@ -632,26 +572,38 @@ getrequests(e)
*/
if (tTd(15, 2))
- dprintf("getrequests: forking (fd = %d)\n", t);
+ sm_dprintf("getrequests: forking (fd = %d)\n", t);
/*
- ** advance state of PRNG
- ** this is necessary because otherwise all child processes
+ ** Advance state of PRNG.
+ ** This is necessary because otherwise all child processes
** will produce the same PRN sequence and hence the selection
** of a queue directory (and other things, e.g., MX selection)
** are not "really" random.
*/
-# if STARTTLS
+#if STARTTLS
+ /* XXX get some better "random" data? */
seed = get_random();
- RAND_seed((void *) &last_disk_space_check,
- sizeof last_disk_space_check);
- RAND_seed((void *) &timenow, sizeof timenow);
+ RAND_seed((void *) &NextDiskSpaceCheck,
+ sizeof NextDiskSpaceCheck);
+ RAND_seed((void *) &now, sizeof now);
RAND_seed((void *) &seed, sizeof seed);
-# else /* STARTTLS */
+#else /* STARTTLS */
(void) get_random();
-# endif /* STARTTLS */
+#endif /* STARTTLS */
-#ifndef DEBUG_NO_FORK
+#if NAMED_BIND
+ /*
+ ** Update MX records for FallBackMX.
+ ** Let's hope this is fast otherwise we screw up the
+ ** response time.
+ */
+
+ if (FallBackMX != NULL)
+ (void) getfallbackmxrr(FallBackMX);
+#endif /* NAMED_BIND */
+
+#if !PROFILING
/*
** Create a pipe to keep the child from writing to the
** socket until after the parent has closed it. Otherwise
@@ -661,7 +613,7 @@ getrequests(e)
if (pipe(pipefd) < 0)
pipefd[0] = pipefd[1] = -1;
- (void) blocksignal(SIGCHLD);
+ (void) sm_blocksignal(SIGCHLD);
pid = fork();
if (pid < 0)
{
@@ -671,19 +623,20 @@ getrequests(e)
(void) close(pipefd[0]);
(void) close(pipefd[1]);
}
- (void) releasesignal(SIGCHLD);
+ (void) sm_releasesignal(SIGCHLD);
(void) sleep(10);
(void) close(t);
continue;
}
-#else /* ! DEBUG_NO_FORK */
+
+#else /* !PROFILING */
pid = 0;
-#endif /* ! DEBUG_NO_FORK */
+#endif /* !PROFILING */
if (pid == 0)
{
char *p;
- FILE *inchannel, *outchannel = NULL;
+ SM_FILE_T *inchannel, *outchannel = NULL;
/*
** CHILD -- return to caller.
@@ -693,27 +646,39 @@ getrequests(e)
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
+ CurrentPid = getpid();
- (void) releasesignal(SIGALRM);
- (void) releasesignal(SIGCHLD);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_DFL);
- (void) setsignal(SIGTERM, intsig);
+ (void) sm_releasesignal(SIGALRM);
+ (void) sm_releasesignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_DFL);
+ (void) sm_signal(SIGTERM, intsig);
+
+ /* turn on profiling */
+ /* SM_PROF(0); */
+
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ sm_exc_newthread(fatal_error);
if (!control)
{
- define(macid("{daemon_addr}", NULL),
- newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)),
- &BlankEnvelope);
- (void) snprintf(status, sizeof status, "%d",
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{daemon_addr}"),
+ anynet_ntoa(&Daemons[curdaemon].d_addr));
+ (void) sm_snprintf(status, sizeof status, "%d",
ntohs(Daemons[curdaemon].d_port));
- define(macid("{daemon_port}", NULL),
- newstr(status), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{daemon_port}"), status);
}
- for (idx = 0; idx < ndaemons; idx++)
+ for (idx = 0; idx < NDaemons; idx++)
{
if (Daemons[idx].d_socket >= 0)
(void) close(Daemons[idx].d_socket);
@@ -725,25 +690,29 @@ getrequests(e)
if (control)
{
/* Add control socket process */
- proc_list_add(getpid(), "console socket child",
- PROC_CONTROL_CHILD);
+ proc_list_add(CurrentPid,
+ "console socket child",
+ PROC_CONTROL_CHILD, 0, -1);
}
else
{
proc_list_clear();
+ /* clean up background delivery children */
+ (void) sm_signal(SIGCHLD, reapchild);
+
/* Add parent process as first child item */
- proc_list_add(getpid(), "daemon child",
- PROC_DAEMON_CHILD);
+ proc_list_add(CurrentPid, "daemon child",
+ PROC_DAEMON_CHILD, 0, -1);
/* don't schedule queue runs if ETRN */
QueueIntvl = 0;
- sm_setproctitle(TRUE, e, "startup with %s",
+ sm_setproctitle(true, e, "startup with %s",
anynet_ntoa(&RealHostAddr));
}
-#ifndef DEBUG_NO_FORK
+#if !PROFILING
if (pipefd[0] != -1)
{
auto char c;
@@ -765,99 +734,115 @@ getrequests(e)
continue;
(void) close(pipefd[0]);
}
-#endif /* ! DEBUG_NO_FORK */
+#endif /* !PROFILING */
/* control socket processing */
if (control)
{
control_command(t, e);
-
/* NOTREACHED */
exit(EX_SOFTWARE);
}
/* determine host name */
p = hostnamebyanyaddr(&RealHostAddr);
- if (strlen(p) > (SIZE_T) MAXNAME)
+ if (strlen(p) > MAXNAME) /* XXX - 1 ? */
p[MAXNAME] = '\0';
RealHostName = newstr(p);
if (RealHostName[0] == '[')
{
- /* TEMP, FAIL: which one? */
- define(macid("{client_resolve}", NULL),
- (h_errno == TRY_AGAIN) ? "TEMP" : "FAIL",
- &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{client_resolve}"),
+ h_errno == TRY_AGAIN ? "TEMP" : "FAIL");
}
else
- define(macid("{client_resolve}", NULL), "OK",
- &BlankEnvelope);
- sm_setproctitle(TRUE, e, "startup with %s", p);
-
- if ((inchannel = fdopen(t, "r")) == NULL ||
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{client_resolve}"), "OK");
+ sm_setproctitle(true, e, "startup with %s", p);
+
+ if ((inchannel = sm_io_open(SmFtStdiofd,
+ SM_TIME_DEFAULT,
+ (void *) &t,
+ SM_IO_RDONLY,
+ NULL)) == NULL ||
(t = dup(t)) < 0 ||
- (outchannel = fdopen(t, "w")) == NULL)
+ (outchannel = sm_io_open(SmFtStdiofd,
+ SM_TIME_DEFAULT,
+ (void *) &t,
+ SM_IO_WRONLY,
+ NULL)) == NULL)
{
- syserr("cannot open SMTP server channel, fd=%d", t);
- finis(FALSE, EX_OK);
+ syserr("cannot open SMTP server channel, fd=%d",
+ t);
+ finis(false, true, EX_OK);
}
+ sm_io_automode(inchannel, outchannel);
InChannel = inchannel;
OutChannel = outchannel;
- DisConnected = FALSE;
+ DisConnected = false;
-# ifdef XLA
+#if XLA
if (!xla_host_ok(RealHostName))
{
message("421 4.4.5 Too many SMTP sessions for this host");
- finis(FALSE, EX_OK);
+ finis(false, true, EX_OK);
}
-# endif /* XLA */
+#endif /* XLA */
/* find out name for interface of connection */
- if (getsockname(fileno(InChannel), &sa.sa,
- &len) == 0)
+ if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
+ NULL), &sa.sa, &len) == 0)
{
p = hostnamebyanyaddr(&sa);
if (tTd(15, 9))
- dprintf("getreq: got name %s\n", p);
- define(macid("{if_name}", NULL),
- newstr(p), &BlankEnvelope);
+ sm_dprintf("getreq: got name %s\n", p);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_name}"), p);
+
+ /*
+ ** Do this only if it is not the loopback
+ ** interface.
+ */
- /* do this only if it is not the loopback */
- /* interface: how to figure out? XXX */
if (!isloopback(sa))
{
- define(macid("{if_addr}", NULL),
- newstr(anynet_ntoa(&sa)),
- &BlankEnvelope);
- p = xalloc(5);
- snprintf(p, 4, "%d", sa.sa.sa_family);
- define(macid("{if_family}", NULL), p,
- &BlankEnvelope);
+ char *addr;
+ char family[5];
+
+ addr = anynet_ntoa(&sa);
+ (void) sm_snprintf(family,
+ sizeof(family),
+ "%d", sa.sa.sa_family);
+ macdefine(&BlankEnvelope.e_macro,
+ A_TEMP,
+ macid("{if_addr}"), addr);
+ macdefine(&BlankEnvelope.e_macro,
+ A_TEMP,
+ macid("{if_family}"), family);
if (tTd(15, 7))
- dprintf("getreq: got addr %s and family %s\n",
- macvalue(macid("{if_addr}", NULL),
- &BlankEnvelope),
- macvalue(macid("{if_addr}", NULL),
- &BlankEnvelope));
+ sm_dprintf("getreq: got addr %s and family %s\n",
+ addr, family);
}
else
{
- define(macid("{if_addr}", NULL), NULL,
- &BlankEnvelope);
- define(macid("{if_family}", NULL), NULL,
- &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro,
+ A_PERM,
+ macid("{if_addr}"), NULL);
+ macdefine(&BlankEnvelope.e_macro,
+ A_PERM,
+ macid("{if_family}"), NULL);
}
}
else
{
if (tTd(15, 7))
- dprintf("getreq: getsockname failed\n");
- define(macid("{if_name}", NULL), NULL,
- &BlankEnvelope);
- define(macid("{if_addr}", NULL), NULL,
- &BlankEnvelope);
- define(macid("{if_family}", NULL), NULL,
- &BlankEnvelope);
+ sm_dprintf("getreq: getsockname failed\n");
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_name}"), NULL);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_addr}"), NULL);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_family}"), NULL);
}
break;
}
@@ -865,17 +850,18 @@ getrequests(e)
/* parent -- keep track of children */
if (control)
{
- snprintf(status, sizeof status, "control socket server child");
- proc_list_add(pid, status, PROC_CONTROL);
+ (void) sm_snprintf(status, sizeof status,
+ "control socket server child");
+ proc_list_add(pid, status, PROC_CONTROL, 0, -1);
}
else
{
- snprintf(status, sizeof status,
- "SMTP server child for %s",
- anynet_ntoa(&RealHostAddr));
- proc_list_add(pid, status, PROC_DAEMON);
+ (void) sm_snprintf(status, sizeof status,
+ "SMTP server child for %s",
+ anynet_ntoa(&RealHostAddr));
+ proc_list_add(pid, status, PROC_DAEMON, 0, -1);
}
- (void) releasesignal(SIGCHLD);
+ (void) sm_releasesignal(SIGCHLD);
/* close the read end of the synchronization pipe */
if (pipefd[0] != -1)
@@ -894,12 +880,103 @@ getrequests(e)
pipefd[1] = -1;
}
}
-
if (tTd(15, 2))
- dprintf("getreq: returning\n");
+ sm_dprintf("getreq: returning\n");
+
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+ /* set the filters for this daemon */
+ if (Daemons[curdaemon].d_inputfilterlist != NULL)
+ {
+ for (i = 0;
+ (Daemons[curdaemon].d_inputfilters[i] != NULL &&
+ i < MAXFILTERS);
+ i++)
+ {
+ InputFilters[i] = Daemons[curdaemon].d_inputfilters[i];
+ }
+ if (i < MAXFILTERS)
+ InputFilters[i] = NULL;
+ }
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
return &Daemons[curdaemon].d_flags;
}
- /*
+
+/*
+** GETREQUESTS_CHECKDISKSPACE -- check available diskspace.
+**
+** Parameters:
+** e -- envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Modifies Daemon flags (D_ETRNONLY) if not enough disk space.
+*/
+
+static void
+getrequests_checkdiskspace(e)
+ ENVELOPE *e;
+{
+ bool logged = false;
+ int idx;
+ time_t now;
+
+ now = curtime();
+ if (now < NextDiskSpaceCheck)
+ return;
+
+ /* Check if there is available disk space in all queue groups. */
+ if (!enoughdiskspace(0, NULL))
+ {
+ for (idx = 0; idx < NDaemons; ++idx)
+ {
+ if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
+ continue;
+
+ /* log only if not logged before */
+ if (!logged)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID,
+ "rejecting new messages: min free: %ld",
+ MinBlocksFree);
+ sm_setproctitle(true, e,
+ "rejecting new messages: min free: %ld",
+ MinBlocksFree);
+ logged = true;
+ }
+ setbitn(D_ETRNONLY, Daemons[idx].d_flags);
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < NDaemons; ++idx)
+ {
+ if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
+ continue;
+
+ /* log only if not logged before */
+ if (!logged)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID,
+ "accepting new messages (again)");
+ logged = true;
+ }
+
+ /* title will be set later */
+ clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
+ }
+ }
+
+ /* only check disk space once a minute */
+ NextDiskSpaceCheck = now + 60;
+}
+
+/*
** OPENDAEMONSOCKET -- open SMTP socket
**
** Deals with setting all appropriate options.
@@ -916,11 +993,11 @@ getrequests(e)
** Exits if the socket cannot be created.
*/
-# define MAXOPENTRIES 10 /* maximum number of tries to open connection */
+#define MAXOPENTRIES 10 /* maximum number of tries to open connection */
static int
opendaemonsocket(d, firsttime)
- struct daemon *d;
+ DAEMON_T *d;
bool firsttime;
{
int on = 1;
@@ -930,7 +1007,7 @@ opendaemonsocket(d, firsttime)
int save_errno;
if (tTd(15, 2))
- dprintf("opendaemonsocket(%s)\n", d->d_name);
+ sm_dprintf("opendaemonsocket(%s)\n", d->d_name);
do
{
@@ -938,16 +1015,55 @@ opendaemonsocket(d, firsttime)
(void) sleep(5);
if (firsttime || d->d_socket < 0)
{
+#if _FFR_DAEMON_NETUNIX
+# if NETUNIX
+ if (d->d_addr.sa.sa_family == AF_UNIX)
+ {
+ int rval;
+ long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT;
+
+ /* if not safe, don't use it */
+ rval = safefile(d->d_addr.sunix.sun_path,
+ RunAsUid, RunAsGid,
+ RunAsUserName, sff,
+ S_IRUSR|S_IWUSR, NULL);
+ if (rval != 0)
+ {
+ save_errno = errno;
+ syserr("opendaemonsocket: daemon %s: unsafe domain socket %s",
+ d->d_name,
+ d->d_addr.sunix.sun_path);
+ goto fail;
+ }
+
+ /* Don't try to overtake an existing socket */
+ (void) unlink(d->d_addr.sunix.sun_path);
+ }
+# endif /* NETUNIX */
+#endif /* _FFR_DOMAIN_NETUNIX */
d->d_socket = socket(d->d_addr.sa.sa_family,
SOCK_STREAM, 0);
if (d->d_socket < 0)
{
save_errno = errno;
- syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name);
+ syserr("opendaemonsocket: daemon %s: can't create server SMTP socket",
+ d->d_name);
+ fail:
+ if (bitnset(D_OPTIONAL, d->d_flags) &&
+ (!transienterror(save_errno) ||
+ ntries >= MAXOPENTRIES - 1))
+ {
+ syserr("opendaemonsocket: daemon %s: optional socket disabled",
+ d->d_name);
+ setbitn(D_DISABLE, d->d_flags);
+ d->d_socket = -1;
+ return -1;
+ }
severe:
if (LogLevel > 0)
sm_syslog(LOG_ALERT, NOQID,
- "daemon %s: problem creating SMTP socket", d->d_name);
+ "daemon %s: problem creating SMTP socket",
+ d->d_name);
d->d_socket = -1;
continue;
}
@@ -963,7 +1079,7 @@ opendaemonsocket(d, firsttime)
(void) setsockopt(d->d_socket, SOL_SOCKET,
SO_KEEPALIVE, (char *)&on, sizeof on);
-# ifdef SO_RCVBUF
+#ifdef SO_RCVBUF
if (d->d_tcprcvbufsize > 0)
{
if (setsockopt(d->d_socket, SOL_SOCKET,
@@ -972,8 +1088,8 @@ opendaemonsocket(d, firsttime)
sizeof(d->d_tcprcvbufsize)) < 0)
syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
}
-# endif /* SO_RCVBUF */
-# ifdef SO_SNDBUF
+#endif /* SO_RCVBUF */
+#ifdef SO_SNDBUF
if (d->d_tcpsndbufsize > 0)
{
if (setsockopt(d->d_socket, SOL_SOCKET,
@@ -982,7 +1098,7 @@ opendaemonsocket(d, firsttime)
sizeof(d->d_tcpsndbufsize)) < 0)
syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
}
-# endif /* SO_SNDBUF */
+#endif /* SO_SNDBUF */
if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
fcntl(d->d_socket, F_SETFD,
@@ -992,30 +1108,37 @@ opendaemonsocket(d, firsttime)
syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
d->d_name,
fdflags == -1 ? "get" : "set",
- errstring(save_errno));
+ sm_errstring(save_errno));
(void) close(d->d_socket);
goto severe;
}
switch (d->d_addr.sa.sa_family)
{
-# if NETINET
+#if _FFR_DAEMON_NETUNIX
+# ifdef NETUNIX
+ case AF_UNIX:
+ socksize = sizeof d->d_addr.sunix;
+ break;
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
+#if NETINET
case AF_INET:
socksize = sizeof d->d_addr.sin;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
socksize = sizeof d->d_addr.sin6;
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
-# if NETISO
+#if NETISO
case AF_ISO:
socksize = sizeof d->d_addr.siso;
break;
-# endif /* NETISO */
+#endif /* NETISO */
default:
socksize = sizeof d->d_addr;
@@ -1029,7 +1152,7 @@ opendaemonsocket(d, firsttime)
syserr("opendaemonsocket: daemon %s: cannot bind",
d->d_name);
(void) close(d->d_socket);
- goto severe;
+ goto fail;
}
}
if (!firsttime &&
@@ -1048,22 +1171,22 @@ opendaemonsocket(d, firsttime)
/* NOTREACHED */
return -1; /* avoid compiler warning on IRIX */
}
- /*
+/*
** SETUPDAEMON -- setup socket for daemon
**
** Parameters:
** daemonaddr -- socket for daemon
-** daemon -- number of daemon
**
** Returns:
** port number on which daemon should run
**
*/
-static u_short
+
+static unsigned short
setupdaemon(daemonaddr)
SOCKADDR *daemonaddr;
{
- u_short port;
+ unsigned short port;
/*
** Set up the address for the mailer.
@@ -1072,28 +1195,28 @@ setupdaemon(daemonaddr)
if (daemonaddr->sa.sa_family == AF_UNSPEC)
{
memset(daemonaddr, '\0', sizeof *daemonaddr);
-# if NETINET
+#if NETINET
daemonaddr->sa.sa_family = AF_INET;
-# endif /* NETINET */
+#endif /* NETINET */
}
switch (daemonaddr->sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (daemonaddr->sin.sin_addr.s_addr == 0)
daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
port = daemonaddr->sin.sin_port;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
daemonaddr->sin6.sin6_addr = in6addr_any;
port = daemonaddr->sin6.sin6_port;
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
/* unknown protocol */
@@ -1102,9 +1225,9 @@ setupdaemon(daemonaddr)
}
if (port == 0)
{
-# ifdef NO_GETSERVBYNAME
+#ifdef NO_GETSERVBYNAME
port = htons(25);
-# else /* NO_GETSERVBYNAME */
+#else /* NO_GETSERVBYNAME */
{
register struct servent *sp;
@@ -1117,30 +1240,30 @@ setupdaemon(daemonaddr)
else
port = sp->s_port;
}
-# endif /* NO_GETSERVBYNAME */
+#endif /* NO_GETSERVBYNAME */
}
switch (daemonaddr->sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
daemonaddr->sin.sin_port = port;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
daemonaddr->sin6.sin6_port = port;
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
/* unknown protocol */
break;
}
- return(port);
+ return port;
}
- /*
+/*
** CLRDAEMON -- reset the daemon connection
**
** Parameters:
@@ -1158,14 +1281,89 @@ clrdaemon()
{
int i;
- for (i = 0; i < ndaemons; i++)
+ for (i = 0; i < NDaemons; i++)
{
if (Daemons[i].d_socket >= 0)
(void) close(Daemons[i].d_socket);
Daemons[i].d_socket = -1;
}
}
- /*
+
+/*
+** GETMODIFIERS -- get modifier flags
+**
+** Parameters:
+** v -- the modifiers (input text line).
+** modifiers -- pointer to flag field to represent modifiers.
+**
+** Returns:
+** (xallocat()ed) string representation of modifiers.
+**
+** Side Effects:
+** fills in modifiers.
+*/
+
+char *
+getmodifiers(v, modifiers)
+ char *v;
+ BITMAP256 modifiers;
+{
+ int l;
+ char *h, *f, *flags;
+
+ /* maximum length of flags: upper case Option -> "OO " */
+ l = 3 * strlen(v) + 3;
+
+ /* is someone joking? */
+ if (l < 0 || l > 256)
+ {
+ if (LogLevel > 2)
+ sm_syslog(LOG_ERR, NOQID,
+ "getmodifiers too long, ignored");
+ return NULL;
+ }
+ flags = xalloc(l);
+ f = flags;
+ clrbitmap(modifiers);
+ for (h = v; *h != '\0'; h++)
+ {
+ if (isascii(*h) && !isspace(*h) && isprint(*h))
+ {
+ setbitn(*h, modifiers);
+ if (flags != f)
+ *flags++ = ' ';
+ *flags++ = *h;
+ if (isupper(*h))
+ *flags++ = *h;
+ }
+ }
+ *flags++ = '\0';
+ return f;
+}
+
+/*
+** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag.
+**
+** Parameters:
+** flag -- the flag to test.
+**
+** Returns:
+** true iff all daemons have set flag.
+*/
+
+bool
+chkdaemonmodifiers(flag)
+ int flag;
+{
+ int i;
+
+ for (i = 0; i < NDaemons; i++)
+ if (!bitnset((char) flag, Daemons[i].d_flags))
+ return false;
+ return true;
+}
+
+/*
** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
**
** Parameters:
@@ -1179,20 +1377,18 @@ clrdaemon()
static void
setsockaddroptions(p, d)
register char *p;
- struct daemon *d;
+ DAEMON_T *d;
{
-# if NETISO
+#if NETISO
short portno;
-# endif /* NETISO */
- int l;
- char *h, *flags;
+#endif /* NETISO */
char *port = NULL;
char *addr = NULL;
-# if NETINET
+#if NETINET
if (d->d_addr.sa.sa_family == AF_UNSPEC)
d->d_addr.sa.sa_family = AF_INET;
-# endif /* NETINET */
+#endif /* NETINET */
while (p != NULL)
{
@@ -1220,26 +1416,33 @@ setsockaddroptions(p, d)
case 'F': /* address family */
if (isascii(*v) && isdigit(*v))
d->d_addr.sa.sa_family = atoi(v);
-# if NETINET
- else if (strcasecmp(v, "inet") == 0)
+#if _FFR_DAEMON_NETUNIX
+# ifdef NETUNIX
+ else if (sm_strcasecmp(v, "unix") == 0 ||
+ sm_strcasecmp(v, "local") == 0)
+ d->d_addr.sa.sa_family = AF_UNIX;
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
+#if NETINET
+ else if (sm_strcasecmp(v, "inet") == 0)
d->d_addr.sa.sa_family = AF_INET;
-# endif /* NETINET */
-# if NETINET6
- else if (strcasecmp(v, "inet6") == 0)
+#endif /* NETINET */
+#if NETINET6
+ else if (sm_strcasecmp(v, "inet6") == 0)
d->d_addr.sa.sa_family = AF_INET6;
-# endif /* NETINET6 */
-# if NETISO
- else if (strcasecmp(v, "iso") == 0)
+#endif /* NETINET6 */
+#if NETISO
+ else if (sm_strcasecmp(v, "iso") == 0)
d->d_addr.sa.sa_family = AF_ISO;
-# endif /* NETISO */
-# if NETNS
- else if (strcasecmp(v, "ns") == 0)
+#endif /* NETISO */
+#if NETNS
+ else if (sm_strcasecmp(v, "ns") == 0)
d->d_addr.sa.sa_family = AF_NS;
-# endif /* NETNS */
-# if NETX25
- else if (strcasecmp(v, "x.25") == 0)
+#endif /* NETNS */
+#if NETX25
+ else if (sm_strcasecmp(v, "x.25") == 0)
d->d_addr.sa.sa_family = AF_CCITT;
-# endif /* NETX25 */
+#endif /* NETX25 */
else
syserr("554 5.3.5 Unknown address family %s in Family=option",
v);
@@ -1249,6 +1452,14 @@ setsockaddroptions(p, d)
addr = v;
break;
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+ case 'I':
+ d->d_inputfilterlist = v;
+ break;
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
+
case 'P': /* port */
port = v;
break;
@@ -1258,25 +1469,7 @@ setsockaddroptions(p, d)
break;
case 'M': /* modifiers (flags) */
- l = 3 * strlen(v) + 3;
- h = v;
- flags = xalloc(l);
- d->d_mflags = flags;
- for (; *h != '\0'; h++)
- {
- if (!(isascii(*h) && isspace(*h)))
- {
- if (flags != d->d_mflags)
- *flags++ = ' ';
- *flags++ = *h;
- if (isupper(*h))
- *flags++ = *h;
- }
- }
- *flags++ = '\0';
- for (; *v != '\0'; v++)
- if (!(isascii(*v) && isspace(*v)))
- setbitn(bitidx(*v), d->d_flags);
+ d->d_mflags = getmodifiers(v, d->d_flags);
break;
case 'S': /* send buffer size */
@@ -1302,10 +1495,31 @@ setsockaddroptions(p, d)
{
switch (d->d_addr.sa.sa_family)
{
-# if NETINET
+#if _FFR_DAEMON_NETUNIX
+# if NETUNIX
+ case AF_UNIX:
+ if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path))
+ {
+ errno = ENAMETOOLONG;
+ syserr("setsockaddroptions: domain socket name too long: %s > %d",
+ addr, sizeof(d->d_addr.sunix.sun_path));
+ break;
+ }
+
+ /* file safety check done in opendaemonsocket() */
+ (void) memset(&d->d_addr.sunix.sun_path, '\0',
+ sizeof(d->d_addr.sunix.sun_path));
+ (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path,
+ addr,
+ sizeof(d->d_addr.sunix.sun_path));
+ break;
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
+#if NETINET
case AF_INET:
if (!isascii(*addr) || !isdigit(*addr) ||
- ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE))
+ ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr))
+ == INADDR_NONE))
{
register struct hostent *hp;
@@ -1325,21 +1539,19 @@ setsockaddroptions(p, d)
memmove(&d->d_addr.sin.sin_addr,
*(hp->h_addr_list),
INADDRSZ);
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
freehostent(hp);
hp = NULL;
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
}
}
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
- if (!isascii(*addr) ||
- (!isxdigit(*addr) && *addr != ':') ||
- inet_pton(AF_INET6, addr,
- &d->d_addr.sin6.sin6_addr) != 1)
+ if (anynet_pton(AF_INET6, addr,
+ &d->d_addr.sin6.sin6_addr) != 1)
{
register struct hostent *hp;
@@ -1359,14 +1571,12 @@ setsockaddroptions(p, d)
memmove(&d->d_addr.sin6.sin6_addr,
*(hp->h_addr_list),
IN6ADDRSZ);
-# if _FFR_FREEHOSTENT
freehostent(hp);
hp = NULL;
-# endif /* _FFR_FREEHOSTENT */
}
}
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
syserr("554 5.3.5 address= option unsupported for family %d",
@@ -1379,16 +1589,17 @@ setsockaddroptions(p, d)
{
switch (d->d_addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (isascii(*port) && isdigit(*port))
- d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)port));
+ d->d_addr.sin.sin_port = htons((unsigned short)
+ atoi((const char *) port));
else
{
-# ifdef NO_GETSERVBYNAME
+# ifdef NO_GETSERVBYNAME
syserr("554 5.3.5 invalid port number: %s",
port);
-# else /* NO_GETSERVBYNAME */
+# else /* NO_GETSERVBYNAME */
register struct servent *sp;
sp = getservbyname(port, "tcp");
@@ -1397,21 +1608,22 @@ setsockaddroptions(p, d)
port);
else
d->d_addr.sin.sin_port = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
+# endif /* NO_GETSERVBYNAME */
}
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (isascii(*port) && isdigit(*port))
- d->d_addr.sin6.sin6_port = htons((u_short)atoi(port));
+ d->d_addr.sin6.sin6_port = htons((unsigned short)
+ atoi(port));
else
{
-# ifdef NO_GETSERVBYNAME
+# ifdef NO_GETSERVBYNAME
syserr("554 5.3.5 invalid port number: %s",
port);
-# else /* NO_GETSERVBYNAME */
+# else /* NO_GETSERVBYNAME */
register struct servent *sp;
sp = getservbyname(port, "tcp");
@@ -1420,22 +1632,22 @@ setsockaddroptions(p, d)
port);
else
d->d_addr.sin6.sin6_port = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
+# endif /* NO_GETSERVBYNAME */
}
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
-# if NETISO
+#if NETISO
case AF_ISO:
/* assume two byte transport selector */
if (isascii(*port) && isdigit(*port))
- portno = htons((u_short)atoi(port));
+ portno = htons((unsigned short) atoi(port));
else
{
-# ifdef NO_GETSERVBYNAME
+# ifdef NO_GETSERVBYNAME
syserr("554 5.3.5 invalid port number: %s",
port);
-# else /* NO_GETSERVBYNAME */
+# else /* NO_GETSERVBYNAME */
register struct servent *sp;
sp = getservbyname(port, "tcp");
@@ -1444,12 +1656,12 @@ setsockaddroptions(p, d)
port);
else
portno = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
+# endif /* NO_GETSERVBYNAME */
}
memmove(TSEL(&d->d_addr.siso),
(char *) &portno, 2);
break;
-# endif /* NETISO */
+#endif /* NETISO */
default:
syserr("554 5.3.5 Port= option unsupported for family %d",
@@ -1458,50 +1670,62 @@ setsockaddroptions(p, d)
}
}
}
- /*
+/*
** SETDAEMONOPTIONS -- set options for running the MTA daemon
**
** Parameters:
** p -- the options line.
**
** Returns:
-** TRUE if successful, FALSE otherwise.
+** true if successful, false otherwise.
+**
+** Side Effects:
+** increments number of daemons.
*/
+#define DEF_LISTENQUEUE 10
+
bool
setdaemonoptions(p)
register char *p;
{
- if (ndaemons >= MAXDAEMONS)
- return FALSE;
- Daemons[ndaemons].d_socket = -1;
- Daemons[ndaemons].d_listenqueue = 10;
- clrbitmap(Daemons[ndaemons].d_flags);
- setsockaddroptions(p, &Daemons[ndaemons]);
-
- if (Daemons[ndaemons].d_name != NULL)
- Daemons[ndaemons].d_name = newstr(Daemons[ndaemons].d_name);
+ if (NDaemons >= MAXDAEMONS)
+ return false;
+ Daemons[NDaemons].d_socket = -1;
+ Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
+ clrbitmap(Daemons[NDaemons].d_flags);
+ setsockaddroptions(p, &Daemons[NDaemons]);
+
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+ if (Daemons[NDaemons].d_inputfilterlist != NULL)
+ Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
+
+ if (Daemons[NDaemons].d_name != NULL)
+ Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
else
{
char num[30];
- snprintf(num, sizeof num, "Daemon%d", ndaemons);
- Daemons[ndaemons].d_name = newstr(num);
+ (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons);
+ Daemons[NDaemons].d_name = newstr(num);
}
if (tTd(37, 1))
{
- dprintf("Daemon %s flags: ", Daemons[ndaemons].d_name);
- if (bitnset(D_ETRNONLY, Daemons[ndaemons].d_flags))
- dprintf("ETRNONLY ");
- if (bitnset(D_NOETRN, Daemons[ndaemons].d_flags))
- dprintf("NOETRN ");
- dprintf("\n");
+ sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name);
+ if (bitnset(D_ETRNONLY, Daemons[NDaemons].d_flags))
+ sm_dprintf("ETRNONLY ");
+ if (bitnset(D_NOETRN, Daemons[NDaemons].d_flags))
+ sm_dprintf("NOETRN ");
+ sm_dprintf("\n");
}
- ++ndaemons;
- return TRUE;
+ ++NDaemons;
+ return true;
}
- /*
+/*
** INITDAEMON -- initialize daemon if not yet done.
**
** Parameters:
@@ -1513,18 +1737,19 @@ setdaemonoptions(p)
** Side Effects:
** initializes structure for one daemon.
*/
+
void
initdaemon()
{
- if (ndaemons == 0)
+ if (NDaemons == 0)
{
- Daemons[ndaemons].d_socket = -1;
- Daemons[ndaemons].d_listenqueue = 10;
- Daemons[ndaemons].d_name = "Daemon0";
- ndaemons = 1;
+ Daemons[NDaemons].d_socket = -1;
+ Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
+ Daemons[NDaemons].d_name = "Daemon0";
+ NDaemons = 1;
}
}
- /*
+/*
** SETCLIENTOPTIONS -- set options for running the client
**
** Parameters:
@@ -1534,29 +1759,33 @@ initdaemon()
** none.
*/
-static SOCKADDR ClientAddr; /* address for client */
+static DAEMON_T ClientSettings[AF_MAX + 1];
void
setclientoptions(p)
register char *p;
{
- struct daemon d;
- extern ENVELOPE BlankEnvelope;
+ int family;
+ DAEMON_T d;
memset(&d, '\0', sizeof d);
setsockaddroptions(p, &d);
/* grab what we need */
- memcpy(&ClientAddr, &d.d_addr, sizeof ClientAddr);
- TcpSndBufferSize = d.d_tcpsndbufsize;
- TcpRcvBufferSize = d.d_tcprcvbufsize;
- if (d.d_mflags != NULL)
- define(macid("{client_flags}", NULL), d.d_mflags,
- &BlankEnvelope);
+ family = d.d_addr.sa.sa_family;
+ STRUCTCOPY(d, ClientSettings[family]);
+ setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */
+ if (d.d_name != NULL)
+ ClientSettings[family].d_name = newstr(d.d_name);
else
- define(macid("{client_flags}", NULL), "", &BlankEnvelope);
+ {
+ char num[30];
+
+ (void) sm_snprintf(num, sizeof num, "Client%d", family);
+ ClientSettings[family].d_name = newstr(num);
+ }
}
- /*
+/*
** ADDR_FAMILY -- determine address family from address
**
** Parameters:
@@ -1573,31 +1802,107 @@ static int
addr_family(addr)
char *addr;
{
-# if NETINET6
+#if NETINET6
SOCKADDR clt_addr;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
-# if NETINET
+#if NETINET
if (inet_addr(addr) != INADDR_NONE)
{
if (tTd(16, 9))
- printf("addr_family(%s): INET\n", addr);
+ sm_dprintf("addr_family(%s): INET\n", addr);
return AF_INET;
}
-# endif /* NETINET */
-# if NETINET6
- if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
+#endif /* NETINET */
+#if NETINET6
+ if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
{
if (tTd(16, 9))
- printf("addr_family(%s): INET6\n", addr);
+ sm_dprintf("addr_family(%s): INET6\n", addr);
return AF_INET6;
}
-# endif /* NETINET6 */
+#endif /* NETINET6 */
+#if _FFR_DAEMON_NETUNIX
+# if NETUNIX
+ if (*addr == '/')
+ {
+ if (tTd(16, 9))
+ sm_dprintf("addr_family(%s): LOCAL\n", addr);
+ return AF_UNIX;
+ }
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
if (tTd(16, 9))
- printf("addr_family(%s): UNSPEC\n", addr);
+ sm_dprintf("addr_family(%s): UNSPEC\n", addr);
return AF_UNSPEC;
}
- /*
+
+/*
+** CHKCLIENTMODIFIERS -- check whether all clients have set a flag.
+**
+** Parameters:
+** flag -- the flag to test.
+**
+** Returns:
+** true iff all configured clients have set the flag.
+*/
+
+bool
+chkclientmodifiers(flag)
+ int flag;
+{
+ int i;
+ bool flagisset;
+
+ flagisset = false;
+ for (i = 0; i < AF_MAX; i++)
+ {
+ if (bitnset(D_ISSET, ClientSettings[i].d_flags))
+ {
+ if (!bitnset((char) flag, ClientSettings[i].d_flags))
+ return false;
+ flagisset = true;
+ }
+ }
+ return flagisset;
+}
+
+#if MILTER
+# if _FFR_MILTER_PERDAEMON
+/*
+** SETUP_DAEMON_FILTERS -- Parse per-socket filters
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+*/
+
+void
+setup_daemon_milters()
+{
+ int idx;
+
+ if (OpMode == MD_SMTP)
+ {
+ /* no need to configure the daemons */
+ return;
+ }
+
+ for (idx = 0; idx < NDaemons; idx++)
+ {
+ if (Daemons[idx].d_inputfilterlist != NULL)
+ {
+ milter_config(Daemons[idx].d_inputfilterlist,
+ Daemons[idx].d_inputfilters,
+ MAXFILTERS);
+ }
+ }
+}
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
+/*
** MAKECONNECTION -- make a connection to an SMTP socket on a machine.
**
** Parameters:
@@ -1606,6 +1911,8 @@ addr_family(addr)
** mci -- a pointer to the mail connection information
** structure to be filled in.
** e -- the current envelope.
+** enough -- time at which to stop further connection attempts.
+** (0 means no limit)
**
** Returns:
** An exit code telling whether the connection could be
@@ -1620,24 +1927,25 @@ static jmp_buf CtxConnectTimeout;
SOCKADDR CurHostAddr; /* address of current host */
int
-makeconnection(host, port, mci, e)
+makeconnection(host, port, mci, e, enough)
char *host;
- volatile u_int port;
+ volatile unsigned int port;
register MCI *mci;
ENVELOPE *e;
+ time_t enough;
{
register volatile int addrno = 0;
- register volatile int s;
- register struct hostent *volatile hp = (struct hostent *)NULL;
+ volatile int s;
+ register struct hostent *volatile hp = (struct hostent *) NULL;
SOCKADDR addr;
SOCKADDR clt_addr;
int save_errno = 0;
volatile SOCKADDR_LEN_T addrlen;
volatile bool firstconnect;
- EVENT *volatile ev = NULL;
-# if NETINET6
- volatile bool v6found = FALSE;
-# endif /* NETINET6 */
+ SM_EVENT *volatile ev = NULL;
+#if NETINET6
+ volatile bool v6found = false;
+#endif /* NETINET6 */
volatile int family = InetMode;
SOCKADDR_LEN_T len;
volatile SOCKADDR_LEN_T socksize = 0;
@@ -1646,9 +1954,9 @@ makeconnection(host, port, mci, e)
char *p;
extern ENVELOPE BlankEnvelope;
- /* retranslate ${daemon_flags} into bitmap */
+ /* retranslate {daemon_flags} into bitmap */
clrbitmap(d_flags);
- if ((p = macvalue(macid("{daemon_flags}", NULL), e)) != NULL)
+ if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL)
{
for (; *p != '\0'; p++)
{
@@ -1657,33 +1965,19 @@ makeconnection(host, port, mci, e)
}
}
- /* "add" ${client_flags} to bitmap */
- if ((p = macvalue(macid("{client_flags}", NULL), e)) != NULL)
- {
- for (; *p != '\0'; p++)
- {
- /* look for just this one flag */
- if (*p == D_IFNHELO)
- {
- setbitn(bitidx(*p), d_flags);
- break;
- }
- }
- }
-
-# if NETINET6
+#if NETINET6
v4retry:
-# endif /* NETINET6 */
- clt_bind = FALSE;
+#endif /* NETINET6 */
+ clt_bind = false;
/* Set up the address for outgoing connection. */
if (bitnset(D_BINDIF, d_flags) &&
- (p = macvalue(macid("{if_addr}", NULL), e)) != NULL &&
+ (p = macvalue(macid("{if_addr}"), e)) != NULL &&
*p != '\0')
{
-# if NETINET6
+#if NETINET6
char p6[INET6_ADDRSTRLEN];
-# endif /* NETINET6 */
+#endif /* NETINET6 */
memset(&clt_addr, '\0', sizeof clt_addr);
@@ -1691,79 +1985,80 @@ makeconnection(host, port, mci, e)
clt_addr.sa.sa_family = addr_family(p);
switch (clt_addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
clt_addr.sin.sin_addr.s_addr = inet_addr(p);
if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
{
- clt_bind = TRUE;
+ clt_bind = true;
socksize = sizeof (struct sockaddr_in);
}
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (inet_addr(p) != INADDR_NONE)
- snprintf(p6, sizeof p6, "::ffff:%s", p);
+ (void) sm_snprintf(p6, sizeof p6,
+ "IPv6:::ffff:%s", p);
else
- strlcpy(p6, p, sizeof p6);
- if (inet_pton(AF_INET6, p6,
- &clt_addr.sin6.sin6_addr) == 1 &&
+ (void) sm_strlcpy(p6, p, sizeof p6);
+ if (anynet_pton(AF_INET6, p6,
+ &clt_addr.sin6.sin6_addr) == 1 &&
!IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
{
- clt_bind = TRUE;
+ clt_bind = true;
socksize = sizeof (struct sockaddr_in6);
}
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
-# if 0
+#if 0
default:
syserr("554 5.3.5 Address= option unsupported for family %d",
clt_addr.sa.sa_family);
break;
-# endif /* 0 */
+#endif /* 0 */
}
if (clt_bind)
family = clt_addr.sa.sa_family;
}
- else
+
+ /* D_BINDIF not set or not available, fallback to ClientPortOptions */
+ if (!clt_bind)
{
- STRUCTCOPY(ClientAddr, clt_addr);
- if (clt_addr.sa.sa_family == AF_UNSPEC)
- clt_addr.sa.sa_family = family;
+ STRUCTCOPY(ClientSettings[family].d_addr, clt_addr);
switch (clt_addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (clt_addr.sin.sin_addr.s_addr == 0)
clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
else
- clt_bind = TRUE;
+ clt_bind = true;
if (clt_addr.sin.sin_port != 0)
- clt_bind = TRUE;
+ clt_bind = true;
socksize = sizeof (struct sockaddr_in);
break;
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
clt_addr.sin6.sin6_addr = in6addr_any;
else
- clt_bind = TRUE;
+ clt_bind = true;
socksize = sizeof (struct sockaddr_in6);
if (clt_addr.sin6.sin6_port != 0)
- clt_bind = TRUE;
+ clt_bind = true;
break;
-# endif /* NETINET6 */
-# if NETISO
+#endif /* NETINET6 */
+#if NETISO
case AF_ISO:
socksize = sizeof clt_addr.siso;
- clt_bind = TRUE;
+ clt_bind = true;
break;
-# endif /* NETISO */
+#endif /* NETISO */
default:
break;
}
@@ -1774,9 +2069,7 @@ makeconnection(host, port, mci, e)
** Accept "[a.b.c.d]" syntax for host name.
*/
-# if NAMED_BIND
SM_SET_H_ERRNO(0);
-# endif /* NAMED_BIND */
errno = 0;
memset(&CurHostAddr, '\0', sizeof CurHostAddr);
memset(&addr, '\0', sizeof addr);
@@ -1788,18 +2081,18 @@ makeconnection(host, port, mci, e)
p = strchr(host, ']');
if (p != NULL)
{
-# if NETINET
+#if NETINET
unsigned long hid = INADDR_NONE;
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
struct sockaddr_in6 hid6;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
*p = '\0';
-# if NETINET6
+#if NETINET6
memset(&hid6, '\0', sizeof hid6);
-# endif /* NETINET6 */
-# if NETINET
+#endif /* NETINET6 */
+#if NETINET
if (family == AF_INET &&
(hid = inet_addr(&host[1])) != INADDR_NONE)
{
@@ -1807,34 +2100,34 @@ makeconnection(host, port, mci, e)
addr.sin.sin_addr.s_addr = hid;
}
else
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
if (family == AF_INET6 &&
- inet_pton(AF_INET6, &host[1],
- &hid6.sin6_addr) == 1)
+ anynet_pton(AF_INET6, &host[1],
+ &hid6.sin6_addr) == 1)
{
addr.sin6.sin6_family = AF_INET6;
addr.sin6.sin6_addr = hid6.sin6_addr;
}
else
-# endif /* NETINET6 */
+#endif /* NETINET6 */
{
/* try it as a host name (avoid MX lookup) */
hp = sm_gethostbyname(&host[1], family);
if (hp == NULL && p[-1] == '.')
{
-# if NAMED_BIND
+#if NAMED_BIND
int oldopts = _res.options;
_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
p[-1] = '\0';
hp = sm_gethostbyname(&host[1],
family);
p[-1] = '.';
-# if NAMED_BIND
+#if NAMED_BIND
_res.options = oldopts;
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
}
*p = ']';
goto gothostent;
@@ -1861,34 +2154,54 @@ makeconnection(host, port, mci, e)
hp = sm_gethostbyname(host, family);
if (hp == NULL && *p == '.')
{
-# if NAMED_BIND
+#if NAMED_BIND
int oldopts = _res.options;
_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
*p = '\0';
hp = sm_gethostbyname(host, family);
*p = '.';
-# if NAMED_BIND
+#if NAMED_BIND
_res.options = oldopts;
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
}
}
gothostent:
if (hp == NULL)
{
-# if NAMED_BIND
+#if NAMED_BIND
/* check for name server timeouts */
- if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
- (errno == ECONNREFUSED && UseNameServer))
+# if NETINET6
+ if (WorkAroundBrokenAAAA && family == AF_INET6 &&
+ errno == ETIMEDOUT)
{
- save_errno = errno;
- mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
- errno = save_errno;
- return EX_TEMPFAIL;
+ /*
+ ** An attempt with family AF_INET may
+ ** succeed By skipping the next section
+ ** of code, we will try AF_INET before
+ ** failing.
+ */
+
+ if (tTd(16, 10))
+ sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n");
}
-# endif /* NAMED_BIND */
-# if NETINET6
+ else
+# endif /* NETINET6 */
+ {
+ if (errno == ETIMEDOUT ||
+ h_errno == TRY_AGAIN ||
+ (errno == ECONNREFUSED && UseNameServer))
+ {
+ save_errno = errno;
+ mci_setstat(mci, EX_TEMPFAIL,
+ "4.4.3", NULL);
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+ }
+#endif /* NAMED_BIND */
+#if NETINET6
/*
** Try v6 first, then fall back to v4.
** If we found a v6 address, but no v4
@@ -1902,7 +2215,7 @@ gothostent:
}
if (v6found)
goto v6tempfail;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
save_errno = errno;
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = save_errno;
@@ -1911,21 +2224,21 @@ gothostent:
addr.sa.sa_family = hp->h_addrtype;
switch (hp->h_addrtype)
{
-# if NETINET
+#if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr,
INADDRSZ);
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr,
IN6ADDRSZ);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
if (hp->h_length > sizeof addr.sa.sa_data)
@@ -1936,9 +2249,7 @@ gothostent:
errno = EINVAL;
return EX_NOHOST;
}
- memmove(addr.sa.sa_data,
- hp->h_addr,
- hp->h_length);
+ memmove(addr.sa.sa_data, hp->h_addr, hp->h_length);
break;
}
addrno = 1;
@@ -1950,9 +2261,9 @@ gothostent:
if (port == 0)
{
-# ifdef NO_GETSERVBYNAME
+#ifdef NO_GETSERVBYNAME
port = htons(25);
-# else /* NO_GETSERVBYNAME */
+#else /* NO_GETSERVBYNAME */
register struct servent *sp = getservbyname("smtp", "tcp");
if (sp == NULL)
@@ -1964,41 +2275,56 @@ gothostent:
}
else
port = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
+#endif /* NO_GETSERVBYNAME */
+ }
+
+#if NETINET6
+ if (addr.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) &&
+ ClientSettings[AF_INET].d_addr.sa.sa_family != 0)
+ {
+ /*
+ ** Ignore mapped IPv4 address since
+ ** there is a ClientPortOptions setting
+ ** for IPv4.
+ */
+
+ goto nextaddr;
}
+#endif /* NETINET6 */
switch (addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
addr.sin.sin_port = port;
addrlen = sizeof (struct sockaddr_in);
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
addr.sin6.sin6_port = port;
addrlen = sizeof (struct sockaddr_in6);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
-# if NETISO
+#if NETISO
case AF_ISO:
/* assume two byte transport selector */
memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
addrlen = sizeof (struct sockaddr_iso);
break;
-# endif /* NETISO */
+#endif /* NETISO */
default:
syserr("Can't connect to address family %d", addr.sa.sa_family);
mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
errno = EINVAL;
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
return EX_NOHOST;
}
@@ -2006,29 +2332,30 @@ gothostent:
** Try to actually open the connection.
*/
-# ifdef XLA
+#if XLA
/* if too many connections, don't bother trying */
if (!xla_noqueue_ok(host))
{
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return EX_TEMPFAIL;
}
-# endif /* XLA */
+#endif /* XLA */
- firstconnect = TRUE;
+ firstconnect = true;
for (;;)
{
if (tTd(16, 1))
- dprintf("makeconnection (%s [%s].%d (%d))\n",
- host, anynet_ntoa(&addr), ntohs(port),
- addr.sa.sa_family);
+ sm_dprintf("makeconnection (%s [%s].%d (%d))\n",
+ host, anynet_ntoa(&addr), ntohs(port),
+ (int) addr.sa.sa_family);
/* save for logging */
CurHostAddr = addr;
+#if HASRRESVPORT
if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
{
int rport = IPPORT_RESERVED - 1;
@@ -2036,47 +2363,47 @@ gothostent:
s = rresvport(&rport);
}
else
+#endif /* HASRRESVPORT */
{
- s = socket(clt_addr.sa.sa_family, SOCK_STREAM, 0);
+ s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
}
if (s < 0)
{
save_errno = errno;
syserr("makeconnection: cannot create socket");
-# ifdef XLA
+#if XLA
xla_host_end(host);
-# endif /* XLA */
+#endif /* XLA */
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
errno = save_errno;
return EX_TEMPFAIL;
}
-# ifdef SO_SNDBUF
- if (TcpSndBufferSize > 0)
+#ifdef SO_SNDBUF
+ if (ClientSettings[family].d_tcpsndbufsize > 0)
{
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
- (char *) &TcpSndBufferSize,
- sizeof(TcpSndBufferSize)) < 0)
+ (char *) &ClientSettings[family].d_tcpsndbufsize,
+ sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0)
syserr("makeconnection: setsockopt(SO_SNDBUF)");
}
-# endif /* SO_SNDBUF */
-# ifdef SO_RCVBUF
- if (TcpRcvBufferSize > 0)
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ if (ClientSettings[family].d_tcprcvbufsize > 0)
{
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
- (char *) &TcpRcvBufferSize,
- sizeof(TcpRcvBufferSize)) < 0)
+ (char *) &ClientSettings[family].d_tcprcvbufsize,
+ sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0)
syserr("makeconnection: setsockopt(SO_RCVBUF)");
}
-# endif /* SO_RCVBUF */
-
+#endif /* SO_RCVBUF */
if (tTd(16, 1))
- dprintf("makeconnection: fd=%d\n", s);
+ sm_dprintf("makeconnection: fd=%d\n", s);
/* turn on network debugging? */
if (tTd(16, 101))
@@ -2086,9 +2413,9 @@ gothostent:
(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
(char *)&on, sizeof on);
}
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
- errno = 0; /* for debugging */
+ if (e->e_xfp != NULL) /* for debugging */
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
+ errno = 0; /* for debugging */
if (clt_bind)
{
@@ -2096,7 +2423,7 @@ gothostent:
switch (clt_addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (clt_addr.sin.sin_port != 0)
(void) setsockopt(s, SOL_SOCKET,
@@ -2104,9 +2431,9 @@ gothostent:
(char *) &on,
sizeof on);
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (clt_addr.sin6.sin6_port != 0)
(void) setsockopt(s, SOL_SOCKET,
@@ -2114,7 +2441,7 @@ gothostent:
(char *) &on,
sizeof on);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
}
if (bind(s, &clt_addr.sa, socksize) < 0)
@@ -2124,10 +2451,10 @@ gothostent:
errno = save_errno;
syserr("makeconnection: cannot bind socket [%s]",
anynet_ntoa(&clt_addr));
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
errno = save_errno;
return EX_TEMPFAIL;
}
@@ -2143,34 +2470,34 @@ gothostent:
int i;
if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
- ev = setevent(TimeOuts.to_iconnect,
- connecttimeout, 0);
+ ev = sm_setevent(TimeOuts.to_iconnect,
+ connecttimeout, 0);
else if (TimeOuts.to_connect != 0)
- ev = setevent(TimeOuts.to_connect,
- connecttimeout, 0);
+ ev = sm_setevent(TimeOuts.to_connect,
+ connecttimeout, 0);
else
ev = NULL;
switch (ConnectOnlyTo.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
&ConnectOnlyTo.sin6.sin6_addr,
IN6ADDRSZ);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
}
i = connect(s, (struct sockaddr *) &addr, addrlen);
save_errno = errno;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
if (i >= 0)
break;
}
@@ -2178,12 +2505,13 @@ gothostent:
save_errno = errno;
/* if running demand-dialed connection, try again */
- if (DialDelay > 0 && firstconnect)
+ if (DialDelay > 0 && firstconnect &&
+ bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
{
if (tTd(16, 1))
- dprintf("Connect failed (%s); trying again...\n",
- errstring(save_errno));
- firstconnect = FALSE;
+ sm_dprintf("Connect failed (%s); trying again...\n",
+ sm_errstring(save_errno));
+ firstconnect = false;
(void) sleep(DialDelay);
continue;
}
@@ -2191,34 +2519,38 @@ gothostent:
/* couldn't connect.... figure out why */
(void) close(s);
- if (LogLevel >= 14)
+ if (LogLevel > 13)
sm_syslog(LOG_INFO, e->e_id,
"makeconnection (%s [%s]) failed: %s",
host, anynet_ntoa(&addr),
- errstring(save_errno));
+ sm_errstring(save_errno));
- if (hp != NULL && hp->h_addr_list[addrno] != NULL)
+#if NETINET6
+nextaddr:
+#endif /* NETINET6 */
+ if (hp != NULL && hp->h_addr_list[addrno] != NULL &&
+ (enough == 0 || curtime() < enough))
{
if (tTd(16, 1))
- dprintf("Connect failed (%s); trying new address....\n",
- errstring(save_errno));
+ sm_dprintf("Connect failed (%s); trying new address....\n",
+ sm_errstring(save_errno));
switch (addr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
hp->h_addr_list[addrno++],
INADDRSZ);
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
hp->h_addr_list[addrno++],
IN6ADDRSZ);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
memmove(addr.sa.sa_data,
@@ -2230,84 +2562,108 @@ gothostent:
}
errno = save_errno;
-# if NETINET6
+#if NETINET6
if (family == AF_INET6)
{
if (tTd(16, 1))
- dprintf("Connect failed (%s); retrying with AF_INET....\n",
- errstring(save_errno));
- v6found = TRUE;
+ sm_dprintf("Connect failed (%s); retrying with AF_INET....\n",
+ sm_errstring(save_errno));
+ v6found = true;
family = AF_INET;
-# if _FFR_FREEHOSTENT
if (hp != NULL)
{
freehostent(hp);
hp = NULL;
}
-# endif /* _FFR_FREEHOSTENT */
goto v4retry;
}
v6tempfail:
-# endif /* NETINET6 */
+#endif /* NETINET6 */
/* couldn't open connection */
-# if NETINET6
+#if NETINET6
/* Don't clobber an already saved errno from v4retry */
if (errno > 0)
-# endif /* NETINET6 */
+#endif /* NETINET6 */
save_errno = errno;
if (tTd(16, 1))
- dprintf("Connect failed (%s)\n", errstring(save_errno));
-# ifdef XLA
+ sm_dprintf("Connect failed (%s)\n",
+ sm_errstring(save_errno));
+#if XLA
xla_host_end(host);
-# endif /* XLA */
+#endif /* XLA */
mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
errno = save_errno;
return EX_TEMPFAIL;
}
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
{
freehostent(hp);
hp = NULL;
}
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
/* connection ok, put it into canonical form */
mci->mci_out = NULL;
- if ((mci->mci_out = fdopen(s, "w")) == NULL ||
+ if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &s,
+ SM_IO_WRONLY, NULL)) == NULL ||
(s = dup(s)) < 0 ||
- (mci->mci_in = fdopen(s, "r")) == NULL)
+ (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &s,
+ SM_IO_RDONLY, NULL)) == NULL)
{
save_errno = errno;
syserr("cannot open SMTP client channel, fd=%d", s);
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
if (mci->mci_out != NULL)
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
(void) close(s);
errno = save_errno;
return EX_TEMPFAIL;
}
+ sm_io_automode(mci->mci_out, mci->mci_in);
+
+ /* set {client_flags} */
+ if (ClientSettings[addr.sa.sa_family].d_mflags != NULL)
+ {
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{client_flags}"),
+ ClientSettings[addr.sa.sa_family].d_mflags);
+ }
+ else
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{client_flags}"), "");
+
+ /* "add" {client_flags} to bitmap */
+ if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags))
+ {
+ /* look for just this one flag */
+ setbitn(D_IFNHELO, d_flags);
+ }
/* find out name for Interface through which we connect */
len = sizeof addr;
if (getsockname(s, &addr.sa, &len) == 0)
{
char *name;
- char *p;
+ char family[5];
- define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)),
- &BlankEnvelope);
- p = xalloc(5);
- snprintf(p, 4, "%d", addr.sa.sa_family);
- define(macid("{if_family}", NULL), p, &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_addr_out}"), anynet_ntoa(&addr));
+ (void) sm_snprintf(family, sizeof(family), "%d",
+ addr.sa.sa_family);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_family_out}"), family);
name = hostnamebyanyaddr(&addr);
- define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{if_name_out}"), name);
if (LogLevel > 11)
{
/* log connection information */
@@ -2322,9 +2678,12 @@ gothostent:
}
else
{
- define(macid("{if_name}", NULL), NULL, &BlankEnvelope);
- define(macid("{if_addr}", NULL), NULL, &BlankEnvelope);
- define(macid("{if_family}", NULL), NULL, &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_name_out}"), NULL);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_addr_out}"), NULL);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{if_family_out}"), NULL);
}
mci_setstat(mci, EX_OK, NULL, NULL);
return EX_OK;
@@ -2342,7 +2701,7 @@ connecttimeout()
errno = ETIMEDOUT;
longjmp(CtxConnectTimeout, 1);
}
- /*
+/*
** MAKECONNECTION_DS -- make a connection to a domain socket.
**
** Parameters:
@@ -2358,8 +2717,9 @@ connecttimeout()
** none.
*/
-# if NETUNIX
-int makeconnection_ds(mux_path, mci)
+#if NETUNIX
+int
+makeconnection_ds(mux_path, mci)
char *mux_path;
register MCI *mci;
{
@@ -2387,12 +2747,14 @@ int makeconnection_ds(mux_path, mci)
if (strlen(mux_path) >= sizeof unix_addr.sun_path)
{
syserr("makeconnection_ds: domain socket name too long");
- /* XXX why TEMPFAIL ? */
+
+ /* XXX why TEMPFAIL but 5.x.y ? */
mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
errno = ENAMETOOLONG;
return EX_UNAVAILABLE;
}
- (void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path);
+ (void) sm_strlcpy(unix_addr.sun_path, mux_path,
+ sizeof unix_addr.sun_path);
/* initialize domain socket */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -2419,56 +2781,103 @@ int makeconnection_ds(mux_path, mci)
/* connection ok, put it into canonical form */
mci->mci_out = NULL;
- if ((mci->mci_out = fdopen(sock, "w")) == NULL ||
- (sock = dup(sock)) < 0 ||
- (mci->mci_in = fdopen(sock, "r")) == NULL)
+ if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &sock, SM_IO_WRONLY, NULL))
+ == NULL
+ || (sock = dup(sock)) < 0 ||
+ (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &sock, SM_IO_RDONLY, NULL))
+ == NULL)
{
save_errno = errno;
syserr("cannot open SMTP client channel, fd=%d", sock);
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
if (mci->mci_out != NULL)
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
(void) close(sock);
errno = save_errno;
return EX_TEMPFAIL;
}
+ sm_io_automode(mci->mci_out, mci->mci_in);
mci_setstat(mci, EX_OK, NULL, NULL);
errno = 0;
return EX_OK;
}
-# endif /* NETUNIX */
- /*
-** SIGHUP -- handle a SIGHUP signal
+#endif /* NETUNIX */
+/*
+** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
**
** Parameters:
-** sig -- incoming signal.
+** none.
**
** Returns:
** none.
**
** Side Effects:
-** Sets RestartRequest which should cause the daemon
-** to restart.
-**
-** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
-** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
-** DOING.
+** closes control socket, exits.
*/
-/* ARGSUSED */
-static SIGFUNC_DECL
-sighup(sig)
- int sig;
+void
+shutdown_daemon()
{
- int save_errno = errno;
+ int i;
+ char *reason;
- FIX_SYSV_SIGNAL(sig, sighup);
- RestartRequest = "signal";
- errno = save_errno;
- return SIGFUNC_RETURN;
+ sm_allsignals(true);
+
+ reason = ShutdownRequest;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+
+ if (LogLevel > 79)
+ sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)",
+ reason == NULL ? "implicit call" : reason);
+
+ FileName = NULL;
+ closecontrolsocket(true);
+#if XLA
+ xla_all_end();
+#endif /* XLA */
+
+ for (i = 0; i < NDaemons; i++)
+ {
+ if (Daemons[i].d_socket >= 0)
+ {
+ (void) close(Daemons[i].d_socket);
+ Daemons[i].d_socket = -1;
+
+#if _FFR_DAEMON_NETUNIX
+# if NETUNIX
+ /* Remove named sockets */
+ if (Daemons[i].d_addr.sa.sa_family == AF_UNIX)
+ {
+ int rval;
+ long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT;
+
+ /* if not safe, don't use it */
+ rval = safefile(Daemons[i].d_addr.sunix.sun_path,
+ RunAsUid, RunAsGid,
+ RunAsUserName, sff,
+ S_IRUSR|S_IWUSR, NULL);
+ if (rval == 0 &&
+ unlink(Daemons[i].d_addr.sunix.sun_path) < 0)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "Could not remove daemon %s socket: %s: %s",
+ Daemons[i].d_name,
+ Daemons[i].d_addr.sunix.sun_path,
+ sm_errstring(errno));
+ }
+ }
+# endif /* NETUNIX */
+#endif /* _FFR_DAEMON_NETUNIX */
+ }
+ }
+
+ finis(false, true, EX_OK);
}
- /*
+/*
** RESTART_DAEMON -- Performs a clean restart of the daemon
**
** Parameters:
@@ -2485,14 +2894,15 @@ sighup(sig)
#define SM_NOOP_SIGNAL(sig, old) \
do \
{ \
- (old) = setsignal((sig), sm_signal_noop); \
+ (old) = sm_signal((sig), sm_signal_noop); \
if ((old) == SIG_IGN || (old) == SIG_DFL) \
- (void) setsignal((sig), (old)); \
+ (void) sm_signal((sig), (old)); \
} while (0)
-static void
+void
restart_daemon()
{
+ bool drop;
int i;
int save_errno;
char *reason;
@@ -2500,8 +2910,8 @@ restart_daemon()
extern int DtableSize;
/* clear the events to turn off SIGALRMs */
- clear_events();
- allsignals(TRUE);
+ sm_clear_events();
+ sm_allsignals(true);
reason = RestartRequest;
RestartRequest = NULL;
@@ -2512,21 +2922,34 @@ restart_daemon()
if (LogLevel > 3)
sm_syslog(LOG_INFO, NOQID,
"could not restart: need full path");
- finis(FALSE, EX_OSFILE);
+ finis(false, true, EX_OSFILE);
+ /* NOTREACHED */
}
if (LogLevel > 3)
sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
SaveArgv[0],
reason == NULL ? "implicit call" : reason);
- closecontrolsocket(TRUE);
- if (drop_privileges(TRUE) != EX_OK)
+ closecontrolsocket(true);
+
+ /*
+ ** Want to drop to the user who started the process in all cases
+ ** *but* when running as "smmsp" for the clientmqueue queue run
+ ** daemon. In that case, UseMSP will be true, RunAsUid should not
+ ** be root, and RealUid should be either 0 or RunAsUid.
+ */
+
+ drop = !(UseMSP && RunAsUid != 0 &&
+ (RealUid == 0 || RealUid == RunAsUid));
+
+ if (drop_privileges(drop) != EX_OK)
{
if (LogLevel > 0)
sm_syslog(LOG_ALERT, NOQID,
- "could not set[ug]id(%d, %d): %m",
- RunAsUid, RunAsGid);
- finis(FALSE, EX_OSERR);
+ "could not drop privileges: %s",
+ sm_errstring(errno));
+ finis(false, true, EX_OSERR);
+ /* NOTREACHED */
}
/* arrange for all the files to be closed */
@@ -2537,6 +2960,9 @@ restart_daemon()
if ((j = fcntl(i, F_GETFD, 0)) != -1)
(void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
}
+#if SM_CONF_SHM
+ cleanup_shm(DaemonPid == getpid());
+#endif /* SM_CONF_SHM */
/*
** Need to allow signals before execve() to make them "harmless".
@@ -2554,29 +2980,30 @@ restart_daemon()
#ifdef SIGUSR1
SM_NOOP_SIGNAL(SIGUSR1, ousr1);
#endif /* SIGUSR1 */
- allsignals(FALSE);
+ sm_allsignals(false);
(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
save_errno = errno;
/* block signals again and restore needed signals */
- allsignals(TRUE);
+ sm_allsignals(true);
/* For finis() events */
- (void) setsignal(SIGALRM, oalrm);
+ (void) sm_signal(SIGALRM, oalrm);
#ifdef SIGUSR1
/* For debugging finis() */
- (void) setsignal(SIGUSR1, ousr1);
+ (void) sm_signal(SIGUSR1, ousr1);
#endif /* SIGUSR1 */
errno = save_errno;
if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m",
- SaveArgv[0]);
- finis(FALSE, EX_OSFILE);
+ sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s",
+ SaveArgv[0], sm_errstring(errno));
+ finis(false, true, EX_OSFILE);
+ /* NOTREACHED */
}
- /*
+/*
** MYHOSTNAME -- return the name of this host.
**
** Parameters:
@@ -2598,9 +3025,9 @@ myhostname(hostbuf, size)
register struct hostent *hp;
if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
- (void) strlcpy(hostbuf, "localhost", size);
+ (void) sm_strlcpy(hostbuf, "localhost", size);
hp = sm_gethostbyname(hostbuf, InetMode);
-# if NETINET && NETINET6
+#if NETINET && NETINET6
if (hp == NULL && InetMode == AF_INET6)
{
/*
@@ -2611,14 +3038,13 @@ myhostname(hostbuf, size)
hp = sm_gethostbyname(hostbuf, AF_INET);
}
-# endif /* NETINET && NETINET6 */
-
+#endif /* NETINET && NETINET6 */
if (hp == NULL)
return NULL;
if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
(void) cleanstrcpy(hostbuf, hp->h_name, size);
-# if NETINFO
+#if NETINFO
if (strchr(hostbuf, '.') == NULL)
{
char *domainname;
@@ -2627,12 +3053,9 @@ myhostname(hostbuf, size)
"domain", '\0');
if (domainname != NULL &&
strlen(domainname) + strlen(hostbuf) + 1 < size)
- {
- (void) strlcat(hostbuf, ".", size);
- (void) strlcat(hostbuf, domainname, size);
- }
+ (void) sm_strlcat2(hostbuf, ".", domainname, size);
}
-# endif /* NETINFO */
+#endif /* NETINFO */
/*
** If there is still no dot in the name, try looking for a
@@ -2664,7 +3087,7 @@ myhostname(hostbuf, size)
*/
if (strchr(hostbuf, '.') == NULL &&
- !getcanonname(hostbuf, size, TRUE))
+ !getcanonname(hostbuf, size, true, NULL))
{
sm_syslog(LOG_CRIT, NOQID,
"My unqualified host name (%s) unknown; sleeping for retry",
@@ -2672,7 +3095,7 @@ myhostname(hostbuf, size)
message("My unqualified host name (%s) unknown; sleeping for retry",
hostbuf);
(void) sleep(60);
- if (!getcanonname(hostbuf, size, TRUE))
+ if (!getcanonname(hostbuf, size, true, NULL))
{
sm_syslog(LOG_ALERT, NOQID,
"unable to qualify my own domain name (%s) -- using short name",
@@ -2683,7 +3106,7 @@ myhostname(hostbuf, size)
}
return hp;
}
- /*
+/*
** ADDRCMP -- compare two host addresses
**
** Parameters:
@@ -2702,22 +3125,22 @@ addrcmp(hp, ha, sa)
char *ha;
SOCKADDR *sa;
{
-# if NETINET6
- u_char *a;
-# endif /* NETINET6 */
+#if NETINET6
+ unsigned char *a;
+#endif /* NETINET6 */
switch (sa->sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (hp->h_addrtype == AF_INET)
return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
- a = (u_char *) &sa->sin6.sin6_addr;
+ a = (unsigned char *) &sa->sin6.sin6_addr;
/* Straight binary comparison */
if (hp->h_addrtype == AF_INET6)
@@ -2728,20 +3151,20 @@ addrcmp(hp, ha, sa)
IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
}
return -1;
}
- /*
+/*
** GETAUTHINFO -- get the real host name associated with a file descriptor
**
** Uses RFC1413 protocol to try to get info from the other end.
**
** Parameters:
** fd -- the descriptor
-** may_be_forged -- an outage that is set to TRUE if the
+** may_be_forged -- an outage that is set to true if the
** forward lookup of RealHostName does not match
-** RealHostAddr; set to FALSE if they do match.
+** RealHostAddr; set to false if they do match.
**
** Returns:
** The user@host information associated with this descriptor.
@@ -2767,15 +3190,24 @@ getauthinfo(fd, may_be_forged)
int fd;
bool *may_be_forged;
{
- volatile u_short port = 0;
+ unsigned short SM_NONVOLATILE port = 0;
SOCKADDR_LEN_T falen;
register char *volatile p = NULL;
SOCKADDR la;
SOCKADDR_LEN_T lalen;
+#ifndef NO_GETSERVBYNAME
register struct servent *sp;
+# if NETINET
+ static unsigned short port4 = 0;
+# endif /* NETINET */
+# if NETINET6
+ static unsigned short port6 = 0;
+# endif /* NETINET6 */
+#endif /* ! NO_GETSERVBYNAME */
volatile int s;
int i = 0;
- EVENT *ev;
+ size_t len;
+ SM_EVENT *ev;
int nleft;
struct hostent *hp;
char *ostype = NULL;
@@ -2783,7 +3215,7 @@ getauthinfo(fd, may_be_forged)
char ibuf[MAXNAME + 1];
static char hbuf[MAXNAME * 2 + 11];
- *may_be_forged = FALSE;
+ *may_be_forged = false;
falen = sizeof RealHostAddr;
if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
falen <= 0 || RealHostAddr.sa.sa_family == 0)
@@ -2795,14 +3227,15 @@ getauthinfo(fd, may_be_forged)
** errno in this case, so a mis-report doesn't
** happen later.
*/
+
if (errno != ENOTSOCK)
return NULL;
errno = 0;
}
- (void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
- RealUserName);
+ (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName,
+ "@localhost");
if (tTd(9, 1))
- dprintf("getauthinfo: %s\n", hbuf);
+ sm_dprintf("getauthinfo: %s\n", hbuf);
return hbuf;
}
@@ -2811,25 +3244,17 @@ getauthinfo(fd, may_be_forged)
/* translate that to a host name */
RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
if (strlen(RealHostName) > MAXNAME)
- RealHostName[MAXNAME] = '\0';
+ RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
}
/* cross check RealHostName with forward DNS lookup */
- if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
- RealHostName[0] == '[')
- {
- /*
- ** address is not a socket or have an
- ** IP address with no forward lookup
- */
- *may_be_forged = FALSE;
- }
- else
+ if (anynet_ntoa(&RealHostAddr)[0] != '[' &&
+ RealHostName[0] != '[')
{
int family;
family = RealHostAddr.sa.sa_family;
-# if NETINET6 && NEEDSGETIPNODE
+#if NETINET6 && NEEDSGETIPNODE
/*
** If RealHostAddr is an IPv6 connection with an
** IPv4-mapped address, we need RealHostName's IPv4
@@ -2846,22 +3271,24 @@ getauthinfo(fd, may_be_forged)
if (family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
family = AF_INET;
-# endif /* NETINET6 && NEEDSGETIPNODE */
+#endif /* NETINET6 && NEEDSGETIPNODE */
/* try to match the reverse against the forward lookup */
hp = sm_gethostbyname(RealHostName, family);
if (hp == NULL)
- *may_be_forged = TRUE;
+ *may_be_forged = true;
else
{
for (ha = hp->h_addr_list; *ha != NULL; ha++)
+ {
if (addrcmp(hp, *ha, &RealHostAddr) == 0)
break;
+ }
*may_be_forged = *ha == NULL;
-# if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
freehostent(hp);
hp = NULL;
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
}
}
@@ -2871,7 +3298,7 @@ getauthinfo(fd, may_be_forged)
lalen = sizeof la;
switch (RealHostAddr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (getsockname(fd, &la.sa, &lalen) < 0 ||
lalen <= 0 ||
@@ -2883,7 +3310,7 @@ getauthinfo(fd, may_be_forged)
port = RealHostAddr.sin.sin_port;
/* create ident query */
- (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
+ (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
ntohs(RealHostAddr.sin.sin_port),
ntohs(la.sin.sin_port));
@@ -2891,19 +3318,35 @@ getauthinfo(fd, may_be_forged)
la.sin.sin_port = 0;
/* create foreign address */
-# ifdef NO_GETSERVBYNAME
+# ifdef NO_GETSERVBYNAME
RealHostAddr.sin.sin_port = htons(113);
-# else /* NO_GETSERVBYNAME */
- sp = getservbyname("auth", "tcp");
- if (sp != NULL)
- RealHostAddr.sin.sin_port = sp->s_port;
- else
- RealHostAddr.sin.sin_port = htons(113);
+# else /* NO_GETSERVBYNAME */
+
+ /*
+ ** getservbyname() consumes about 5% of the time
+ ** when receiving a small message (almost all of the time
+ ** spent in this routine).
+ ** Hence we store the port in a static variable
+ ** to save this time.
+ ** The portnumber shouldn't change very often...
+ ** This code makes the assumption that the port number
+ ** is not 0.
+ */
+
+ if (port4 == 0)
+ {
+ sp = getservbyname("auth", "tcp");
+ if (sp != NULL)
+ port4 = sp->s_port;
+ else
+ port4 = htons(113);
+ }
+ RealHostAddr.sin.sin_port = port4;
break;
-# endif /* NO_GETSERVBYNAME */
-# endif /* NETINET */
+# endif /* NO_GETSERVBYNAME */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (getsockname(fd, &la.sa, &lalen) < 0 ||
lalen <= 0 ||
@@ -2915,7 +3358,7 @@ getauthinfo(fd, may_be_forged)
port = RealHostAddr.sin6.sin6_port;
/* create ident query */
- (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
+ (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
ntohs(RealHostAddr.sin6.sin6_port),
ntohs(la.sin6.sin6_port));
@@ -2923,17 +3366,21 @@ getauthinfo(fd, may_be_forged)
la.sin6.sin6_port = 0;
/* create foreign address */
-# ifdef NO_GETSERVBYNAME
+# ifdef NO_GETSERVBYNAME
RealHostAddr.sin6.sin6_port = htons(113);
-# else /* NO_GETSERVBYNAME */
- sp = getservbyname("auth", "tcp");
- if (sp != NULL)
- RealHostAddr.sin6.sin6_port = sp->s_port;
- else
- RealHostAddr.sin6.sin6_port = htons(113);
+# else /* NO_GETSERVBYNAME */
+ if (port6 == 0)
+ {
+ sp = getservbyname("auth", "tcp");
+ if (sp != NULL)
+ port6 = sp->s_port;
+ else
+ port6 = htons(113);
+ }
+ RealHostAddr.sin6.sin6_port = port6;
break;
-# endif /* NO_GETSERVBYNAME */
-# endif /* NETINET6 */
+# endif /* NO_GETSERVBYNAME */
+#endif /* NETINET6 */
default:
/* no ident info */
goto noident;
@@ -2948,24 +3395,22 @@ getauthinfo(fd, may_be_forged)
}
/* put a timeout around the whole thing */
- ev = setevent(TimeOuts.to_ident, authtimeout, 0);
+ ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0);
/* connect to foreign IDENT server using same address as SMTP socket */
s = socket(la.sa.sa_family, SOCK_STREAM, 0);
if (s < 0)
{
- clrevent(ev);
+ sm_clrevent(ev);
goto noident;
}
if (bind(s, &la.sa, lalen) < 0 ||
connect(s, &RealHostAddr.sa, lalen) < 0)
- {
goto closeident;
- }
if (tTd(9, 10))
- dprintf("getauthinfo: sent %s", ibuf);
+ sm_dprintf("getauthinfo: sent %s", ibuf);
/* send query */
if (write(s, ibuf, strlen(ibuf)) < 0)
@@ -2979,11 +3424,11 @@ getauthinfo(fd, may_be_forged)
p += i;
nleft -= i;
*p = '\0';
- if (strchr(ibuf, '\n') != NULL)
+ if (strchr(ibuf, '\n') != NULL || nleft <= 0)
break;
}
(void) close(s);
- clrevent(ev);
+ sm_clrevent(ev);
if (i < 0 || p == &ibuf[0])
goto noident;
@@ -2992,7 +3437,7 @@ getauthinfo(fd, may_be_forged)
*++p = '\0';
if (tTd(9, 3))
- dprintf("getauthinfo: got %s\n", ibuf);
+ sm_dprintf("getauthinfo: got %s\n", ibuf);
/* parse result */
p = strchr(ibuf, ':');
@@ -3003,7 +3448,7 @@ getauthinfo(fd, may_be_forged)
}
while (isascii(*++p) && isspace(*p))
continue;
- if (strncasecmp(p, "userid", 6) != 0)
+ if (sm_strncasecmp(p, "userid", 6) != 0)
{
/* presumably an error string */
goto noident;
@@ -3042,55 +3487,55 @@ getauthinfo(fd, may_be_forged)
continue;
/* p now points to the authenticated name -- copy carefully */
- if (strncasecmp(ostype, "other", 5) == 0 &&
+ if (sm_strncasecmp(ostype, "other", 5) == 0 &&
(ostype[5] == ' ' || ostype[5] == '\0'))
{
- snprintf(hbuf, sizeof hbuf, "IDENT:");
+ (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf);
cleanstrcpy(&hbuf[6], p, MAXNAME);
}
else
cleanstrcpy(hbuf, p, MAXNAME);
- i = strlen(hbuf);
- snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
- RealHostName == NULL ? "localhost" : RealHostName);
+ len = strlen(hbuf);
+ (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@",
+ RealHostName == NULL ? "localhost" : RealHostName);
goto postident;
closeident:
(void) close(s);
- clrevent(ev);
+ sm_clrevent(ev);
noident:
/* put back the original incoming port */
switch (RealHostAddr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (port > 0)
RealHostAddr.sin.sin_port = port;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (port > 0)
RealHostAddr.sin6.sin6_port = port;
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
}
if (RealHostName == NULL)
{
if (tTd(9, 1))
- dprintf("getauthinfo: NULL\n");
+ sm_dprintf("getauthinfo: NULL\n");
return NULL;
}
- snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
+ (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf);
postident:
-# if IP_SRCROUTE
-# ifndef GET_IPOPT_DST
-# define GET_IPOPT_DST(dst) (dst)
-# endif /* ! GET_IPOPT_DST */
+#if IP_SRCROUTE
+# ifndef GET_IPOPT_DST
+# define GET_IPOPT_DST(dst) (dst)
+# endif /* ! GET_IPOPT_DST */
/*
** Extract IP source routing information.
**
@@ -3108,8 +3553,8 @@ postident:
{
SOCKOPT_LEN_T ipoptlen;
int j;
- u_char *q;
- u_char *o;
+ unsigned char *q;
+ unsigned char *o;
int l;
struct IPOPTION ipopt;
@@ -3119,8 +3564,8 @@ postident:
goto noipsr;
if (ipoptlen == 0)
goto noipsr;
- o = (u_char *) ipopt.IP_LIST;
- while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
+ o = (unsigned char *) ipopt.IP_LIST;
+ while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen)
{
switch (*o)
{
@@ -3147,10 +3592,11 @@ postident:
p = &hbuf[strlen(hbuf)];
l = sizeof hbuf - (hbuf - p) - 6;
- snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
- *o == IPOPT_SSRR ? "!" : "",
- l > 240 ? 120 : l / 2,
- inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
+ (void) sm_snprintf(p, SPACELEFT(hbuf, p),
+ " [%s@%.*s",
+ *o == IPOPT_SSRR ? "!" : "",
+ l > 240 ? 120 : l / 2,
+ inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
i = strlen(p);
p += i;
l -= strlen(p);
@@ -3164,12 +3610,13 @@ postident:
struct in_addr addr;
memcpy(&addr, q, sizeof(addr));
- snprintf(p, SPACELEFT(hbuf, p),
- "%c%.*s",
- j != 0 ? '@' : ':',
- l > 240 ? 120 :
- j == 0 ? l : l / 2,
- inet_ntoa(addr));
+ (void) sm_snprintf(p,
+ SPACELEFT(hbuf, p),
+ "%c%.*s",
+ j != 0 ? '@' : ':',
+ l > 240 ? 120 :
+ j == 0 ? l : l / 2,
+ inet_ntoa(addr));
i = strlen(p);
p += i;
l -= i + 1;
@@ -3184,51 +3631,53 @@ postident:
break;
}
}
- snprintf(p, SPACELEFT(hbuf, p), "]");
+ (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]");
goto postipsr;
}
noipsr:
-# endif /* IP_SRCROUTE */
+#endif /* IP_SRCROUTE */
if (RealHostName != NULL && RealHostName[0] != '[')
{
p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
- anynet_ntoa(&RealHostAddr));
+ (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
+ anynet_ntoa(&RealHostAddr));
}
if (*may_be_forged)
{
p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
+ (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p));
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{client_resolve}"), "FORGED");
}
-# if IP_SRCROUTE
+#if IP_SRCROUTE
postipsr:
-# endif /* IP_SRCROUTE */
- if (tTd(9, 1))
- dprintf("getauthinfo: %s\n", hbuf);
+#endif /* IP_SRCROUTE */
/* put back the original incoming port */
switch (RealHostAddr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
if (port > 0)
RealHostAddr.sin.sin_port = port;
break;
-# endif /* NETINET */
+#endif /* NETINET */
-# if NETINET6
+#if NETINET6
case AF_INET6:
if (port > 0)
RealHostAddr.sin6.sin6_port = port;
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
}
+ if (tTd(9, 1))
+ sm_dprintf("getauthinfo: %s\n", hbuf);
return hbuf;
}
- /*
+/*
** HOST_MAP_LOOKUP -- turn a hostname into canonical form
**
** Parameters:
@@ -3258,34 +3707,39 @@ host_map_lookup(map, name, av, statp)
int *statp;
{
register struct hostent *hp;
-# if NETINET
+#if NETINET
struct in_addr in_addr;
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
struct in6_addr in6_addr;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
char *cp, *ans = NULL;
register STAB *s;
+ time_t now;
+#if NAMED_BIND
+ time_t SM_NONVOLATILE retrans = 0;
+ int SM_NONVOLATILE retry = 0;
+#endif /* NAMED_BIND */
char hbuf[MAXNAME + 1];
/*
** See if we have already looked up this name. If so, just
- ** return it.
+ ** return it (unless expired).
*/
+ now = curtime();
s = stab(name, ST_NAMECANON, ST_ENTER);
- if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
+ if (bitset(NCF_VALID, s->s_namecanon.nc_flags) &&
+ s->s_namecanon.nc_exp >= now)
{
if (tTd(9, 1))
- dprintf("host_map_lookup(%s) => CACHE %s\n",
- name,
- s->s_namecanon.nc_cname == NULL
+ sm_dprintf("host_map_lookup(%s) => CACHE %s\n",
+ name,
+ s->s_namecanon.nc_cname == NULL
? "NULL"
: s->s_namecanon.nc_cname);
errno = s->s_namecanon.nc_errno;
-# if NAMED_BIND
SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
-# endif /* NAMED_BIND */
*statp = s->s_namecanon.nc_stat;
if (*statp == EX_TEMPFAIL)
{
@@ -3323,7 +3777,7 @@ host_map_lookup(map, name, av, statp)
bitset(MF_DEFER, map->map_mflags))
{
if (tTd(9, 1))
- dprintf("host_map_lookup(%s) => DEFERRED\n", name);
+ sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name);
*statp = EX_TEMPFAIL;
return NULL;
}
@@ -3336,47 +3790,83 @@ host_map_lookup(map, name, av, statp)
*/
if (tTd(9, 1))
- dprintf("host_map_lookup(%s) => ", name);
+ sm_dprintf("host_map_lookup(%s) => ", name);
+#if NAMED_BIND
+ if (map->map_timeout > 0)
+ {
+ retrans = _res.retrans;
+ _res.retrans = map->map_timeout;
+ }
+ if (map->map_retry > 0)
+ {
+ retry = _res.retry;
+ _res.retry = map->map_retry;
+ }
+#endif /* NAMED_BIND */
+
+ /* set default TTL */
+ s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
if (*name != '[')
{
- snprintf(hbuf, sizeof hbuf, "%s", name);
- if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
+ int ttl;
+
+ (void) sm_strlcpy(hbuf, name, sizeof hbuf);
+ if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl))
+ {
ans = hbuf;
+ if (ttl > 0)
+ s->s_namecanon.nc_exp = now + SM_MIN(ttl,
+ SM_DEFAULT_TTL);
+ }
}
else
{
if ((cp = strchr(name, ']')) == NULL)
{
if (tTd(9, 1))
- dprintf("FAILED\n");
+ sm_dprintf("FAILED\n");
return NULL;
}
*cp = '\0';
hp = NULL;
-# if NETINET
+#if NETINET
if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
hp = sm_gethostbyaddr((char *)&in_addr,
INADDRSZ, AF_INET);
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
if (hp == NULL &&
- inet_pton(AF_INET6, &name[1], &in6_addr) == 1)
+ anynet_pton(AF_INET6, &name[1], &in6_addr) == 1)
hp = sm_gethostbyaddr((char *)&in6_addr,
IN6ADDRSZ, AF_INET6);
-# endif /* NETINET6 */
+#endif /* NETINET6 */
*cp = ']';
if (hp != NULL)
{
/* found a match -- copy out */
- ans = denlstring((char *) hp->h_name, TRUE, TRUE);
-# if _FFR_FREEHOSTENT && NETINET6
+ ans = denlstring((char *) hp->h_name, true, true);
+#if NETINET6
+ if (ans == hp->h_name)
+ {
+ static char n[MAXNAME + 1];
+
+ /* hp->h_name is about to disappear */
+ (void) sm_strlcpy(n, ans, sizeof n);
+ ans = n;
+ }
freehostent(hp);
hp = NULL;
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
}
}
+#if NAMED_BIND
+ if (map->map_timeout > 0)
+ _res.retrans = retrans;
+ if (map->map_retry > 0)
+ _res.retry = retry;
+#endif /* NAMED_BIND */
s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
@@ -3384,23 +3874,25 @@ host_map_lookup(map, name, av, statp)
if (ans != NULL)
{
s->s_namecanon.nc_stat = *statp = EX_OK;
- s->s_namecanon.nc_cname = newstr(ans);
+ if (s->s_namecanon.nc_cname != NULL)
+ sm_free(s->s_namecanon.nc_cname);
+ s->s_namecanon.nc_cname = sm_strdup_x(ans);
if (bitset(MF_MATCHONLY, map->map_mflags))
cp = map_rewrite(map, name, strlen(name), NULL);
else
cp = map_rewrite(map, ans, strlen(ans), av);
if (tTd(9, 1))
- dprintf("FOUND %s\n", ans);
+ sm_dprintf("FOUND %s\n", ans);
return cp;
}
/* No match found */
s->s_namecanon.nc_errno = errno;
-# if NAMED_BIND
+#if NAMED_BIND
s->s_namecanon.nc_herrno = h_errno;
if (tTd(9, 1))
- dprintf("FAIL (%d)\n", h_errno);
+ sm_dprintf("FAIL (%d)\n", h_errno);
switch (h_errno)
{
case TRY_AGAIN:
@@ -3426,152 +3918,23 @@ host_map_lookup(map, name, av, statp)
*statp = EX_UNAVAILABLE;
break;
}
-# else /* NAMED_BIND */
+#else /* NAMED_BIND */
if (tTd(9, 1))
- dprintf("FAIL\n");
+ sm_dprintf("FAIL\n");
*statp = EX_NOHOST;
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
s->s_namecanon.nc_stat = *statp;
return NULL;
}
-#else /* DAEMON */
-/* code for systems without sophisticated networking */
-
/*
-** MYHOSTNAME -- stub version for case of no daemon code.
-**
-** Can't convert to upper case here because might be a UUCP name.
-**
-** Mark, you can change this to be anything you want......
-*/
-
-char **
-myhostname(hostbuf, size)
- char hostbuf[];
- int size;
-{
- register FILE *f;
-
- hostbuf[0] = '\0';
- f = fopen("/usr/include/whoami", "r");
- if (f != NULL)
- {
- (void) fgets(hostbuf, size, f);
- fixcrlf(hostbuf, TRUE);
- (void) fclose(f);
- }
- if (hostbuf[0] == '\0')
- (void) strlcpy(hostbuf, "localhost", size);
- return NULL;
-}
- /*
-** GETAUTHINFO -- get the real host name associated with a file descriptor
-**
-** Parameters:
-** fd -- the descriptor
-** may_be_forged -- an outage that is set to TRUE if the
-** forward lookup of RealHostName does not match
-** RealHostAddr; set to FALSE if they do match.
-**
-** Returns:
-** The host name associated with this descriptor, if it can
-** be determined.
-** NULL otherwise.
-**
-** Side Effects:
-** none
-*/
-
-char *
-getauthinfo(fd, may_be_forged)
- int fd;
- bool *may_be_forged;
-{
- *may_be_forged = FALSE;
- return NULL;
-}
- /*
-** HOST_MAP_LOOKUP -- turn a hostname into canonical form
+** HOST_MAP_INIT -- initialize host class structures
**
** Parameters:
-** map -- a pointer to the database map.
-** name -- a buffer containing a hostname.
-** avp -- a pointer to a (cf file defined) argument vector.
-** statp -- an exit status (out parameter).
+** map -- a pointer to this map.
+** args -- argument string.
**
** Returns:
-** mapped host name
-** FALSE otherwise.
-**
-** Side Effects:
-** Looks up the host specified in name. If it is not
-** the canonical name for that host, replace it with
-** the canonical name. If the name is unknown, or it
-** is already the canonical name, leave it unchanged.
-*/
-
-/*ARGSUSED*/
-char *
-host_map_lookup(map, name, avp, statp)
- MAP *map;
- char *name;
- char **avp;
- char *statp;
-{
- register struct hostent *hp = NULL;
- char *cp;
-
- hp = sm_gethostbyname(name, InetMode);
- if (hp == NULL && InetMode != AF_INET)
- hp = sm_gethostbyname(name, AF_INET);
- if (hp == NULL)
- {
-# if NAMED_BIND
- if (tTd(9, 1))
- dprintf("FAIL (%d)\n", h_errno);
- switch (h_errno)
- {
- case TRY_AGAIN:
- if (UseNameServer)
- {
- CurEnv->e_status = "4.4.3";
- message("851 %s: Name server timeout",
- shortenstring(name, 33));
- }
- *statp = EX_TEMPFAIL;
- break;
-
- case HOST_NOT_FOUND:
- case NO_DATA:
- *statp = EX_NOHOST;
- break;
-
- case NO_RECOVERY:
- *statp = EX_SOFTWARE;
- break;
-
- default:
- *statp = EX_UNAVAILABLE;
- break;
- }
-#else /* NAMED_BIND */
- *statp = EX_NOHOST;
-#endif /* NAMED_BIND */
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- cp = map_rewrite(map, name, strlen(name), NULL);
- else
- cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
-# if _FFR_FREEHOSTENT && NETINET6
- freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
- return cp;
-}
-
-#endif /* DAEMON */
- /*
-** HOST_MAP_INIT -- initialize host class structures
+** true.
*/
bool
@@ -3612,6 +3975,27 @@ host_map_init(map, args)
case 'D':
map->map_mflags |= MF_DEFER;
break;
+
+ case 'd':
+ {
+ char *h;
+
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+ map->map_timeout = convtime(p, 's');
+ if (h != NULL)
+ *h = ' ';
+ }
+ break;
+
+ case 'r':
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ map->map_retry = atoi(p);
+ break;
}
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
@@ -3622,9 +4006,9 @@ host_map_init(map, args)
map->map_app = newstr(map->map_app);
if (map->map_tapp != NULL)
map->map_tapp = newstr(map->map_tapp);
- return TRUE;
+ return true;
}
-
+
#if NETINET6
/*
** ANYNET_NTOP -- convert an IPv6 network address to printable form.
@@ -3637,6 +4021,7 @@ host_map_init(map, args)
** Returns:
** A printable version of that structure.
*/
+
char *
anynet_ntop(s6a, dst, dst_len)
struct in6_addr *s6a;
@@ -3650,11 +4035,56 @@ anynet_ntop(s6a, dst, dst_len)
&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
dst, dst_len);
else
+ {
+ char *d;
+ size_t sz;
+
+ /* Save pointer to beginning of string */
+ d = dst;
+
+ /* Add IPv6: protocol tag */
+ sz = sm_strlcpy(dst, "IPv6:", dst_len);
+ if (sz >= dst_len)
+ return NULL;
+ dst += sz;
+ dst_len -= sz;
ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
+
+ /* Restore pointer to beginning of string */
+ if (ap != NULL)
+ ap = d;
+ }
return ap;
}
+
+/*
+** ANYNET_PTON -- convert printed form to network address.
+**
+** Wrapper for inet_pton() which handles IPv6: labels.
+**
+** Parameters:
+** family -- address family
+** src -- string
+** dst -- destination address structure
+**
+** Returns:
+** 1 if the address was valid
+** 0 if the address wasn't parseable
+** -1 if error
+*/
+
+int
+anynet_pton(family, src, dst)
+ int family;
+ const char *src;
+ void *dst;
+{
+ if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0)
+ src += 5;
+ return inet_pton(family, src, dst);
+}
#endif /* NETINET6 */
- /*
+/*
** ANYNET_NTOA -- convert a network address to printable form.
**
** Parameters:
@@ -3690,10 +4120,10 @@ anynet_ntoa(sap)
# if NETUNIX
case AF_UNIX:
if (sap->sunix.sun_path[0] != '\0')
- snprintf(buf, sizeof buf, "[UNIX: %.64s]",
- sap->sunix.sun_path);
+ (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]",
+ sap->sunix.sun_path);
else
- snprintf(buf, sizeof buf, "[UNIX: localhost]");
+ (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf);
return buf;
# endif /* NETUNIX */
@@ -3712,8 +4142,8 @@ anynet_ntoa(sap)
# if NETLINK
case AF_LINK:
- snprintf(buf, sizeof buf, "[LINK: %s]",
- link_ntoa((struct sockaddr_dl *) &sap->sa));
+ (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]",
+ link_ntoa((struct sockaddr_dl *) &sap->sa));
return buf;
# endif /* NETLINK */
default:
@@ -3723,18 +4153,19 @@ anynet_ntoa(sap)
}
/* unknown family -- just dump bytes */
- (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
+ (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
bp = &buf[strlen(buf)];
ap = sap->sa.sa_data;
for (l = sizeof sap->sa.sa_data; --l >= 0; )
{
- (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
+ *ap++ & 0377);
bp += 3;
}
*--bp = '\0';
return buf;
}
- /*
+/*
** HOSTNAMEBYANYADDR -- return name of host based on address
**
** Parameters:
@@ -3771,24 +4202,21 @@ hostnamebyanyaddr(sap)
# if NETINET
case AF_INET:
hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
- INADDRSZ,
- AF_INET);
+ INADDRSZ, AF_INET);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
- IN6ADDRSZ,
- AF_INET6);
+ IN6ADDRSZ, AF_INET6);
break;
# endif /* NETINET6 */
# if NETISO
case AF_ISO:
hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
- sizeof sap->siso.siso_addr,
- AF_ISO);
+ sizeof sap->siso.siso_addr, AF_ISO);
break;
# endif /* NETISO */
@@ -3799,9 +4227,8 @@ hostnamebyanyaddr(sap)
# endif /* NETUNIX */
default:
- hp = sm_gethostbyaddr(sap->sa.sa_data,
- sizeof sap->sa.sa_data,
- sap->sa.sa_family);
+ hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data,
+ sap->sa.sa_family);
break;
}
@@ -3821,31 +4248,29 @@ hostnamebyanyaddr(sap)
{
char *name;
- name = denlstring((char *) hp->h_name, TRUE, TRUE);
-
-# if _FFR_FREEHOSTENT && NETINET6
+ name = denlstring((char *) hp->h_name, true, true);
+# if NETINET6
if (name == hp->h_name)
{
static char n[MAXNAME + 1];
/* Copy the string, hp->h_name is about to disappear */
- strlcpy(n, name, sizeof n);
+ (void) sm_strlcpy(n, name, sizeof n);
name = n;
}
-
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return name;
}
# endif /* NETINET || NETINET6 */
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
if (hp != NULL)
{
freehostent(hp);
hp = NULL;
}
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
# if NETUNIX
if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
@@ -3854,7 +4279,8 @@ hostnamebyanyaddr(sap)
{
static char buf[203];
- (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
+ (void) sm_snprintf(buf, sizeof buf, "[%.200s]",
+ anynet_ntoa(sap));
return buf;
}
}
diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c
index 70b774d..402eac4 100644
--- a/contrib/sendmail/src/deliver.c
+++ b/contrib/sendmail/src/deliver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,34 +11,35 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: deliver.c,v 8.600.2.1.2.86 2001/07/20 21:52:55 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+#include <sys/time.h>
+SM_RCSID("@(#)$Id: deliver.c,v 8.928 2002/01/10 03:23:29 gshapiro Exp $")
#if HASSETUSERCONTEXT
# include <login_cap.h>
#endif /* HASSETUSERCONTEXT */
-#if STARTTLS || (SASL && SFIO)
+#if STARTTLS || SASL
# include "sfsasl.h"
-#endif /* STARTTLS || (SASL && SFIO) */
+#endif /* STARTTLS || SASL */
+void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
static int deliver __P((ENVELOPE *, ADDRESS *));
static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
static void mailfiletimeout __P((void));
-static void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
static int parse_hostsignature __P((char *, char **, MAILER *));
static void sendenvelope __P((ENVELOPE *, int));
-static char *hostsignature __P((MAILER *, char *));
+extern MCI *mci_new __P((SM_RPOOL_T *));
+static int coloncmp __P((const char *, const char *));
-#if SMTP
-# if STARTTLS
+#if STARTTLS
static int starttls __P((MAILER *, MCI *, ENVELOPE *));
-# endif /* STARTTLS */
-#endif /* SMTP */
+static int endtlsclt __P((MCI *));
+#endif /* STARTTLS */
+# if STARTTLS || SASL
+static bool iscltflgset __P((ENVELOPE *, int));
+# endif /* STARTTLS || SASL */
/*
** SENDALL -- actually send all the messages.
@@ -70,7 +71,7 @@ sendall(e, mode)
register ENVELOPE *ee;
ENVELOPE *splitenv = NULL;
int oldverbose = Verbose;
- bool somedeliveries = FALSE, expensive = FALSE;
+ bool somedeliveries = false, expensive = false;
pid_t pid;
/*
@@ -81,11 +82,13 @@ sendall(e, mode)
if (bitset(EF_DISCARD, e->e_flags))
{
if (tTd(13, 1))
- dprintf("sendall: discarding id %s\n", e->e_id);
+ sm_dprintf("sendall: discarding id %s\n", e->e_id);
e->e_flags |= EF_CLRQUEUE;
- if (LogLevel > 4)
+ if (LogLevel > 9)
+ logundelrcpts(e, "discarded", 9, true);
+ else if (LogLevel > 4)
sm_syslog(LOG_INFO, e->e_id, "discarded");
- markstats(e, NULL, TRUE);
+ markstats(e, NULL, STATS_REJECT);
return;
}
@@ -114,13 +117,13 @@ sendall(e, mode)
if (tTd(13, 1))
{
- dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
+ sm_dprintf("\n===== SENDALL: mode %c, id %s, e_from ",
mode, e->e_id);
- printaddr(&e->e_from, FALSE);
- dprintf("\te_flags = ");
+ printaddr(&e->e_from, false);
+ sm_dprintf("\te_flags = ");
printenvflags(e);
- dprintf("sendqueue:\n");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("sendqueue:\n");
+ printaddr(e->e_sendqueue, true);
}
/*
@@ -144,9 +147,7 @@ sendall(e, mode)
recip = "(nobody)";
errno = 0;
-#if QUEUE
- queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
-#endif /* QUEUE */
+ queueup(e, WILL_BE_QUEUED(mode), false);
e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
ExitStat = EX_UNAVAILABLE;
syserr("554 5.4.6 Too many hops %d (%d max): from %s via %s, to %s",
@@ -178,8 +179,8 @@ sendall(e, mode)
{
if (tTd(13, 5))
{
- dprintf("sendall: QS_SENDER ");
- printaddr(&e->e_from, FALSE);
+ sm_dprintf("sendall: QS_SENDER ");
+ printaddr(&e->e_from, false);
}
e->e_from.q_state = QS_SENDER;
(void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
@@ -209,8 +210,8 @@ sendall(e, mode)
if (tTd(13, 25))
{
- dprintf("\nAfter first owner pass, sendq =\n");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("\nAfter first owner pass, sendq =\n");
+ printaddr(e->e_sendqueue, true);
}
owner = "";
@@ -218,8 +219,8 @@ sendall(e, mode)
while (owner != NULL && otherowners > 0)
{
if (tTd(13, 28))
- dprintf("owner = \"%s\", otherowners = %d\n",
- owner, otherowners);
+ sm_dprintf("owner = \"%s\", otherowners = %d\n",
+ owner, otherowners);
owner = NULL;
otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
@@ -227,19 +228,19 @@ sendall(e, mode)
{
if (tTd(13, 30))
{
- dprintf("Checking ");
- printaddr(q, FALSE);
+ sm_dprintf("Checking ");
+ printaddr(q, false);
}
if (QS_IS_DEAD(q->q_state))
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_DEAD\n");
+ sm_dprintf(" ... QS_IS_DEAD\n");
continue;
}
if (tTd(13, 29) && !tTd(13, 30))
{
- dprintf("Checking ");
- printaddr(q, FALSE);
+ sm_dprintf("Checking ");
+ printaddr(q, false);
}
if (q->q_owner != NULL)
@@ -247,8 +248,8 @@ sendall(e, mode)
if (owner == NULL)
{
if (tTd(13, 40))
- dprintf(" ... First owner = \"%s\"\n",
- q->q_owner);
+ sm_dprintf(" ... First owner = \"%s\"\n",
+ q->q_owner);
owner = q->q_owner;
}
else if (owner != q->q_owner)
@@ -256,8 +257,8 @@ sendall(e, mode)
if (strcmp(owner, q->q_owner) == 0)
{
if (tTd(13, 40))
- dprintf(" ... Same owner = \"%s\"\n",
- owner);
+ sm_dprintf(" ... Same owner = \"%s\"\n",
+ owner);
/* make future comparisons cheap */
q->q_owner = owner;
@@ -265,27 +266,27 @@ sendall(e, mode)
else
{
if (tTd(13, 40))
- dprintf(" ... Another owner \"%s\"\n",
- q->q_owner);
+ sm_dprintf(" ... Another owner \"%s\"\n",
+ q->q_owner);
otherowners++;
}
owner = q->q_owner;
}
else if (tTd(13, 40))
- dprintf(" ... Same owner = \"%s\"\n",
- owner);
+ sm_dprintf(" ... Same owner = \"%s\"\n",
+ owner);
}
else
{
if (tTd(13, 40))
- dprintf(" ... Null owner\n");
+ sm_dprintf(" ... Null owner\n");
otherowners++;
}
if (QS_IS_BADADDR(q->q_state))
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_BADADDR\n");
+ sm_dprintf(" ... QS_IS_BADADDR\n");
continue;
}
@@ -302,28 +303,27 @@ sendall(e, mode)
if (FallBackMX != NULL &&
!wordinclass(FallBackMX, 'w') &&
mode != SM_VERIFY &&
- (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0) &&
+ !bitnset(M_NOMX, m->m_flags) &&
+ strcmp(m->m_mailer, "[IPC]") == 0 &&
m->m_argv[0] != NULL &&
- (strcmp(m->m_argv[0], "TCP") == 0 ||
- strcmp(m->m_argv[0], "IPC") == 0))
+ strcmp(m->m_argv[0], "TCP") == 0)
{
int len;
char *p;
if (tTd(13, 30))
- dprintf(" ... FallBackMX\n");
+ sm_dprintf(" ... FallBackMX\n");
- len = strlen(FallBackMX) + 3;
- p = xalloc(len);
- snprintf(p, len, "[%s]", FallBackMX);
+ len = strlen(FallBackMX) + 1;
+ p = sm_rpool_malloc_x(e->e_rpool, len);
+ (void) sm_strlcpy(p, FallBackMX, len);
q->q_state = QS_OK;
q->q_host = p;
}
else
{
if (tTd(13, 30))
- dprintf(" ... QS_IS_QUEUEUP\n");
+ sm_dprintf(" ... QS_IS_QUEUEUP\n");
continue;
}
}
@@ -341,9 +341,9 @@ sendall(e, mode)
bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
{
if (tTd(13, 30))
- dprintf(" ... expensive\n");
+ sm_dprintf(" ... expensive\n");
q->q_state = QS_QUEUEUP;
- expensive = TRUE;
+ expensive = true;
}
else if (bitnset(M_HOLD, q->q_mailer->m_flags) &&
QueueLimitId == NULL &&
@@ -351,15 +351,26 @@ sendall(e, mode)
QueueLimitRecipient == NULL)
{
if (tTd(13, 30))
- dprintf(" ... hold\n");
+ sm_dprintf(" ... hold\n");
+ q->q_state = QS_QUEUEUP;
+ expensive = true;
+ }
+#if _FFR_QUARANTINE
+ else if (QueueMode != QM_QUARANTINE &&
+ e->e_quarmsg != NULL)
+ {
+ if (tTd(13, 30))
+ sm_dprintf(" ... quarantine: %s\n",
+ e->e_quarmsg);
q->q_state = QS_QUEUEUP;
- expensive = TRUE;
+ expensive = true;
}
+#endif /* _FFR_QUARANTINE */
else
{
if (tTd(13, 30))
- dprintf(" ... deliverable\n");
- somedeliveries = TRUE;
+ sm_dprintf(" ... deliverable\n");
+ somedeliveries = true;
}
}
@@ -369,35 +380,45 @@ sendall(e, mode)
** Split this envelope into two.
*/
- ee = (ENVELOPE *) xalloc(sizeof *ee);
- *ee = *e;
+ ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool,
+ sizeof *ee);
+ STRUCTCOPY(*e, *ee);
ee->e_message = NULL;
ee->e_id = NULL;
assign_queueid(ee);
if (tTd(13, 1))
- dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
- e->e_id, ee->e_id, owner, otherowners);
-
- ee->e_header = copyheader(e->e_header);
- ee->e_sendqueue = copyqueue(e->e_sendqueue);
- ee->e_errorqueue = copyqueue(e->e_errorqueue);
+ sm_dprintf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
+ e->e_id, ee->e_id, owner,
+ otherowners);
+
+ ee->e_header = copyheader(e->e_header, ee->e_rpool);
+ ee->e_sendqueue = copyqueue(e->e_sendqueue,
+ ee->e_rpool);
+ ee->e_errorqueue = copyqueue(e->e_errorqueue,
+ ee->e_rpool);
ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
ee->e_flags |= EF_NORECEIPT;
- setsender(owner, ee, NULL, '\0', TRUE);
+ setsender(owner, ee, NULL, '\0', true);
if (tTd(13, 5))
{
- dprintf("sendall(split): QS_SENDER ");
- printaddr(&ee->e_from, FALSE);
+ sm_dprintf("sendall(split): QS_SENDER ");
+ printaddr(&ee->e_from, false);
}
ee->e_from.q_state = QS_SENDER;
ee->e_dfp = NULL;
ee->e_lockfp = NULL;
ee->e_xfp = NULL;
- ee->e_queuedir = e->e_queuedir;
+ ee->e_qgrp = e->e_qgrp;
+ ee->e_qdir = e->e_qdir;
ee->e_errormode = EM_MAIL;
ee->e_sibling = splitenv;
ee->e_statmsg = NULL;
+#if _FFR_QUARANTINE
+ if (e->e_quarmsg != NULL)
+ ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
+ e->e_quarmsg);
+#endif /* _FFR_QUARANTINE */
splitenv = ee;
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
@@ -406,8 +427,8 @@ sendall(e, mode)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
- dprintf("\t... stripping %s from original envelope\n",
- q->q_paddr);
+ sm_dprintf("\t... stripping %s from original envelope\n",
+ q->q_paddr);
}
}
for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
@@ -416,8 +437,8 @@ sendall(e, mode)
{
q->q_state = QS_CLONED;
if (tTd(13, 6))
- dprintf("\t... dropping %s from cloned envelope\n",
- q->q_paddr);
+ sm_dprintf("\t... dropping %s from cloned envelope\n",
+ q->q_paddr);
}
else
{
@@ -425,13 +446,13 @@ sendall(e, mode)
q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
if (tTd(13, 6))
- dprintf("\t... moving %s to cloned envelope\n",
- q->q_paddr);
+ sm_dprintf("\t... moving %s to cloned envelope\n",
+ q->q_paddr);
}
}
if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
- dup_queue_file(e, ee, 'd');
+ dup_queue_file(e, ee, DATAFL_LETTER);
/*
** Give the split envelope access to the parent
@@ -441,26 +462,26 @@ sendall(e, mode)
*/
if (e->e_xfp != NULL)
- ee->e_xfp = bfdup(e->e_xfp);
+ ee->e_xfp = sm_io_dup(e->e_xfp);
/* failed to dup e->e_xfp, start a new transcript */
if (ee->e_xfp == NULL)
openxscript(ee);
if (mode != SM_VERIFY && LogLevel > 4)
- sm_syslog(LOG_INFO, ee->e_id,
- "clone %s, owner=%s",
- e->e_id, owner);
+ sm_syslog(LOG_INFO, e->e_id,
+ "%s: clone: owner=%s",
+ ee->e_id, owner);
}
}
if (owner != NULL)
{
- setsender(owner, e, NULL, '\0', TRUE);
+ setsender(owner, e, NULL, '\0', true);
if (tTd(13, 5))
{
- dprintf("sendall(owner): QS_SENDER ");
- printaddr(&e->e_from, FALSE);
+ sm_dprintf("sendall(owner): QS_SENDER ");
+ printaddr(&e->e_from, false);
}
e->e_from.q_state = QS_SENDER;
e->e_errormode = EM_MAIL;
@@ -469,14 +490,15 @@ sendall(e, mode)
}
/* if nothing to be delivered, just queue up everything */
- if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
+ if (!somedeliveries && !WILL_BE_QUEUED(mode) &&
mode != SM_VERIFY)
{
- time_t now = curtime();
+ time_t now;
if (tTd(13, 29))
- dprintf("No deliveries: auto-queuing\n");
+ sm_dprintf("No deliveries: auto-queuing\n");
mode = SM_QUEUE;
+ now = curtime();
/* treat this as a delivery in terms of counting tries */
e->e_dtime = now;
@@ -490,11 +512,12 @@ sendall(e, mode)
}
}
-#if QUEUE
- if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
- (mode != SM_VERIFY && SuperSafe)) &&
+ if ((WILL_BE_QUEUED(mode) || mode == SM_FORK ||
+ (mode != SM_VERIFY && SuperSafe == SAFE_REALLY)) &&
(!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
{
+ bool msync;
+
/*
** Be sure everything is instantiated in the queue.
** Split envelopes first in case the machine crashes.
@@ -502,11 +525,16 @@ sendall(e, mode)
** recipients.
*/
+#if !HASFLOCK
+ msync = false;
+#else /* !HASFLOCK */
+ msync = mode == SM_FORK;
+#endif /* !HASFLOCK */
+
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- queueup(ee, mode == SM_QUEUE || mode == SM_DEFER);
- queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
+ queueup(ee, WILL_BE_QUEUED(mode), msync);
+ queueup(e, WILL_BE_QUEUED(mode), msync);
}
-#endif /* QUEUE */
if (tTd(62, 10))
checkfds("after envelope splitting");
@@ -517,20 +545,20 @@ sendall(e, mode)
if (tTd(13, 20))
{
- dprintf("sendall: final mode = %c\n", mode);
+ sm_dprintf("sendall: final mode = %c\n", mode);
if (tTd(13, 21))
{
- dprintf("\n================ Final Send Queue(s) =====================\n");
- dprintf("\n *** Envelope %s, e_from=%s ***\n",
- e->e_id, e->e_from.q_paddr);
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("\n================ Final Send Queue(s) =====================\n");
+ sm_dprintf("\n *** Envelope %s, e_from=%s ***\n",
+ e->e_id, e->e_from.q_paddr);
+ printaddr(e->e_sendqueue, true);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
- dprintf("\n *** Envelope %s, e_from=%s ***\n",
- ee->e_id, ee->e_from.q_paddr);
- printaddr(ee->e_sendqueue, TRUE);
+ sm_dprintf("\n *** Envelope %s, e_from=%s ***\n",
+ ee->e_id, ee->e_from.q_paddr);
+ printaddr(ee->e_sendqueue, true);
}
- dprintf("==========================================================\n\n");
+ sm_dprintf("==========================================================\n\n");
}
}
switch (mode)
@@ -546,18 +574,18 @@ sendall(e, mode)
#endif /* HASFLOCK */
if (e->e_nrcpts > 0)
e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
+ dropenvelope(e, splitenv != NULL, true);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
if (ee->e_nrcpts > 0)
ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
+ dropenvelope(ee, false, true);
}
return;
case SM_FORK:
if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
#if !HASFLOCK
/*
@@ -573,7 +601,7 @@ sendall(e, mode)
/* now drop the envelope in the parent */
e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
+ dropenvelope(e, splitenv != NULL, false);
/* arrange to reacquire lock after fork */
e->e_id = qid;
@@ -586,7 +614,7 @@ sendall(e, mode)
/* drop envelope in parent */
ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
+ dropenvelope(ee, false, false);
/* and save qid for reacquisition */
ee->e_id = qid;
@@ -602,7 +630,7 @@ sendall(e, mode)
** them if necessary.
*/
- closemaps();
+ closemaps(false);
pid = fork();
if (pid < 0)
@@ -624,13 +652,13 @@ sendall(e, mode)
/* close any random open files in the envelope */
closexscript(e);
if (e->e_dfp != NULL)
- (void) bfclose(e->e_dfp);
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
e->e_dfp = NULL;
e->e_flags &= ~EF_HAS_DF;
/* can't call unlockqueue to avoid unlink of xfp */
if (e->e_lockfp != NULL)
- (void) fclose(e->e_lockfp);
+ (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
else
syserr("%s: sendall: null lockfp", e->e_id);
e->e_lockfp = NULL;
@@ -639,30 +667,44 @@ sendall(e, mode)
/* make sure the parent doesn't own the envelope */
e->e_id = NULL;
+#if USE_DOUBLE_FORK
/* catch intermediate zombie */
(void) waitfor(pid);
+#endif /* USE_DOUBLE_FORK */
return;
}
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
/*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ sm_exc_newthread(fatal_error);
+
+ /*
** Since we have accepted responsbility for the message,
** change the SIGTERM handler. intsig() (the old handler)
** would remove the envelope if this was a command line
** message submission.
*/
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGTERM, SIG_DFL);
+#if USE_DOUBLE_FORK
/* double fork to avoid zombies */
pid = fork();
if (pid > 0)
exit(EX_OK);
save_errno = errno;
+#endif /* USE_DOUBLE_FORK */
+
+ CurrentPid = getpid();
/* be sure we are immune from the terminal */
disconnect(2, e);
@@ -678,11 +720,11 @@ sendall(e, mode)
#else /* HASFLOCK */
e->e_id = NULL;
#endif /* HASFLOCK */
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
}
/* be sure to give error messages in child */
- QuickAbort = FALSE;
+ QuickAbort = false;
/*
** Close any cached connections.
@@ -694,7 +736,7 @@ sendall(e, mode)
** message.
*/
- mci_flush(FALSE, NULL);
+ mci_flush(false, NULL);
#if HASFLOCK
break;
@@ -708,31 +750,31 @@ sendall(e, mode)
{
ENVELOPE *sibling = ee->e_sibling;
- (void) dowork(ee->e_queuedir, ee->e_id,
- FALSE, FALSE, ee);
+ (void) dowork(ee->e_qgrp, ee->e_qdir, ee->e_id,
+ false, false, ee);
ee->e_sibling = sibling;
}
- (void) dowork(e->e_queuedir, e->e_id,
- FALSE, FALSE, e);
- finis(TRUE, ExitStat);
+ (void) dowork(e->e_qgrp, e->e_qdir, e->e_id,
+ false, false, e);
+ finis(true, true, ExitStat);
#endif /* HASFLOCK */
}
sendenvelope(e, mode);
- dropenvelope(e, TRUE);
+ dropenvelope(e, true, true);
for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
{
CurEnv = ee;
if (mode != SM_VERIFY)
openxscript(ee);
sendenvelope(ee, mode);
- dropenvelope(ee, TRUE);
+ dropenvelope(ee, true, true);
}
CurEnv = e;
Verbose = oldverbose;
if (mode == SM_FORK)
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
}
static void
@@ -744,9 +786,9 @@ sendenvelope(e, mode)
bool didany;
if (tTd(13, 10))
- dprintf("sendenvelope(%s) e_flags=0x%lx\n",
- e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
- e->e_flags);
+ sm_dprintf("sendenvelope(%s) e_flags=0x%lx\n",
+ e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
+ e->e_flags);
if (LogLevel > 80)
sm_syslog(LOG_DEBUG, e->e_id,
"sendenvelope, flags=0x%lx",
@@ -766,9 +808,15 @@ sendenvelope(e, mode)
return;
}
- /* Don't attempt deliveries if we want to bounce now */
+ /*
+ ** Don't attempt deliveries if we want to bounce now
+ ** or if deliver-by time is exceeded.
+ */
+
if (!bitset(EF_RESPONSE, e->e_flags) &&
- TimeOuts.to_q_return[e->e_timeoutclass] == NOW)
+ (TimeOuts.to_q_return[e->e_timeoutclass] == NOW ||
+ (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
+ curtime() > e->e_ctime + e->e_deliver_by)))
return;
/*
@@ -781,9 +829,52 @@ sendenvelope(e, mode)
e->e_nsent = 0;
e->e_flags |= EF_GLOBALERRS;
- define(macid("{envid}", NULL), e->e_envid, e);
- define(macid("{bodytype}", NULL), e->e_bodytype, e);
- didany = FALSE;
+ macdefine(&e->e_macro, A_PERM, macid("{envid}"), e->e_envid);
+ macdefine(&e->e_macro, A_PERM, macid("{bodytype}"), e->e_bodytype);
+ didany = false;
+
+ if (!bitset(EF_SPLIT, e->e_flags))
+ {
+ ENVELOPE *oldsib;
+ ENVELOPE *ee;
+
+ /*
+ ** Save old sibling and set it to NULL to avoid
+ ** queueing up the same envelopes again.
+ ** This requires that envelopes in that list have
+ ** been take care of before (or at some other place).
+ */
+
+ oldsib = e->e_sibling;
+ e->e_sibling = NULL;
+ if (!split_by_recipient(e) &&
+ bitset(EF_FATALERRS, e->e_flags))
+ {
+ if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
+ e->e_flags |= EF_CLRQUEUE;
+ return;
+ }
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ queueup(ee, false, true);
+
+ /* clean up */
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ {
+ /* now unlock the job */
+ closexscript(ee);
+ unlockqueue(ee);
+
+ /* this envelope is marked unused */
+ if (ee->e_dfp != NULL)
+ {
+ (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT);
+ ee->e_dfp = NULL;
+ }
+ ee->e_id = NULL;
+ ee->e_flags &= ~EF_HAS_DF;
+ }
+ e->e_sibling = oldsib;
+ }
/* now run through the queue */
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
@@ -791,8 +882,8 @@ sendenvelope(e, mode)
#if XDEBUG
char wbuf[MAXNAME + 20];
- (void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
- MAXNAME, q->q_paddr);
+ (void) sm_snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
+ MAXNAME, q->q_paddr);
checkfd012(wbuf);
#endif /* XDEBUG */
if (mode == SM_VERIFY)
@@ -813,7 +904,6 @@ sendenvelope(e, mode)
}
else if (QS_IS_OK(q->q_state))
{
-#if QUEUE
/*
** Checkpoint the send list every few addresses
*/
@@ -821,12 +911,11 @@ sendenvelope(e, mode)
if (CheckpointInterval > 0 &&
e->e_nsent >= CheckpointInterval)
{
- queueup(e, FALSE);
+ queueup(e, false, false);
e->e_nsent = 0;
}
-#endif /* QUEUE */
(void) deliver(e, q);
- didany = TRUE;
+ didany = true;
}
}
if (didany)
@@ -839,13 +928,66 @@ sendenvelope(e, mode)
checkfd012("end of sendenvelope");
#endif /* XDEBUG */
}
- /*
+
+#if REQUIRES_DIR_FSYNC
+/*
+** SYNC_DIR -- fsync a directory based on a filename
+**
+** Parameters:
+** filename -- path of file
+** panic -- panic?
+**
+** Returns:
+** none
+*/
+
+void
+sync_dir(filename, panic)
+ char *filename;
+ bool panic;
+{
+ int dirfd;
+ char *dirp;
+ char dir[MAXPATHLEN];
+
+ /* filesystems which require the directory be synced */
+ dirp = strrchr(filename, '/');
+ if (dirp != NULL)
+ {
+ if (sm_strlcpy(dir, filename, sizeof dir) >= sizeof dir)
+ return;
+ dir[dirp - filename] = '\0';
+ dirp = dir;
+ }
+ else
+ dirp = ".";
+ dirfd = open(dirp, O_RDONLY, 0700);
+ if (tTd(40,32))
+ sm_syslog(LOG_INFO, NOQID, "sync_dir: %s: fsync(%d)",
+ dirp, dirfd);
+ if (dirfd >= 0)
+ {
+ if (fsync(dirfd) < 0)
+ {
+ if (panic)
+ syserr("!sync_dir: cannot fsync directory %s",
+ dirp);
+ else if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "sync_dir: cannot fsync directory %s: %s",
+ dirp, sm_errstring(errno));
+ }
+ (void) close(dirfd);
+ }
+}
+#endif /* REQUIRES_DIR_FSYNC */
+/*
** DUP_QUEUE_FILE -- duplicate a queue file into a split queue
**
** Parameters:
** e -- the existing envelope
** ee -- the new envelope
-** type -- the queue file type (e.g., 'd')
+** type -- the queue file type (e.g., DATAFL_LETTER)
**
** Returns:
** none
@@ -853,7 +995,7 @@ sendenvelope(e, mode)
static void
dup_queue_file(e, ee, type)
- struct envelope *e, *ee;
+ ENVELOPE *e, *ee;
int type;
{
char f1buf[MAXPATHLEN], f2buf[MAXPATHLEN];
@@ -865,8 +1007,8 @@ dup_queue_file(e, ee, type)
** Make sure both are in the same directory.
*/
- snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type));
- snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type));
+ (void) sm_strlcpy(f1buf, queuename(e, type), sizeof f1buf);
+ (void) sm_strlcpy(f2buf, queuename(ee, type), sizeof f2buf);
if (link(f1buf, f2buf) < 0)
{
int save_errno = errno;
@@ -877,19 +1019,20 @@ dup_queue_file(e, ee, type)
if (unlink(f2buf) < 0)
{
syserr("!sendall: unlink(%s): permanent",
- f2buf);
+ f2buf);
/* NOTREACHED */
}
if (link(f1buf, f2buf) < 0)
{
syserr("!sendall: link(%s, %s): permanent",
- f1buf, f2buf);
+ f1buf, f2buf);
/* NOTREACHED */
}
}
}
+ SYNC_DIR(f2buf, true);
}
- /*
+/*
** DOFORK -- do a fork, retrying a couple of times on failure.
**
** This MUST be a macro, since after a vfork we are running
@@ -930,7 +1073,7 @@ dup_queue_file(e, ee, type)
(void) sleep((unsigned) NFORKTRIES - i);\
}\
}
- /*
+/*
** DOFORK -- simple fork interface to DOFORK.
**
** Parameters:
@@ -953,7 +1096,73 @@ dofork()
DOFORK(fork);
return pid;
}
- /*
+
+/*
+** COLONCMP -- compare host-signatures up to first ':' or EOS
+**
+** This takes two strings which happen to be host-signatures and
+** compares them. If the lowest preference portions of the MX-RR's
+** match (up to ':' or EOS, whichever is first), then we have
+** match. This is used for coattail-piggybacking messages during
+** message delivery.
+** If the signatures are the same up to the first ':' the remainder of
+** the signatures are then compared with a normal strcmp(). This saves
+** re-examining the first part of the signatures.
+**
+** Parameters:
+** a - first host-signature
+** b - second host-signature
+**
+** Returns:
+** HS_MATCH_NO -- no "match".
+** HS_MATCH_FIRST -- "match" for the first MX preference
+** (up to the first colon (':')).
+** HS_MATCH_FULL -- match for the entire MX record.
+**
+** Side Effects:
+** none.
+*/
+
+#define HS_MATCH_NO 0
+#define HS_MATCH_FIRST 1
+#define HS_MATCH_FULL 2
+
+static int
+coloncmp(a, b)
+ register const char *a;
+ register const char *b;
+{
+ int ret = HS_MATCH_NO;
+ int braclev = 0;
+
+ while (*a == *b++)
+ {
+ /* Need to account for IPv6 bracketed addresses */
+ if (*a == '[')
+ braclev++;
+ else if (*a == '[' && braclev > 0)
+ braclev--;
+ else if (*a == ':' && braclev <= 0)
+ {
+ ret = HS_MATCH_FIRST;
+ a++;
+ break;
+ }
+ else if (*a == '\0')
+ return HS_MATCH_FULL; /* a full match */
+ a++;
+ }
+ if (ret == HS_MATCH_NO &&
+ braclev <= 0 &&
+ ((*a == '\0' && *(b - 1) == ':') ||
+ (*a == ':' && *(b - 1) == '\0')))
+ return HS_MATCH_FIRST;
+ if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0)
+ return HS_MATCH_FULL;
+
+ return ret;
+}
+/*
** DELIVER -- Deliver a message to a list of addresses.
**
** This routine delivers to everyone on the same host as the
@@ -962,6 +1171,45 @@ dofork()
** that it will deliver to all these addresses however -- so
** deliver should be called once for each address on the
** list.
+** Deliver tries to be as opportunistic as possible about piggybacking
+** messages. Some definitions to make understanding easier follow below.
+** Piggybacking occurs when an existing connection to a mail host can
+** be used to send the same message to more than one recipient at the
+** same time. So "no piggybacking" means one message for one recipient
+** per connection. "Intentional piggybacking" happens when the
+** recipients' host address (not the mail host address) is used to
+** attempt piggybacking. Recipients with the same host address
+** have the same mail host. "Coincidental piggybacking" relies on
+** piggybacking based on all the mail host addresses in the MX-RR. This
+** is "coincidental" in the fact it could not be predicted until the
+** MX Resource Records for the hosts were obtained and examined. For
+** example (preference order and equivalence is important, not values):
+** domain1 IN MX 10 mxhost-A
+** IN MX 20 mxhost-B
+** domain2 IN MX 4 mxhost-A
+** IN MX 8 mxhost-B
+** Domain1 and domain2 can piggyback the same message to mxhost-A or
+** mxhost-B (if mxhost-A cannot be reached).
+** "Coattail piggybacking" relaxes the strictness of "coincidental
+** piggybacking" in the hope that most significant (lowest value)
+** MX preference host(s) can create more piggybacking. For example
+** (again, preference order and equivalence is important, not values):
+** domain3 IN MX 100 mxhost-C
+** IN MX 100 mxhost-D
+** IN MX 200 mxhost-E
+** domain4 IN MX 50 mxhost-C
+** IN MX 50 mxhost-D
+** IN MX 80 mxhost-F
+** A message for domain3 and domain4 can piggyback to mxhost-C if mxhost-C
+** is available. Same with mxhost-D because in both RR's the preference
+** value is the same as mxhost-C, respectively.
+** So deliver attempts coattail piggybacking when possible. If the
+** first MX preference level hosts cannot be used then the piggybacking
+** reverts to coincidental piggybacking. Using the above example you
+** cannot deliver to mxhost-F for domain3 regardless of preference value.
+** ("Coattail" from "riding on the coattails of your predecessor" meaning
+** gaining benefit from a predecessor effort with no or little addition
+** effort. The predecessor here being the preceding MX RR).
**
** Parameters:
** e -- the envelope to deliver.
@@ -994,41 +1242,44 @@ deliver(e, firstto)
register char *p;
register MAILER *m; /* mailer for this recipient */
ADDRESS *volatile ctladdr;
+#if HASSETUSERCONTEXT
ADDRESS *volatile contextaddr = NULL;
+#endif /* HASSETUSERCONTEXT */
register MCI *volatile mci;
- register ADDRESS *to = firstto;
- volatile bool clever = FALSE; /* running user smtp to this mailer */
+ register ADDRESS *SM_NONVOLATILE to = firstto;
+ volatile bool clever = false; /* running user smtp to this mailer */
ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
int rcode; /* response code */
- int lmtp_rcode = EX_OK;
- int nummxhosts = 0; /* number of MX hosts available */
- int hostnum = 0; /* current MX host index */
+ SM_NONVOLATILE int lmtp_rcode = EX_OK;
+ SM_NONVOLATILE int nummxhosts = 0; /* number of MX hosts available */
+ SM_NONVOLATILE int hostnum = 0; /* current MX host index */
char *firstsig; /* signature of firstto */
- pid_t pid = -1;
+ volatile pid_t pid = -1;
char *volatile curhost;
- register u_short port = 0;
+ SM_NONVOLATILE unsigned short port = 0;
+ SM_NONVOLATILE time_t enough = 0;
#if NETUNIX
- char *mux_path = NULL; /* path to UNIX domain socket */
+ char *SM_NONVOLATILE mux_path = NULL; /* path to UNIX domain socket */
#endif /* NETUNIX */
time_t xstart;
bool suidwarn;
bool anyok; /* at least one address was OK */
- bool goodmxfound = FALSE; /* at least one MX was OK */
+ SM_NONVOLATILE bool goodmxfound = false; /* at least one MX was OK */
bool ovr;
-#if _FFR_DYNAMIC_TOBUF
+#if _FFR_QUARANTINE
+ bool quarantine;
+#endif /* _FFR_QUARANTINE */
int strsize;
int rcptcount;
+ int ret;
static int tobufsize = 0;
static char *tobuf = NULL;
-#else /* _FFR_DYNAMIC_TOBUF */
- char tobuf[TOBUFSIZE]; /* text line of to people */
-#endif /* _FFR_DYNAMIC_TOBUF */
+ char *rpath; /* translated return path */
int mpvect[2];
int rpvect[2];
char *mxhosts[MAXMXHOSTS + 1];
char *pv[MAXPV + 1];
char buf[MAXNAME + 1];
- char rpathbuf[MAXNAME + 1]; /* translated return path */
errno = 0;
if (!QS_IS_OK(to->q_state))
@@ -1040,29 +1291,32 @@ deliver(e, firstto)
host = to->q_host;
CurEnv = e; /* just in case */
e->e_statmsg = NULL;
-#if SMTP
SmtpError[0] = '\0';
-#endif /* SMTP */
xstart = curtime();
if (tTd(10, 1))
- dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
+ sm_dprintf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
e->e_id, m->m_name, host, to->q_user);
if (tTd(10, 100))
- printopenfds(FALSE);
+ printopenfds(false);
/*
- ** Clear $&{client_*} macros if this is a bounce message to
+ ** Clear {client_*} macros if this is a bounce message to
** prevent rejection by check_compat ruleset.
*/
if (bitset(EF_RESPONSE, e->e_flags))
{
- define(macid("{client_name}", NULL), "", e);
- define(macid("{client_addr}", NULL), "", e);
- define(macid("{client_port}", NULL), "", e);
+ macdefine(&e->e_macro, A_PERM, macid("{client_name}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_port}"), "");
+ macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), "");
}
+ SM_TRY
+ {
+ ADDRESS *skip_back = NULL;
+
/*
** Do initial argv setup.
** Insert the mailer name. Notice that $x expansion is
@@ -1080,15 +1334,18 @@ deliver(e, firstto)
p = e->e_sender;
else
p = e->e_from.q_paddr;
- p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
- if (strlen(p) >= (SIZE_T) sizeof rpathbuf)
+ rpath = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
+ if (strlen(rpath) > MAXSHORTSTR)
{
- p = shortenstring(p, MAXSHORTSTR);
- syserr("remotename: huge return %s", p);
+ rpath = shortenstring(rpath, MAXSHORTSTR);
+
+ /* avoid bogus errno */
+ errno = 0;
+ syserr("remotename: huge return path %s", rpath);
}
- snprintf(rpathbuf, sizeof rpathbuf, "%s", p);
- define('g', rpathbuf, e); /* translated return path */
- define('h', host, e); /* to host */
+ rpath = sm_rpool_strdup_x(e->e_rpool, rpath);
+ macdefine(&e->e_macro, A_PERM, 'g', rpath);
+ macdefine(&e->e_macro, A_PERM, 'h', host);
Errors = 0;
pvp = pv;
*pvp++ = m->m_argv[0];
@@ -1102,7 +1359,7 @@ deliver(e, firstto)
*pvp++ = "-f";
else
*pvp++ = "-r";
- *pvp++ = newstr(rpathbuf);
+ *pvp++ = rpath;
}
/*
@@ -1129,12 +1386,13 @@ deliver(e, firstto)
/* this entry is safe -- go ahead and process it */
expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
if (pvp >= &pv[MAXPV - 3])
{
syserr("554 5.3.5 Too many parameters to %s before $u",
pv[0]);
- return -1;
+ rcode = -1;
+ goto cleanup;
}
}
@@ -1147,14 +1405,8 @@ deliver(e, firstto)
if (*mvp == NULL)
{
/* running LMTP or SMTP */
-#if SMTP
- clever = TRUE;
+ clever = true;
*pvp = NULL;
-#else /* SMTP */
- /* oops! we don't implement SMTP */
- syserr("554 5.3.5 SMTP style mailer not implemented");
- return EX_SOFTWARE;
-#endif /* SMTP */
}
else if (bitnset(M_LMTP, m->m_flags))
{
@@ -1172,62 +1424,85 @@ deliver(e, firstto)
** always send another copy later.
*/
-#if _FFR_DYNAMIC_TOBUF
e->e_to = NULL;
strsize = 2;
rcptcount = 0;
-#else /* _FFR_DYNAMIC_TOBUF */
- tobuf[0] = '\0';
- e->e_to = tobuf;
-#endif /* _FFR_DYNAMIC_TOBUF */
-
ctladdr = NULL;
- firstsig = hostsignature(firstto->q_mailer, firstto->q_host);
+ if (firstto->q_signature == NULL)
+ firstto->q_signature = hostsignature(firstto->q_mailer,
+ firstto->q_host);
+ firstsig = firstto->q_signature;
+
for (; to != NULL; to = to->q_next)
{
/* avoid sending multiple recipients to dumb mailers */
-#if _FFR_DYNAMIC_TOBUF
if (tochain != NULL && !bitnset(M_MUSER, m->m_flags))
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
/* if already sent or not for this host, don't send */
- if (!QS_IS_OK(to->q_state) ||
- to->q_mailer != firstto->q_mailer ||
- strcmp(hostsignature(to->q_mailer, to->q_host),
- firstsig) != 0)
+ if (!QS_IS_OK(to->q_state)) /* already sent; look at next */
continue;
- /* avoid overflowing tobuf */
-#if _FFR_DYNAMIC_TOBUF
- strsize += strlen(to->q_paddr) + 1;
- if (!clever && strsize > TOBUFSIZE)
+ /*
+ ** Must be same mailer to keep grouping rcpts.
+ ** If mailers don't match: continue; sendqueue is not
+ ** sorted by mailers, so don't break;
+ */
+
+ if (to->q_mailer != firstto->q_mailer)
+ continue;
+
+ if (to->q_signature == NULL) /* for safety */
+ to->q_signature = hostsignature(to->q_mailer,
+ to->q_host);
+
+ /*
+ ** This is for coincidental and tailcoat piggybacking messages
+ ** to the same mail host. While the signatures are identical
+ ** (that's the MX-RR's are identical) we can do coincidental
+ ** piggybacking. We try hard for coattail piggybacking
+ ** with the same mail host when the next recipient has the
+ ** same host at lowest preference. It may be that this
+ ** won't work out, so 'skip_back' is maintained if a backup
+ ** to coincidental piggybacking or full signature must happen.
+ */
+
+ ret = firstto == to ? HS_MATCH_FULL :
+ coloncmp(to->q_signature, firstsig);
+ if (ret == HS_MATCH_FULL)
+ skip_back = to;
+ else if (ret == HS_MATCH_NO)
break;
+ if (!clever)
+ {
+ /* avoid overflowing tobuf */
+ strsize += strlen(to->q_paddr) + 1;
+ if (strsize > TOBUFSIZE)
+ break;
+ }
+
if (++rcptcount > to->q_mailer->m_maxrcpt)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
if (tTd(10, 1))
{
- dprintf("\nsend to ");
- printaddr(to, FALSE);
+ sm_dprintf("\nsend to ");
+ printaddr(to, false);
}
/* compute effective uid/gid when sending */
if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
+# if HASSETUSERCONTEXT
contextaddr = ctladdr = getctladdr(to);
+# else /* HASSETUSERCONTEXT */
+ ctladdr = getctladdr(to);
+# endif /* HASSETUSERCONTEXT */
if (tTd(10, 2))
{
- dprintf("ctladdr=");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("ctladdr=");
+ printaddr(ctladdr, false);
}
user = to->q_user;
@@ -1247,45 +1522,61 @@ deliver(e, firstto)
to->q_status = "5.2.3";
else
to->q_status = "5.3.4";
+
/* set to->q_rstatus = NULL; or to the following? */
usrerrenh(to->q_status,
"552 Message is too large; %ld bytes max",
m->m_maxsize);
- markfailure(e, to, NULL, EX_UNAVAILABLE, FALSE);
+ markfailure(e, to, NULL, EX_UNAVAILABLE, false);
giveresponse(EX_UNAVAILABLE, to->q_status, m,
- NULL, ctladdr, xstart, e);
+ NULL, ctladdr, xstart, e, to);
continue;
}
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
+ ovr = true;
- ovr = TRUE;
/* do config file checking of compatibility */
+#if _FFR_QUARANTINE
+ quarantine = (e->e_quarmsg != NULL);
+#endif /* _FFR_QUARANTINE */
rcode = rscheck("check_compat", e->e_from.q_paddr, to->q_paddr,
- e, TRUE, TRUE, 4, NULL);
+ e, true, true, 3, NULL, e->e_id);
if (rcode == EX_OK)
{
/* do in-code checking if not discarding */
if (!bitset(EF_DISCARD, e->e_flags))
{
rcode = checkcompat(to, e);
- ovr = FALSE;
+ ovr = false;
}
}
if (rcode != EX_OK)
{
markfailure(e, to, NULL, rcode, ovr);
giveresponse(rcode, to->q_status, m,
- NULL, ctladdr, xstart, e);
+ NULL, ctladdr, xstart, e, to);
continue;
}
+#if _FFR_QUARANTINE
+ if (!quarantine && e->e_quarmsg != NULL)
+ {
+ /*
+ ** check_compat or checkcompat() has tried
+ ** to quarantine but that isn't supported.
+ ** Revert the attempt.
+ */
+
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), "");
+ }
+#endif /* _FFR_QUARANTINE */
if (bitset(EF_DISCARD, e->e_flags))
{
if (tTd(10, 5))
{
- dprintf("deliver: discarding recipient ");
- printaddr(to, FALSE);
+ sm_dprintf("deliver: discarding recipient ");
+ printaddr(to, false);
}
/* pretend the message was sent */
@@ -1340,11 +1631,11 @@ deliver(e, firstto)
if (strcmp(m->m_mailer, "[FILE]") == 0)
{
- define('u', user, e); /* to user */
+ macdefine(&e->e_macro, A_PERM, 'u', user);
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
- define('z', p, e); /* user's home */
+ macdefine(&e->e_macro, A_PERM, 'z', p);
expand(m->m_argv[1], buf, sizeof buf, e);
if (strlen(buf) > 0)
rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
@@ -1355,8 +1646,8 @@ deliver(e, firstto)
rcode = EX_CONFIG;
}
giveresponse(rcode, to->q_status, m, NULL,
- ctladdr, xstart, e);
- markfailure(e, to, NULL, rcode, TRUE);
+ ctladdr, xstart, e, to);
+ markfailure(e, to, NULL, rcode, true);
e->e_nsent++;
if (rcode == EX_OK)
{
@@ -1366,12 +1657,14 @@ deliver(e, firstto)
{
to->q_flags |= QDELIVERED;
to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp,
+ SM_TIME_DEFAULT,
+ "%s... Successfully delivered\n",
+ to->q_paddr);
}
}
to->q_statdate = curtime();
- markstats(e, to, FALSE);
+ markstats(e, to, STATS_NORMAL);
continue;
}
@@ -1383,20 +1676,13 @@ deliver(e, firstto)
/* link together the chain of recipients */
to->q_tchain = tochain;
tochain = to;
-
-#if _FFR_DYNAMIC_TOBUF
e->e_to = "[CHAIN]";
-#else /* _FFR_DYNAMIC_TOBUF */
- /* create list of users for error messages */
- (void) strlcat(tobuf, ",", sizeof tobuf);
- (void) strlcat(tobuf, to->q_paddr, sizeof tobuf);
-#endif /* _FFR_DYNAMIC_TOBUF */
- define('u', user, e); /* to user */
+ macdefine(&e->e_macro, A_PERM, 'u', user); /* to user */
p = to->q_home;
if (p == NULL && ctladdr != NULL)
p = ctladdr->q_home;
- define('z', p, e); /* user's home */
+ macdefine(&e->e_macro, A_PERM, 'z', p); /* user's home */
/* set the ${dsn_notify} macro if applicable */
if (bitset(QHASNOTIFY, to->q_flags))
@@ -1405,24 +1691,28 @@ deliver(e, firstto)
notify[0] = '\0';
if (bitset(QPINGONSUCCESS, to->q_flags))
- (void) strlcat(notify, "SUCCESS,",
- sizeof notify);
+ (void) sm_strlcat(notify, "SUCCESS,",
+ sizeof notify);
if (bitset(QPINGONFAILURE, to->q_flags))
- (void) strlcat(notify, "FAILURE,",
- sizeof notify);
+ (void) sm_strlcat(notify, "FAILURE,",
+ sizeof notify);
if (bitset(QPINGONDELAY, to->q_flags))
- (void) strlcat(notify, "DELAY,", sizeof notify);
+ (void) sm_strlcat(notify, "DELAY,",
+ sizeof notify);
/* Set to NEVER or drop trailing comma */
if (notify[0] == '\0')
- (void) strlcat(notify, "NEVER", sizeof notify);
+ (void) sm_strlcat(notify, "NEVER",
+ sizeof notify);
else
notify[strlen(notify) - 1] = '\0';
- define(macid("{dsn_notify}", NULL), newstr(notify), e);
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{dsn_notify}"), notify);
}
else
- define(macid("{dsn_notify}", NULL), NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_notify}"), NULL);
/*
** Expand out this user into argument list.
@@ -1431,7 +1721,7 @@ deliver(e, firstto)
if (!clever)
{
expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
if (pvp >= &pv[MAXPV - 2])
{
/* allow some space for trailing parms */
@@ -1441,57 +1731,48 @@ deliver(e, firstto)
}
/* see if any addresses still exist */
-#if _FFR_DYNAMIC_TOBUF
if (tochain == NULL)
-#else /* _FFR_DYNAMIC_TOBUF */
- if (tobuf[0] == '\0')
-#endif /* _FFR_DYNAMIC_TOBUF */
{
- define('g', (char *) NULL, e);
- e->e_to = NULL;
- return 0;
+ rcode = 0;
+ goto cleanup;
}
/* print out messages as full list */
-#if _FFR_DYNAMIC_TOBUF
+ strsize = 1;
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ strsize += strlen(to->q_paddr) + 1;
+ if (strsize < TOBUFSIZE)
+ strsize = TOBUFSIZE;
+ if (strsize > tobufsize)
{
- int l = 1;
- char *tobufptr;
-
- for (to = tochain; to != NULL; to = to->q_tchain)
- l += strlen(to->q_paddr) + 1;
- if (l < TOBUFSIZE)
- l = TOBUFSIZE;
- if (l > tobufsize)
- {
- if (tobuf != NULL)
- sm_free(tobuf);
- tobufsize = l;
- tobuf = xalloc(tobufsize);
- }
- tobufptr = tobuf;
- *tobufptr = '\0';
- for (to = tochain; to != NULL; to = to->q_tchain)
- {
- snprintf(tobufptr, tobufsize - (tobufptr - tobuf),
- ",%s", to->q_paddr);
- tobufptr += strlen(tobufptr);
- }
+ SM_FREE_CLR(tobuf);
+ tobuf = sm_pmalloc_x(strsize);
+ tobufsize = strsize;
+ }
+ p = tobuf;
+ *p = '\0';
+ for (to = tochain; to != NULL; to = to->q_tchain)
+ {
+ (void) sm_strlcpyn(p, tobufsize - (p - tobuf), 2,
+ ",", to->q_paddr);
+ p += strlen(p);
}
-#endif /* _FFR_DYNAMIC_TOBUF */
e->e_to = tobuf + 1;
/*
** Fill out any parameters after the $u parameter.
*/
- while (!clever && *++mvp != NULL)
+ if (!clever)
{
- expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
- if (pvp >= &pv[MAXPV])
- syserr("554 5.3.0 deliver: pv overflow after $u for %s",
- pv[0]);
+ while (*++mvp != NULL)
+ {
+ expand(*mvp, buf, sizeof buf, e);
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
+ if (pvp >= &pv[MAXPV])
+ syserr("554 5.3.0 deliver: pv overflow after $u for %s",
+ pv[0]);
+ }
}
*pvp++ = NULL;
@@ -1515,14 +1796,11 @@ deliver(e, firstto)
if (tTd(11, 1))
{
- dprintf("openmailer:");
+ sm_dprintf("openmailer:");
printav(pv);
}
errno = 0;
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
-
CurHostName = NULL;
/*
@@ -1543,8 +1821,9 @@ deliver(e, firstto)
char wbuf[MAXLINE];
/* make absolutely certain 0, 1, and 2 are in use */
- snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ (void) sm_snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
checkfd012(wbuf);
}
#endif /* XDEBUG */
@@ -1559,7 +1838,7 @@ deliver(e, firstto)
{
e->e_status = "5.6.3";
usrerrenh(e->e_status,
- "554 Cannot send 8-bit data to 7-bit destination");
+ "554 Cannot send 8-bit data to 7-bit destination");
rcode = EX_DATAERR;
goto give_up;
}
@@ -1570,17 +1849,50 @@ deliver(e, firstto)
/* check for Local Person Communication -- not for mortals!!! */
if (strcmp(m->m_mailer, "[LPC]") == 0)
{
- mci = (MCI *) xalloc(sizeof *mci);
- memset((char *) mci, '\0', sizeof *mci);
- mci->mci_in = stdin;
- mci->mci_out = stdout;
+#if _FFR_CACHE_LPC
+ if (clever)
+ {
+ /* flush any expired connections */
+ (void) mci_scan(NULL);
+
+ /* try to get a cached connection or just a slot */
+ mci = mci_get(m->m_name, m);
+ if (mci->mci_host == NULL)
+ mci->mci_host = m->m_name;
+ CurHostName = mci->mci_host;
+ if (mci->mci_state != MCIS_CLOSED)
+ {
+ message("Using cached SMTP/LPC connection for %s...",
+ m->m_name);
+ mci->mci_deliveries++;
+ goto do_transfer;
+ }
+ }
+ else
+ {
+ mci = mci_new(e->e_rpool);
+ }
+ mci->mci_in = smioin;
+ mci->mci_out = smioout;
+ mci->mci_mailer = m;
+ mci->mci_host = m->m_name;
+ if (clever)
+ {
+ mci->mci_state = MCIS_OPENING;
+ mci_cache(mci);
+ }
+ else
+ mci->mci_state = MCIS_OPEN;
+#else /* _FFR_CACHE_LPC */
+ mci = mci_new(e->e_rpool);
+ mci->mci_in = smioin;
+ mci->mci_out = smioout;
mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
mci->mci_mailer = m;
+#endif /* _FFR_CACHE_LPC */
}
- else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0)
+ else if (strcmp(m->m_mailer, "[IPC]") == 0)
{
-#if DAEMON
register int i;
if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
@@ -1622,7 +1934,7 @@ deliver(e, firstto)
# endif /* NETUNIX */
)
{
- port = htons((u_short)atoi(pv[2]));
+ port = htons((unsigned short) atoi(pv[2]));
if (port == 0)
{
# ifdef NO_GETSERVBYNAME
@@ -1639,6 +1951,8 @@ deliver(e, firstto)
}
nummxhosts = parse_hostsignature(curhost, mxhosts, m);
+ if (TimeOuts.to_aconnect > 0)
+ enough = curtime() + TimeOuts.to_aconnect;
tryhost:
while (hostnum < nummxhosts)
{
@@ -1664,6 +1978,24 @@ tryhost:
*endp = '\0';
}
+ if (hostnum == 1 && skip_back != NULL)
+ {
+ /*
+ ** Coattail piggybacking is no longer an
+ ** option with the mail host next to be tried
+ ** no longer the lowest MX preference
+ ** (hostnum == 1 meaning we're on the second
+ ** preference). We do not try to coattail
+ ** piggyback more than the first MX preference.
+ ** Revert 'tochain' to last location for
+ ** coincidental piggybacking. This works this
+ ** easily because the q_tchain kept getting
+ ** added to the top of the linked list.
+ */
+
+ tochain = skip_back;
+ }
+
if (*mxhosts[hostnum] == '\0')
{
syserr("deliver: null host name in signature");
@@ -1672,8 +2004,8 @@ tryhost:
*endp = sep;
continue;
}
- (void) strlcpy(hostbuf, mxhosts[hostnum],
- sizeof hostbuf);
+ (void) sm_strlcpy(hostbuf, mxhosts[hostnum],
+ sizeof hostbuf);
hostnum++;
if (endp != NULL)
*endp = sep;
@@ -1683,15 +2015,22 @@ tryhost:
mci = mci_get(hostbuf, m);
if (mci->mci_state != MCIS_CLOSED)
{
+ char *type;
+
if (tTd(11, 1))
{
- dprintf("openmailer: ");
- mci_dump(mci, FALSE);
+ sm_dprintf("openmailer: ");
+ mci_dump(mci, false);
}
CurHostName = mci->mci_host;
- message("Using cached %sSMTP connection to %s via %s...",
- bitset(MCIF_ESMTP, mci->mci_flags) ? "E" : "",
- hostbuf, m->m_name);
+ if (bitnset(M_LMTP, m->m_flags))
+ type = "L";
+ else if (bitset(MCIF_ESMTP, mci->mci_flags))
+ type = "ES";
+ else
+ type = "S";
+ message("Using cached %sMTP connection to %s via %s...",
+ type, hostbuf, m->m_name);
mci->mci_deliveries++;
break;
}
@@ -1699,19 +2038,19 @@ tryhost:
if (mci->mci_exitstat != EX_OK)
{
if (mci->mci_exitstat == EX_TEMPFAIL)
- goodmxfound = TRUE;
+ goodmxfound = true;
continue;
}
if (mci_lock_host(mci) != EX_OK)
{
mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
- goodmxfound = TRUE;
+ goodmxfound = true;
continue;
}
/* try the connection */
- sm_setproctitle(TRUE, e, "%s %s: %s",
+ sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e),
hostbuf, "user open");
# if NETUNIX
@@ -1719,7 +2058,7 @@ tryhost:
{
message("Connecting to %s via %s...",
mux_path, m->m_name);
- i = makeconnection_ds(mux_path, mci);
+ i = makeconnection_ds((char *) mux_path, mci);
}
else
# endif /* NETUNIX */
@@ -1731,7 +2070,8 @@ tryhost:
message("Connecting to %s port %d via %s...",
hostbuf, ntohs(port),
m->m_name);
- i = makeconnection(hostbuf, port, mci, e);
+ i = makeconnection(hostbuf, port, mci, e,
+ enough);
}
mci->mci_errno = errno;
mci->mci_lastuse = curtime();
@@ -1740,23 +2080,55 @@ tryhost:
# if NAMED_BIND
mci->mci_herrno = h_errno;
# endif /* NAMED_BIND */
+
+ /*
+ ** Have we tried long enough to get a connection?
+ ** If yes, skip to the fallback MX hosts
+ ** (if existent).
+ */
+
+ if (enough > 0 && mci->mci_lastuse >= enough)
+ {
+ int h;
+# if NAMED_BIND
+ extern int NumFallBackMXHosts;
+# else /* NAMED_BIND */
+ const int NumFallBackMXHosts = 0;
+# endif /* NAMED_BIND */
+
+ if (hostnum < nummxhosts && LogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Timeout.to_aconnect occurred before exhausting all addresses");
+
+ /* turn off timeout if fallback available */
+ if (NumFallBackMXHosts > 0)
+ enough = 0;
+
+ /* skip to a fallback MX host */
+ h = nummxhosts - NumFallBackMXHosts;
+ if (hostnum < h)
+ hostnum = h;
+ }
if (i == EX_OK)
{
- goodmxfound = TRUE;
+ goodmxfound = true;
mci->mci_state = MCIS_OPENING;
mci_cache(mci);
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d === CONNECT %s\n",
- (int) getpid(), hostbuf);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d === CONNECT %s\n",
+ (int) CurrentPid,
+ hostbuf);
break;
}
else
{
if (tTd(11, 1))
- dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
- i, errno);
+ sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
+ i, errno);
if (i == EX_TEMPFAIL)
- goodmxfound = TRUE;
+ goodmxfound = true;
mci_unlock_host(mci);
}
@@ -1772,13 +2144,6 @@ tryhost:
goto give_up;
}
mci->mci_pid = 0;
-#else /* DAEMON */
- syserr("554 5.3.5 openmailer: no IPC");
- if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
- rcode = EX_UNAVAILABLE;
- goto give_up;
-#endif /* DAEMON */
}
else
{
@@ -1786,7 +2151,6 @@ tryhost:
(void) mci_scan(NULL);
mci = NULL;
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
/* try to get a cached connection */
@@ -1802,7 +2166,6 @@ tryhost:
goto do_transfer;
}
}
-#endif /* SMTP */
/* announce the connection to verbose listeners */
if (host == NULL || host[0] == '\0')
@@ -1813,10 +2176,14 @@ tryhost:
{
char **av;
- fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid());
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d === EXEC", (int) CurrentPid);
for (av = pv; *av != NULL; av++)
- fprintf(TrafficLogFile, " %s", *av);
- fprintf(TrafficLogFile, "\n");
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT, " %s",
+ *av);
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "\n");
}
#if XDEBUG
@@ -1827,9 +2194,9 @@ tryhost:
if (pipe(mpvect) < 0)
{
syserr("%s... openmailer(%s): pipe (to mailer)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1839,11 +2206,11 @@ tryhost:
if (mpvect[0] < 3 || mpvect[1] < 3)
{
syserr("%s... openmailer(%s): bogus mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
- mpvect[0], mpvect[1]);
- printopenfds(TRUE);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
+ mpvect[0], mpvect[1]);
+ printopenfds(true);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1853,18 +2220,21 @@ tryhost:
checkfdopen(mpvect[1], "mpvect[1]");
if (mpvect[0] == mpvect[1] ||
(e->e_lockfp != NULL &&
- (mpvect[0] == fileno(e->e_lockfp) ||
- mpvect[1] == fileno(e->e_lockfp))))
+ (mpvect[0] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL) ||
+ mpvect[1] == sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL))))
{
if (e->e_lockfp == NULL)
syserr("%s... openmailer(%s): overlapping mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0], mpvect[1]);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name, mpvect[0], mpvect[1]);
else
syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0], mpvect[1],
- fileno(e->e_lockfp));
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name, mpvect[0], mpvect[1],
+ sm_io_getinfo(e->e_lockfp,
+ SM_IO_WHAT_FD, NULL));
}
#endif /* XDEBUG */
@@ -1872,12 +2242,12 @@ tryhost:
if (pipe(rpvect) < 0)
{
syserr("%s... openmailer(%s): pipe (from mailer)",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
(void) close(mpvect[0]);
(void) close(mpvect[1]);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1894,10 +2264,10 @@ tryhost:
** around so that endmailer will get it.
*/
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
- (void) fflush(stdout);
- (void) setsignal(SIGCHLD, SIG_DFL);
+ if (e->e_xfp != NULL) /* for debugging */
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
DOFORK(FORK);
@@ -1907,13 +2277,13 @@ tryhost:
{
/* failure */
syserr("%s... openmailer(%s): cannot fork",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
(void) close(mpvect[0]);
(void) close(mpvect[1]);
(void) close(rpvect[0]);
(void) close(rpvect[1]);
if (tTd(11, 1))
- dprintf("openmailer: NULL\n");
+ sm_dprintf("openmailer: NULL\n");
rcode = EX_OSERR;
goto give_up;
}
@@ -1921,31 +2291,38 @@ tryhost:
{
int i;
int save_errno;
+ int sff;
int new_euid = NO_UID;
int new_ruid = NO_UID;
int new_gid = NO_GID;
+ char *user = NULL;
struct stat stb;
extern int DtableSize;
+ CurrentPid = getpid();
+
/* clear the events to turn off SIGALRMs */
- clear_events();
+ sm_clear_events();
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
+ (void) close(sm_io_getinfo(e->e_lockfp,
+ SM_IO_WHAT_FD,
+ NULL));
/* child -- set up input & exec mailer */
- (void) setsignal(SIGALRM, sm_signal_noop);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_IGN);
- (void) setsignal(SIGINT, SIG_IGN);
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGALRM, sm_signal_noop);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_IGN);
+ (void) sm_signal(SIGINT, SIG_IGN);
+ (void) sm_signal(SIGTERM, SIG_DFL);
# ifdef SIGUSR1
- (void) setsignal(SIGUSR1, sm_signal_noop);
+ (void) sm_signal(SIGUSR1, sm_signal_noop);
# endif /* SIGUSR1 */
if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
@@ -1966,14 +2343,16 @@ tryhost:
pwd = sm_getpwnam(contextaddr->q_user);
if (pwd != NULL)
(void) setusercontext(NULL,
- pwd, pwd->pw_uid,
- LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
+ pwd, pwd->pw_uid,
+ LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
}
# endif /* HASSETUSERCONTEXT */
+#if HASNICE
/* tweak niceness */
if (m->m_nice != 0)
(void) nice(m->m_nice);
+#endif /* HASNICE */
/* reset group id */
if (bitnset(M_SPECIFIC_UID, m->m_flags))
@@ -1984,15 +2363,16 @@ tryhost:
{
if (!DontInitGroups)
{
- char *u = ctladdr->q_ruser;
-
- if (u == NULL)
- u = ctladdr->q_user;
+ user = ctladdr->q_ruser;
+ if (user == NULL)
+ user = ctladdr->q_user;
- if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn)
+ if (initgroups(user,
+ ctladdr->q_gid) == -1
+ && suidwarn)
{
syserr("openmailer: initgroups(%s, %d) failed",
- u, ctladdr->q_gid);
+ user, ctladdr->q_gid);
exit(EX_TEMPFAIL);
}
}
@@ -2001,7 +2381,8 @@ tryhost:
GIDSET_T gidset[1];
gidset[0] = ctladdr->q_gid;
- if (setgroups(1, gidset) == -1 && suidwarn)
+ if (setgroups(1, gidset) == -1
+ && suidwarn)
{
syserr("openmailer: setgroups() failed");
exit(EX_TEMPFAIL);
@@ -2013,10 +2394,12 @@ tryhost:
{
if (!DontInitGroups)
{
- if (initgroups(DefUser, DefGid) == -1 && suidwarn)
+ user = DefUser;
+ if (initgroups(DefUser, DefGid) == -1 &&
+ suidwarn)
{
syserr("openmailer: initgroups(%s, %d) failed",
- DefUser, DefGid);
+ DefUser, DefGid);
exit(EX_TEMPFAIL);
}
}
@@ -2025,7 +2408,8 @@ tryhost:
GIDSET_T gidset[1];
gidset[0] = DefGid;
- if (setgroups(1, gidset) == -1 && suidwarn)
+ if (setgroups(1, gidset) == -1
+ && suidwarn)
{
syserr("openmailer: setgroups() failed");
exit(EX_TEMPFAIL);
@@ -2044,7 +2428,9 @@ tryhost:
new_gid != getegid())
{
/* Only root can change the gid */
- syserr("openmailer: insufficient privileges to change gid");
+ syserr("openmailer: insufficient privileges to change gid, RunAsUid=%d, new_gid=%d, gid=%d, egid=%d",
+ (int) RunAsUid, (int) new_gid,
+ (int) getgid(), (int) getegid());
exit(EX_TEMPFAIL);
}
@@ -2061,12 +2447,12 @@ tryhost:
{
expand(m->m_rootdir, buf, sizeof buf, e);
if (tTd(11, 20))
- dprintf("openmailer: chroot %s\n",
- buf);
+ sm_dprintf("openmailer: chroot %s\n",
+ buf);
if (chroot(buf) < 0)
{
syserr("openmailer: Cannot chroot(%s)",
- buf);
+ buf);
exit(EX_TEMPFAIL);
}
if (chdir("/") < 0)
@@ -2078,6 +2464,7 @@ tryhost:
/* reset user id */
endpwent();
+ sm_mbdb_terminate();
if (bitnset(M_SPECIFIC_UID, m->m_flags))
{
new_euid = m->m_uid;
@@ -2090,7 +2477,21 @@ tryhost:
*/
if (RealUid != 0 && RealUid != getuid())
+ {
+# if MAILER_SETUID_METHOD == USE_SETEUID
+# if HASSETREUID
+ if (setreuid(RealUid, geteuid()) < 0)
+ {
+ syserr("openmailer: setreuid(%d, %d) failed",
+ (int) RealUid, (int) geteuid());
+ exit(EX_OSERR);
+ }
+# endif /* HASSETREUID */
+# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
+# if MAILER_SETUID_METHOD == USE_SETREUID
new_ruid = RealUid;
+# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
+ }
}
else if (bitset(S_ISUID, stb.st_mode))
new_ruid = stb.st_uid;
@@ -2105,32 +2506,17 @@ tryhost:
if (RunAsUid != 0 && new_euid != RunAsUid)
{
/* Only root can change the uid */
- syserr("openmailer: insufficient privileges to change uid");
+ syserr("openmailer: insufficient privileges to change uid, new_euid=%d, RunAsUid=%d",
+ (int) new_euid, (int) RunAsUid);
exit(EX_TEMPFAIL);
}
vendor_set_uid(new_euid);
# if MAILER_SETUID_METHOD == USE_SETEUID
-# if HASSETREUID
- /*
- ** Undo the effects of the uid change in main
- ** for signal handling. The real uid may
- ** be used by mailer in adding a "From "
- ** line.
- */
-
- if (new_ruid != NO_UID &&
- setreuid(RealUid, geteuid()) < 0)
- {
- syserr("openmailer: setreuid(%d, %d) failed",
- (int) new_ruid, (int) geteuid());
- exit(EX_OSERR);
- }
-# endif /* HASSETREUID */
if (seteuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: seteuid(%ld) failed",
- (long) new_euid);
+ (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETEUID */
@@ -2138,7 +2524,7 @@ tryhost:
if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
{
syserr("openmailer: setreuid(%ld, %ld) failed",
- (long) new_ruid, (long) new_euid);
+ (long) new_ruid, (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETREUID */
@@ -2146,7 +2532,7 @@ tryhost:
if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
{
syserr("openmailer: setuid(%ld) failed",
- (long) new_euid);
+ (long) new_euid);
exit(EX_TEMPFAIL);
}
# endif /* MAILER_SETUID_METHOD == USE_SETUID */
@@ -2157,15 +2543,15 @@ tryhost:
if (setuid(new_ruid) < 0 && suidwarn)
{
syserr("openmailer: setuid(%ld) failed",
- (long) new_ruid);
+ (long) new_ruid);
exit(EX_TEMPFAIL);
}
}
if (tTd(11, 2))
- dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n",
- (int) getuid(), (int) geteuid(),
- (int) getgid(), (int) getegid());
+ sm_dprintf("openmailer: running as r/euid=%d/%d, r/egid=%d/%d\n",
+ (int) getuid(), (int) geteuid(),
+ (int) getgid(), (int) getegid());
/* move into some "safe" directory */
if (m->m_execdir != NULL)
@@ -2181,13 +2567,30 @@ tryhost:
if (q != NULL)
*q++ = ':';
if (tTd(11, 20))
- dprintf("openmailer: trydir %s\n",
- buf);
+ sm_dprintf("openmailer: trydir %s\n",
+ buf);
if (buf[0] != '\0' && chdir(buf) >= 0)
break;
}
}
+ /* Check safety of program to be run */
+ sff = SFF_ROOTOK|SFF_EXECOK;
+ if (!bitnset(DBS_RUNWRITABLEPROGRAM,
+ DontBlameSendmail))
+ sff |= SFF_NOGWFILES|SFF_NOWWFILES;
+ if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH,
+ DontBlameSendmail))
+ sff |= SFF_NOPATHCHECK;
+ else
+ sff |= SFF_SAFEDIRPATH;
+ ret = safefile(m->m_mailer, getuid(), getgid(),
+ user, sff, 0, NULL);
+ if (ret != 0)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Warning: program %s unsafe: %s",
+ m->m_mailer, sm_errstring(ret));
+
/* arrange to filter std & diag output of command */
(void) close(rpvect[0]);
if (dup2(rpvect[1], STDOUT_FILENO) < 0)
@@ -2202,8 +2605,8 @@ tryhost:
if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
{
syserr("%s... openmailer(%s): cannot dup stdout for stderr",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name);
_exit(EX_OSERR);
}
@@ -2212,8 +2615,8 @@ tryhost:
if (dup2(mpvect[0], STDIN_FILENO) < 0)
{
syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0]);
+ shortenstring(e->e_to, MAXSHORTSTR),
+ m->m_name, mpvect[0]);
_exit(EX_OSERR);
}
(void) close(mpvect[0]);
@@ -2248,8 +2651,25 @@ tryhost:
if (mci == NULL)
{
- mci = (MCI *) xalloc(sizeof *mci);
- memset((char *) mci, '\0', sizeof *mci);
+ if (clever)
+ {
+ /*
+ ** Allocate from general heap, not
+ ** envelope rpool, because this mci
+ ** is going to be cached.
+ */
+
+ mci = mci_new(NULL);
+ }
+ else
+ {
+ /*
+ ** Prevent a storage leak by allocating
+ ** this from the envelope rpool.
+ */
+
+ mci = mci_new(e->e_rpool);
+ }
}
mci->mci_mailer = m;
if (clever)
@@ -2263,11 +2683,13 @@ tryhost:
}
mci->mci_pid = pid;
(void) close(mpvect[0]);
- mci->mci_out = fdopen(mpvect[1], "w");
+ mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &(mpvect[1]), SM_IO_WRONLY,
+ NULL);
if (mci->mci_out == NULL)
{
syserr("deliver: cannot create mailer output channel, fd=%d",
- mpvect[1]);
+ mpvect[1]);
(void) close(mpvect[1]);
(void) close(rpvect[0]);
(void) close(rpvect[1]);
@@ -2276,21 +2698,19 @@ tryhost:
}
(void) close(rpvect[1]);
- mci->mci_in = fdopen(rpvect[0], "r");
+ mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &(rpvect[0]), SM_IO_RDONLY,
+ NULL);
if (mci->mci_in == NULL)
{
syserr("deliver: cannot create mailer input channel, fd=%d",
mpvect[1]);
(void) close(rpvect[0]);
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
mci->mci_out = NULL;
rcode = EX_OSERR;
goto give_up;
}
-
- /* Don't cache non-clever connections */
- if (!clever)
- mci->mci_flags |= MCIF_TEMP;
}
/*
@@ -2300,12 +2720,17 @@ tryhost:
if (bitnset(M_7BITS, m->m_flags) &&
(!clever || mci->mci_state == MCIS_OPENING))
mci->mci_flags |= MCIF_7BIT;
-#if SMTP
if (clever && mci->mci_state != MCIS_CLOSED)
{
-# if SASL && SFIO
+# if STARTTLS || SASL
+ int dotpos;
+ char *srvname;
+ extern SOCKADDR CurHostAddr;
+# endif /* STARTTLS || SASL */
+
+# if SASL
# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
-# endif /* SASL && SFIO */
+# endif /* SASL */
# if STARTTLS
# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
# endif /* STARTTLS */
@@ -2313,97 +2738,130 @@ tryhost:
# define SET_HELO(f) f |= MCIF_ONLY_EHLO
# define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
+# if STARTTLS || SASL
+ /* don't use CurHostName, it is changed in many places */
+ if (mci->mci_host != NULL)
+ {
+ srvname = mci->mci_host;
+ dotpos = strlen(srvname) - 1;
+ if (dotpos >= 0)
+ {
+ if (srvname[dotpos] == '.')
+ srvname[dotpos] = '\0';
+ else
+ dotpos = -1;
+ }
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ srvname = mci->mci_mailer->m_name;
+ dotpos = -1;
+ }
+ else
+ {
+ srvname = "local";
+ dotpos = -1;
+ }
+
+ /* don't set {server_name} to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
+ srvname);
+
+ /* CurHostAddr is set by makeconnection() and mci_get() */
+ if (CurHostAddr.sa.sa_family != 0)
+ {
+ macdefine(&mci->mci_macro, A_TEMP,
+ macid("{server_addr}"),
+ anynet_ntoa(&CurHostAddr));
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ /* mailer name is unique, use it as address */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"),
+ mci->mci_mailer->m_name);
+ }
+ else
+ {
+ /* don't set it to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"), "0");
+ }
-# if STARTTLS || (SASL && SFIO)
-reconnect: /* after switching to an authenticated connection */
-# endif /* STARTTLS || (SASL && SFIO) */
+ /* undo change of srvname (mci->mci_host) */
+ if (dotpos >= 0)
+ srvname[dotpos] = '.';
+reconnect: /* after switching to an encrypted connection */
+# endif /* STARTTLS || SASL */
+
+ /* set the current connection information */
+ e->e_mci = mci;
# if SASL
mci->mci_saslcap = NULL;
# endif /* SASL */
smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
CLR_HELO(mci->mci_flags);
+ if (IS_DLVR_RETURN(e))
+ {
+ /*
+ ** Check whether other side can deliver e-mail
+ ** fast enough
+ */
+
+ if (!bitset(MCIF_DLVR_BY, mci->mci_flags))
+ {
+ e->e_status = "5.4.7";
+ usrerrenh(e->e_status,
+ "554 Server does not support Deliver By");
+ rcode = EX_UNAVAILABLE;
+ goto give_up;
+ }
+ if (e->e_deliver_by > 0 &&
+ e->e_deliver_by - (curtime() - e->e_ctime) <
+ mci->mci_min_by)
+ {
+ e->e_status = "5.4.7";
+ usrerrenh(e->e_status,
+ "554 Message can't be delivered in time; %ld < %ld",
+ e->e_deliver_by - (curtime() - e->e_ctime),
+ mci->mci_min_by);
+ rcode = EX_UNAVAILABLE;
+ goto give_up;
+ }
+ }
+
# if STARTTLS
/* first TLS then AUTH to provide a security layer */
if (mci->mci_state != MCIS_CLOSED &&
!DONE_STARTTLS(mci->mci_flags))
{
int olderrors;
- int dotpos;
bool usetls;
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
char *host = NULL;
-# if _FFR_TLS_CLT1
- char *p;
-# endif /* _FFR_TLS_CLT1 */
- char *srvname;
- extern SOCKADDR CurHostAddr;
rcode = EX_OK;
usetls = bitset(MCIF_TLS, mci->mci_flags);
-# if _FFR_TLS_CLT1
- if (usetls &&
- (p = macvalue(macid("{client_flags}", NULL), e))
- != NULL)
- {
- for (; *p != '\0'; p++)
- {
- /* look for just this one flag */
- if (*p == D_CLTNOTLS)
- {
- usetls = FALSE;
- break;
- }
- }
- }
-# endif /* _FFR_TLS_CLT1 */
+ if (usetls)
+ usetls = !iscltflgset(e, D_NOTLS);
- if (mci->mci_host != NULL)
- {
- srvname = mci->mci_host;
- dotpos = strlen(srvname) - 1;
- if (dotpos >= 0)
- {
- if (srvname[dotpos] == '.')
- srvname[dotpos] = '\0';
- else
- dotpos = -1;
- }
- }
- else
- {
- srvname = "";
- dotpos = -1;
- }
- define(macid("{server_name}", NULL),
- newstr(srvname), e);
- if (CurHostAddr.sa.sa_family != 0)
- define(macid("{server_addr}", NULL),
- newstr(anynet_ntoa(&CurHostAddr)), e);
- else
- define(macid("{server_addr}", NULL), NULL, e);
if (usetls)
{
- host = macvalue(macid("{server_name}", NULL),
- e);
-# if _FFR_TLS_O_T
+ host = macvalue(macid("{server_name}"), e);
olderrors = Errors;
- QuickAbort = FALSE;
- SuprErrs = TRUE;
- if (rscheck("try_tls", srvname, NULL,
- e, TRUE, FALSE, 8, host) != EX_OK
+ QuickAbort = false;
+ SuprErrs = true;
+ if (rscheck("try_tls", host, NULL, e, true,
+ false, 7, host, NOQID) != EX_OK
|| Errors > olderrors)
- usetls = FALSE;
+ usetls = false;
SuprErrs = saveSuprErrs;
QuickAbort = saveQuickAbort;
-# endif /* _FFR_TLS_O_T */
}
- /* undo change of srvname */
- if (dotpos >= 0)
- srvname[dotpos] = '.';
if (usetls)
{
if ((rcode = starttls(m, mci, e)) == EX_OK)
@@ -2421,6 +2879,7 @@ reconnect: /* after switching to an authenticated connection */
** or abort? How to decide?
** set a macro and call a ruleset.
*/
+
mci->mci_flags &= ~MCIF_TLS;
switch (rcode)
{
@@ -2442,21 +2901,16 @@ reconnect: /* after switching to an authenticated connection */
s = "FAILURE";
rcode = EX_TEMPFAIL;
}
- define(macid("{verify}", NULL),
- newstr(s), e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{verify}"), s);
}
}
- else if (mci->mci_ssl != NULL)
- {
- /* active TLS connection, use that data */
- (void) tls_get_info(mci->mci_ssl, e, FALSE,
- mci->mci_host, FALSE);
- }
else
- define(macid("{verify}", NULL), "NONE", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{verify}"), "NONE");
olderrors = Errors;
- QuickAbort = FALSE;
- SuprErrs = TRUE;
+ QuickAbort = false;
+ SuprErrs = true;
/*
** rcode == EX_SOFTWARE is special:
@@ -2466,9 +2920,11 @@ reconnect: /* after switching to an authenticated connection */
** to log the problem and return an appropriate
** error code.
*/
+
if (rscheck("tls_server",
- macvalue(macid("{verify}", NULL), e),
- NULL, e, TRUE, TRUE, 6, host) != EX_OK ||
+ macvalue(macid("{verify}"), e),
+ NULL, e, true, true, 5, host,
+ NOQID) != EX_OK ||
Errors > olderrors ||
rcode == EX_SOFTWARE)
{
@@ -2478,13 +2934,14 @@ reconnect: /* after switching to an authenticated connection */
if (ISSMTPCODE(MsgBuf) &&
extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
{
- p = newstr(MsgBuf);
+ p = sm_rpool_strdup_x(e->e_rpool,
+ MsgBuf);
}
else
{
p = "403 4.7.0 server not authenticated.";
- (void) strlcpy(enhsc, "4.7.0",
- sizeof enhsc);
+ (void) sm_strlcpy(enhsc, "4.7.0",
+ sizeof enhsc);
}
SuprErrs = saveSuprErrs;
QuickAbort = saveQuickAbort;
@@ -2495,7 +2952,8 @@ reconnect: /* after switching to an authenticated connection */
mci->mci_state = MCIS_QUITING;
if (mci->mci_in != NULL)
{
- (void) fclose(mci->mci_in);
+ (void) sm_io_close(mci->mci_in,
+ SM_TIME_DEFAULT);
mci->mci_in = NULL;
}
mci->mci_flags &= ~MCIF_TLSACT;
@@ -2513,13 +2971,15 @@ reconnect: /* after switching to an authenticated connection */
/* temp or permanent failure? */
rcode = (*p == '4') ? EX_TEMPFAIL
: EX_UNAVAILABLE;
- mci_setstat(mci, rcode, newstr(enhsc), p);
+ mci_setstat(mci, rcode, enhsc, p);
/*
** hack to get the error message into
** the envelope (done in giveresponse())
*/
- (void) strlcpy(SmtpError, p, sizeof SmtpError);
+
+ (void) sm_strlcpy(SmtpError, p,
+ sizeof SmtpError);
}
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
@@ -2531,79 +2991,85 @@ reconnect: /* after switching to an authenticated connection */
goto reconnect;
}
}
- else if (mci->mci_ssl != NULL)
- {
- /* active TLS connection, use that data */
- (void) tls_get_info(mci->mci_ssl, e, FALSE,
- mci->mci_host, FALSE);
- }
# endif /* STARTTLS */
# if SASL
/* if other server supports authentication let's authenticate */
if (mci->mci_state != MCIS_CLOSED &&
mci->mci_saslcap != NULL &&
-# if SFIO
- !DONE_AUTH(mci->mci_flags) &&
-# endif /* SFIO */
- SASLInfo != NULL)
+ !DONE_AUTH(mci->mci_flags) && !iscltflgset(e, D_NOAUTH))
{
- /*
- ** should we require some minimum authentication?
- ** XXX ignore result?
- */
- if (smtpauth(m, mci, e) == EX_OK)
+ /* Should we require some minimum authentication? */
+ if ((ret = smtpauth(m, mci, e)) == EX_OK)
{
-# if SFIO
int result;
- sasl_ssf_t *ssf;
+ sasl_ssf_t *ssf = NULL;
- /* get security strength (features) */
+ /* Get security strength (features) */
result = sasl_getprop(mci->mci_conn, SASL_SSF,
(void **) &ssf);
+
+ /* XXX authid? */
if (LogLevel > 9)
sm_syslog(LOG_INFO, NOQID,
- "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d",
+ "AUTH=client, relay=%.100s, mech=%.16s, bits=%d",
mci->mci_host,
- macvalue(macid("{auth_type}",
- NULL), e),
- result == SASL_OK ? *ssf
- : 0);
+ macvalue(macid("{auth_type}"), e),
+ result == SASL_OK ? *ssf : 0);
/*
- ** only switch to encrypted connection
+ ** Only switch to encrypted connection
** if a security layer has been negotiated
*/
+
if (result == SASL_OK && *ssf > 0)
{
/*
- ** convert sfio stuff to use SASL
- ** check return values
- ** if the call fails,
- ** fall back to unencrypted version
- ** unless some cf option requires
- ** encryption then the connection must
- ** be aborted
+ ** Convert I/O layer to use SASL.
+ ** If the call fails, the connection
+ ** is aborted.
*/
- if (sfdcsasl(mci->mci_in, mci->mci_out,
+
+ if (sfdcsasl(&mci->mci_in,
+ &mci->mci_out,
mci->mci_conn) == 0)
{
- SET_HELO(mci->mci_flags);
mci->mci_flags &= ~MCIF_EXTENS;
- mci->mci_flags |= MCIF_AUTHACT;
+ mci->mci_flags |= MCIF_AUTHACT|
+ MCIF_ONLY_EHLO;
goto reconnect;
}
- syserr("SASL TLS switch failed in client");
+ syserr("AUTH TLS switch failed in client");
}
/* else? XXX */
-# endif /* SFIO */
mci->mci_flags |= MCIF_AUTHACT;
}
+ else if (ret == EX_TEMPFAIL)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_ERR, NOQID,
+ "AUTH=client, relay=%.100s, temporary failure, connection abort",
+ mci->mci_host);
+ smtpquit(m, mci, e);
+
+ /* avoid bogus error msg */
+ mci->mci_errno = 0;
+ rcode = EX_TEMPFAIL;
+ mci_setstat(mci, rcode, "4.7.1", p);
+
+ /*
+ ** hack to get the error message into
+ ** the envelope (done in giveresponse())
+ */
+
+ (void) sm_strlcpy(SmtpError,
+ "Temporary AUTH failure",
+ sizeof SmtpError);
+ }
}
# endif /* SASL */
}
-#endif /* SMTP */
do_transfer:
/* clear out per-message flags from connection structure */
@@ -2618,13 +3084,13 @@ do_transfer:
if (bitnset(M_MAKE8BIT, m->m_flags) &&
!bitset(MCIF_7BIT, mci->mci_flags) &&
(p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
- (strcasecmp(p, "quoted-printable") == 0 ||
- strcasecmp(p, "base64") == 0) &&
+ (sm_strcasecmp(p, "quoted-printable") == 0 ||
+ sm_strcasecmp(p, "base64") == 0) &&
(p = hvalue("Content-Type", e->e_header)) != NULL)
{
/* may want to convert 7 -> 8 */
/* XXX should really parse it here -- and use a class XXX */
- if (strncasecmp(p, "text/plain", 10) == 0 &&
+ if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
(p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
mci->mci_flags |= MCIF_CVT7TO8;
}
@@ -2632,34 +3098,61 @@ do_transfer:
if (tTd(11, 1))
{
- dprintf("openmailer: ");
- mci_dump(mci, FALSE);
+ sm_dprintf("openmailer: ");
+ mci_dump(mci, false);
}
+#if _FFR_CLIENT_SIZE
+ /*
+ ** See if we know the maximum size and
+ ** abort if the message is too big.
+ **
+ ** NOTE: _FFR_CLIENT_SIZE is untested.
+ */
+
+ if (bitset(MCIF_SIZE, mci->mci_flags) &&
+ mci->mci_maxsize > 0 &&
+ e->e_msgsize > mci->mci_maxsize)
+ {
+ e->e_flags |= EF_NO_BODY_RETN;
+ if (bitnset(M_LOCALMAILER, m->m_flags))
+ e->e_status = "5.2.3";
+ else
+ e->e_status = "5.3.4";
+
+ usrerrenh(e->e_status,
+ "552 Message is too large; %ld bytes max",
+ mci->mci_maxsize);
+ rcode = EX_DATAERR;
+
+ /* Need an e_message for error */
+ (void) sm_snprintf(SmtpError, sizeof SmtpError,
+ "Message is too large; %ld bytes max",
+ mci->mci_maxsize);
+ goto give_up;
+ }
+#endif /* _FFR_CLIENT_SIZE */
+
if (mci->mci_state != MCIS_OPEN)
{
/* couldn't open the mailer */
rcode = mci->mci_exitstat;
errno = mci->mci_errno;
-#if NAMED_BIND
SM_SET_H_ERRNO(mci->mci_herrno);
-#endif /* NAMED_BIND */
if (rcode == EX_OK)
{
/* shouldn't happen */
syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
- (u_long) mci, rcode, errno, mci->mci_state,
- firstsig);
- mci_dump_all(TRUE);
+ (unsigned long) mci, rcode, errno,
+ mci->mci_state, firstsig);
+ mci_dump_all(true);
rcode = EX_SOFTWARE;
}
-#if DAEMON
else if (nummxhosts > hostnum)
{
/* try next MX site */
goto tryhost;
}
-#endif /* DAEMON */
}
else if (!clever)
{
@@ -2673,80 +3166,106 @@ do_transfer:
/* get the exit status */
rcode = endmailer(mci, e, pv);
- if (rcode == EX_TEMPFAIL &&
- SmtpError[0] == '\0')
+ if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
{
/*
** Need an e_message for mailq display.
** We set SmtpError as
*/
- snprintf(SmtpError, sizeof SmtpError,
- "%s mailer (%s) exited with EX_TEMPFAIL",
- m->m_name, m->m_mailer);
+ (void) sm_snprintf(SmtpError, sizeof SmtpError,
+ "%s mailer (%s) exited with EX_TEMPFAIL",
+ m->m_name, m->m_mailer);
}
}
else
-#if SMTP
{
/*
** Send the MAIL FROM: protocol
*/
+ /* XXX this isn't pipelined... */
rcode = smtpmailfrom(m, mci, e);
if (rcode == EX_OK)
{
- register char *t = tobuf;
register int i;
+# if PIPELINING
+ ADDRESS *volatile pchain;
+# endif /* PIPELINING */
/* send the recipient list */
tobuf[0] = '\0';
+ mci->mci_retryrcpt = false;
+ mci->mci_tolist = tobuf;
+# if PIPELINING
+ pchain = NULL;
+ mci->mci_nextaddr = NULL;
+# endif /* PIPELINING */
for (to = tochain; to != NULL; to = to->q_tchain)
{
- e->e_to = to->q_paddr;
-#if !_FFR_DYNAMIC_TOBUF
- if (strlen(to->q_paddr) +
- (t - tobuf) + 2 > sizeof tobuf)
- {
- /* not enough room */
+ if (!QS_IS_UNMARKED(to->q_state))
continue;
- }
-#endif /* !_FFR_DYNAMIC_TOBUF */
+ /* mark recipient state as "ok so far" */
+ to->q_state = QS_OK;
+ e->e_to = to->q_paddr;
# if STARTTLS
-# if _FFR_TLS_RCPT
i = rscheck("tls_rcpt", to->q_user, NULL, e,
- TRUE, TRUE, 4, mci->mci_host);
+ true, true, 3, mci->mci_host,
+ e->e_id);
if (i != EX_OK)
{
- /* avoid bogus error msg */
- errno = 0;
- markfailure(e, to, mci, i, FALSE);
- giveresponse(i, to->q_status, m,
- mci, ctladdr, xstart, e);
+ markfailure(e, to, mci, i, false);
+ giveresponse(i, to->q_status, m, mci,
+ ctladdr, xstart, e, to);
+ if (i == EX_TEMPFAIL)
+ {
+ mci->mci_retryrcpt = true;
+ to->q_state = QS_RETRY;
+ }
continue;
}
-# endif /* _FFR_TLS_RCPT */
# endif /* STARTTLS */
- if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
+ i = smtprcpt(to, m, mci, e, ctladdr, xstart);
+# if PIPELINING
+ if (i == EX_OK &&
+ bitset(MCIF_PIPELINED, mci->mci_flags))
{
- markfailure(e, to, mci, i, FALSE);
- giveresponse(i, to->q_status, m,
- mci, ctladdr, xstart, e);
+ /*
+ ** Add new element to list of
+ ** recipients for pipelining.
+ */
+
+ to->q_pchain = NULL;
+ if (mci->mci_nextaddr == NULL)
+ mci->mci_nextaddr = to;
+ if (pchain == NULL)
+ pchain = to;
+ else
+ {
+ pchain->q_pchain = to;
+ pchain = pchain->q_pchain;
+ }
}
- else
+# endif /* PIPELINING */
+ if (i != EX_OK)
{
- *t++ = ',';
- for (p = to->q_paddr; *p; *t++ = *p++)
- continue;
- *t = '\0';
+ markfailure(e, to, mci, i, false);
+ giveresponse(i, to->q_status, m, mci,
+ ctladdr, xstart, e, to);
+ if (i == EX_TEMPFAIL)
+ to->q_state = QS_RETRY;
}
}
- /* now send the data */
- if (tobuf[0] == '\0')
+ /* No recipients in list and no missing responses? */
+ if (tobuf[0] == '\0'
+# if PIPELINING
+ && mci->mci_nextaddr == NULL
+# endif /* PIPELINING */
+ )
{
rcode = EX_OK;
e->e_to = NULL;
@@ -2756,24 +3275,15 @@ do_transfer:
else
{
e->e_to = tobuf + 1;
- rcode = smtpdata(m, mci, e);
+ rcode = smtpdata(m, mci, e, ctladdr, xstart);
}
}
-# if DAEMON
if (rcode == EX_TEMPFAIL && nummxhosts > hostnum)
{
/* try next MX site */
goto tryhost;
}
-# endif /* DAEMON */
- }
-#else /* SMTP */
- {
- syserr("554 5.3.5 deliver: need SMTP compiled to use clever mailer");
- rcode = EX_CONFIG;
- goto give_up;
}
-#endif /* SMTP */
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
@@ -2790,15 +3300,14 @@ do_transfer:
*/
give_up:
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
lmtp_rcode = rcode;
tobuf[0] = '\0';
- anyok = FALSE;
+ anyok = false;
+ strsize = 0;
}
else
-#endif /* SMTP */
anyok = rcode == EX_OK;
for (to = tochain; to != NULL; to = to->q_tchain)
@@ -2807,7 +3316,6 @@ do_transfer:
if (!QS_IS_OK(to->q_state))
continue;
-#if SMTP
/* if running LMTP, get the status for each address */
if (bitnset(M_LMTP, m->m_flags))
{
@@ -2815,44 +3323,30 @@ do_transfer:
rcode = smtpgetstat(m, mci, e);
if (rcode == EX_OK)
{
-#if _FFR_DYNAMIC_TOBUF
- (void) strlcat(tobuf, ",", tobufsize);
- (void) strlcat(tobuf, to->q_paddr, tobufsize);
-#else /* _FFR_DYNAMIC_TOBUF */
- if (strlen(to->q_paddr) +
- strlen(tobuf) + 2 > sizeof tobuf)
- {
- syserr("LMTP tobuf overflow");
- }
- else
- {
- (void) strlcat(tobuf, ",",
- sizeof tobuf);
- (void) strlcat(tobuf, to->q_paddr,
- sizeof tobuf);
- }
-#endif /* _FFR_DYNAMIC_TOBUF */
- anyok = TRUE;
+ strsize += sm_strlcat2(tobuf + strsize, ",",
+ to->q_paddr,
+ tobufsize - strsize);
+ SM_ASSERT(strsize < tobufsize);
+ anyok = true;
}
else
{
e->e_to = to->q_paddr;
- markfailure(e, to, mci, rcode, TRUE);
+ markfailure(e, to, mci, rcode, true);
giveresponse(rcode, to->q_status, m, mci,
- ctladdr, xstart, e);
+ ctladdr, xstart, e, to);
e->e_to = tobuf + 1;
continue;
}
}
else
-#endif /* SMTP */
{
/* mark bad addresses */
if (rcode != EX_OK)
{
if (goodmxfound && rcode == EX_NOHOST)
rcode = EX_TEMPFAIL;
- markfailure(e, to, mci, rcode, TRUE);
+ markfailure(e, to, mci, rcode, true);
continue;
}
}
@@ -2862,37 +3356,63 @@ do_transfer:
to->q_statdate = curtime();
e->e_nsent++;
-#if QUEUE
/*
** Checkpoint the send list every few addresses
*/
if (CheckpointInterval > 0 && e->e_nsent >= CheckpointInterval)
{
- queueup(e, FALSE);
+ queueup(e, false, false);
e->e_nsent = 0;
}
-#endif /* QUEUE */
if (bitnset(M_LOCALMAILER, m->m_flags) &&
bitset(QPINGONSUCCESS, to->q_flags))
{
to->q_flags |= QDELIVERED;
to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Successfully delivered\n",
+ to->q_paddr);
}
else if (bitset(QPINGONSUCCESS, to->q_flags) &&
bitset(QPRIMARY, to->q_flags) &&
!bitset(MCIF_DSN, mci->mci_flags))
{
to->q_flags |= QRELAYED;
- fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
- to->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... relayed; expect no further notifications\n",
+ to->q_paddr);
+ }
+ else if (IS_DLVR_NOTIFY(e) &&
+ !bitset(MCIF_DLVR_BY, mci->mci_flags) &&
+ bitset(QPRIMARY, to->q_flags) &&
+ (!bitset(QHASNOTIFY, to->q_flags) ||
+ bitset(QPINGONSUCCESS, to->q_flags) ||
+ bitset(QPINGONFAILURE, to->q_flags) ||
+ bitset(QPINGONDELAY, to->q_flags)))
+ {
+ /* RFC 2852, 4.1.4.2: no NOTIFY, or not NEVER */
+ to->q_flags |= QBYNRELAY;
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Deliver-by notify: relayed\n",
+ to->q_paddr);
+ }
+ else if (IS_DLVR_TRACE(e) &&
+ (!bitset(QHASNOTIFY, to->q_flags) ||
+ bitset(QPINGONSUCCESS, to->q_flags) ||
+ bitset(QPINGONFAILURE, to->q_flags) ||
+ bitset(QPINGONDELAY, to->q_flags)) &&
+ bitset(QPRIMARY, to->q_flags))
+ {
+ /* RFC 2852, 4.1.4: no NOTIFY, or not NEVER */
+ to->q_flags |= QBYTRACE;
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... Deliver-By trace: relayed\n",
+ to->q_paddr);
}
}
-#if SMTP
if (bitnset(M_LMTP, m->m_flags))
{
/*
@@ -2904,48 +3424,90 @@ do_transfer:
e->e_statmsg = NULL;
/* reset the mci state for the next transaction */
- if (mci != NULL && mci->mci_state == MCIS_ACTIVE)
+ if (mci != NULL &&
+ (mci->mci_state == MCIS_MAIL ||
+ mci->mci_state == MCIS_RCPT ||
+ mci->mci_state == MCIS_DATA))
mci->mci_state = MCIS_OPEN;
}
-#endif /* SMTP */
if (tobuf[0] != '\0')
- giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e);
+ {
+ giveresponse(rcode, NULL, m, mci, ctladdr, xstart, e, tochain);
+#if 0
+ /*
+ ** This code is disabled for now because I am not
+ ** sure that copying status from the first recipient
+ ** to all non-status'ed recipients is a good idea.
+ */
+
+ if (tochain->q_message != NULL &&
+ !bitnset(M_LMTP, m->m_flags) && rcode != EX_OK)
+ {
+ for (to = tochain->q_tchain; to != NULL;
+ to = to->q_tchain)
+ {
+ /* see if address already marked */
+ if (QS_IS_QUEUEUP(to->q_state) &&
+ to->q_message == NULL)
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ tochain->q_message);
+ }
+ }
+#endif /* 0 */
+ }
if (anyok)
- markstats(e, tochain, FALSE);
+ markstats(e, tochain, STATS_NORMAL);
mci_store_persistent(mci);
-#if SMTP
+ /* Some recipients were tempfailed, try them on the next host */
+ if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
+ {
+ /* try next MX site */
+ goto tryhost;
+ }
+
/* now close the connection */
if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
!bitset(MCIF_CACHED, mci->mci_flags))
smtpquit(m, mci, e);
-#endif /* SMTP */
-
- /*
- ** Restore state and return.
- */
-#if XDEBUG
+cleanup: ;
+ }
+ SM_FINALLY
{
+ /*
+ ** Restore state and return.
+ */
+#if XDEBUG
char wbuf[MAXLINE];
/* make absolutely certain 0, 1, and 2 are in use */
- snprintf(wbuf, sizeof wbuf, "%s... end of deliver(%s)",
- e->e_to == NULL ? "NO-TO-LIST"
- : shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
+ (void) sm_snprintf(wbuf, sizeof wbuf,
+ "%s... end of deliver(%s)",
+ e->e_to == NULL ? "NO-TO-LIST"
+ : shortenstring(e->e_to,
+ MAXSHORTSTR),
+ m->m_name);
checkfd012(wbuf);
- }
#endif /* XDEBUG */
- errno = 0;
- define('g', (char *) NULL, e);
- e->e_to = NULL;
+ errno = 0;
+
+ /*
+ ** It was originally necessary to set macro 'g' to NULL
+ ** because it previously pointed to an auto buffer.
+ ** We don't do this any more, so this may be unnecessary.
+ */
+
+ macdefine(&e->e_macro, A_PERM, 'g', (char *) NULL);
+ e->e_to = NULL;
+ }
+ SM_END_TRY
return rcode;
}
- /*
+/*
** MARKFAILURE -- mark a failure on a specific address.
**
** Parameters:
@@ -2964,7 +3526,7 @@ do_transfer:
** the message will be queued, as appropriate.
*/
-static void
+void
markfailure(e, q, mci, rcode, ovr)
register ENVELOPE *e;
register ADDRESS *q;
@@ -2972,6 +3534,7 @@ markfailure(e, q, mci, rcode, ovr)
int rcode;
bool ovr;
{
+ int save_errno = errno;
char *status = NULL;
char *rstatus = NULL;
@@ -2994,9 +3557,10 @@ markfailure(e, q, mci, rcode, ovr)
/* find most specific error code possible */
if (mci != NULL && mci->mci_status != NULL)
{
- status = mci->mci_status;
+ status = sm_rpool_strdup_x(e->e_rpool, mci->mci_status);
if (mci->mci_rstatus != NULL)
- rstatus = newstr(mci->mci_rstatus);
+ rstatus = sm_rpool_strdup_x(e->e_rpool,
+ mci->mci_rstatus);
else
rstatus = NULL;
}
@@ -3059,20 +3623,23 @@ markfailure(e, q, mci, rcode, ovr)
}
if (rcode != EX_OK && q->q_rstatus == NULL &&
q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
- strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0)
+ sm_strcasecmp(q->q_mailer->m_diagtype, "X-UNIX") == 0)
{
char buf[16];
- (void) snprintf(buf, sizeof buf, "%d", rcode);
- q->q_rstatus = newstr(buf);
+ (void) sm_snprintf(buf, sizeof buf, "%d", rcode);
+ q->q_rstatus = sm_rpool_strdup_x(e->e_rpool, buf);
}
q->q_statdate = curtime();
if (CurHostName != NULL && CurHostName[0] != '\0' &&
mci != NULL && !bitset(M_LOCALMAILER, mci->mci_flags))
- q->q_statmta = newstr(CurHostName);
+ q->q_statmta = sm_rpool_strdup_x(e->e_rpool, CurHostName);
+
+ /* restore errno */
+ errno = save_errno;
}
- /*
+/*
** ENDMAILER -- Wait for mailer to terminate.
**
** We should never get fatal errors (e.g., segmentation
@@ -3117,26 +3684,26 @@ endmailer(mci, e, pv)
int st;
int save_errno = errno;
char buf[MAXLINE];
- EVENT *ev = NULL;
+ SM_EVENT *ev = NULL;
mci_unlock_host(mci);
/* close output to mailer */
if (mci->mci_out != NULL)
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
/* copy any remaining input to transcript */
if (mci->mci_in != NULL && mci->mci_state != MCIS_ERROR &&
e->e_xfp != NULL)
{
while (sfgets(buf, sizeof buf, mci->mci_in,
- TimeOuts.to_quit, "Draining Input") != NULL)
- (void) fputs(buf, e->e_xfp);
+ TimeOuts.to_quit, "Draining Input") != NULL)
+ (void) sm_io_fputs(e->e_xfp, SM_TIME_DEFAULT, buf);
}
#if SASL
- /* shutdown SASL */
+ /* close SASL connection */
if (bitset(MCIF_AUTHACT, mci->mci_flags))
{
sasl_dispose(&mci->mci_conn);
@@ -3151,7 +3718,7 @@ endmailer(mci, e, pv)
/* now close the input */
if (mci->mci_in != NULL)
- (void) fclose(mci->mci_in);
+ (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
mci->mci_in = mci->mci_out = NULL;
mci->mci_state = MCIS_CLOSED;
@@ -3165,8 +3732,8 @@ endmailer(mci, e, pv)
if (mci->mci_mailer->m_wait > 0)
{
if (setjmp(EndWaitTimeout) == 0)
- ev = setevent(mci->mci_mailer->m_wait,
- endwaittimeout, 0);
+ ev = sm_setevent(mci->mci_mailer->m_wait,
+ endwaittimeout, 0);
else
{
syserr("endmailer %s: wait timeout (%ld)",
@@ -3180,7 +3747,7 @@ endmailer(mci, e, pv)
st = waitfor(mci->mci_pid);
save_errno = errno;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
errno = save_errno;
if (st == -1)
@@ -3206,16 +3773,17 @@ endmailer(mci, e, pv)
{
register char **av;
- fprintf(e->e_xfp, "Arguments:");
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "Arguments:");
for (av = pv; *av != NULL; av++)
- fprintf(e->e_xfp, " %s", *av);
- fprintf(e->e_xfp, "\n");
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, " %s",
+ *av);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "\n");
}
ExitStat = EX_TEMPFAIL;
return EX_TEMPFAIL;
}
- /*
+/*
** GIVERESPONSE -- Interpret an error response from a mailer
**
** Parameters:
@@ -3231,6 +3799,7 @@ endmailer(mci, e, pv)
** xstart -- the transaction start time, for computing
** transaction delays.
** e -- the current envelope.
+** to -- the current recipient (NULL if none).
**
** Returns:
** none.
@@ -3241,7 +3810,7 @@ endmailer(mci, e, pv)
*/
void
-giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
+giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
int status;
char *dsn;
register MAILER *m;
@@ -3249,15 +3818,15 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
ADDRESS *ctladdr;
time_t xstart;
ENVELOPE *e;
+ ADDRESS *to;
{
register const char *statmsg;
- extern char *SysExMsg[];
- register int i;
int errnum = errno;
int off = 4;
- extern int N_SysEx;
+ bool usestat = false;
char dsnbuf[ENHSCLEN];
char buf[MAXLINE];
+ char *exmsg;
if (e == NULL)
syserr("giveresponse: null envelope");
@@ -3266,48 +3835,43 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
** Compute status message from code.
*/
- i = status - EX__BASE;
+ exmsg = sm_sysexmsg(status);
if (status == 0)
{
statmsg = "250 2.0.0 Sent";
if (e->e_statmsg != NULL)
{
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- statmsg,
- shortenstring(e->e_statmsg, 403));
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)",
+ statmsg,
+ shortenstring(e->e_statmsg, 403));
statmsg = buf;
}
}
- else if (i < 0 || i >= N_SysEx)
+ else if (exmsg == NULL)
{
- (void) snprintf(buf, sizeof buf,
- "554 5.3.0 unknown mailer error %d",
- status);
+ (void) sm_snprintf(buf, sizeof buf,
+ "554 5.3.0 unknown mailer error %d",
+ status);
status = EX_UNAVAILABLE;
statmsg = buf;
+ usestat = true;
}
else if (status == EX_TEMPFAIL)
{
char *bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "%s", SysExMsg[i] + 1);
+ (void) sm_strlcpy(bp, exmsg + 1, SPACELEFT(buf, bp));
bp += strlen(bp);
#if NAMED_BIND
if (h_errno == TRY_AGAIN)
- statmsg = errstring(h_errno+E_DNSBASE);
+ statmsg = sm_errstring(h_errno + E_DNSBASE);
else
#endif /* NAMED_BIND */
{
if (errnum != 0)
- statmsg = errstring(errnum);
+ statmsg = sm_errstring(errnum);
else
- {
-#if SMTP
statmsg = SmtpError;
-#else /* SMTP */
- statmsg = NULL;
-#endif /* SMTP */
- }
}
if (statmsg != NULL && statmsg[0] != '\0')
{
@@ -3333,33 +3897,39 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
#endif /* EHOSTUNREACH */
if (mci->mci_host != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp),
- ": %s", mci->mci_host);
+ (void) sm_strlcpyn(bp,
+ SPACELEFT(buf, bp),
+ 2, ": ",
+ mci->mci_host);
bp += strlen(bp);
}
break;
}
- snprintf(bp, SPACELEFT(buf, bp), ": %s", statmsg);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ": ",
+ statmsg);
+ usestat = true;
}
statmsg = buf;
}
#if NAMED_BIND
else if (status == EX_NOHOST && h_errno != 0)
{
- statmsg = errstring(h_errno + E_DNSBASE);
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- SysExMsg[i] + 1, statmsg);
+ statmsg = sm_errstring(h_errno + E_DNSBASE);
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)", exmsg + 1,
+ statmsg);
statmsg = buf;
+ usestat = true;
}
#endif /* NAMED_BIND */
else
{
- statmsg = SysExMsg[i];
+ statmsg = exmsg;
if (*statmsg++ == ':' && errnum != 0)
{
- (void) snprintf(buf, sizeof buf, "%s: %s",
- statmsg, errstring(errnum));
+ (void) sm_snprintf(buf, sizeof buf, "%s: %s", statmsg,
+ sm_errstring(errnum));
statmsg = buf;
+ usestat = true;
}
}
@@ -3375,8 +3945,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
{
if (dsn == NULL)
{
- snprintf(dsnbuf, sizeof dsnbuf,
- "%.*s", off, statmsg + 4);
+ (void) sm_snprintf(dsnbuf, sizeof dsnbuf,
+ "%.*s", off, statmsg + 4);
dsn = dsnbuf;
}
off += 5;
@@ -3387,7 +3957,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
}
message("%s", statmsg + off);
if (status == EX_TEMPFAIL && e->e_xfp != NULL)
- fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, "%s\n",
+ &MsgBuf[4]);
}
else
{
@@ -3399,18 +3970,21 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
{
if (dsn == NULL)
{
- snprintf(dsnbuf, sizeof dsnbuf,
- "%.*s", off, statmsg + 4);
+ (void) sm_snprintf(dsnbuf, sizeof dsnbuf,
+ "%.*s", off, statmsg + 4);
dsn = dsnbuf;
}
off += 5;
- (void) strlcpy(mbuf, statmsg, off);
- (void) strlcat(mbuf, " %s", sizeof mbuf);
+
+ /* copy only part of statmsg to mbuf */
+ (void) sm_strlcpy(mbuf, statmsg, off);
+ (void) sm_strlcat(mbuf, " %s", sizeof mbuf);
}
else
{
dsnbuf[0] = '\0';
- (void) snprintf(mbuf, sizeof mbuf, "%.3s %%s", statmsg);
+ (void) sm_snprintf(mbuf, sizeof mbuf, "%.3s %%s",
+ statmsg);
off = 4;
}
usrerr(mbuf, &statmsg[off]);
@@ -3428,25 +4002,29 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e)
logdelivery(m, mci, dsn, statmsg + off, ctladdr, xstart, e);
if (tTd(11, 2))
- dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s\n",
- status,
- dsn == NULL ? "<NULL>" : dsn,
- e->e_message == NULL ? "<NULL>" : e->e_message);
+ sm_dprintf("giveresponse: status=%d, dsn=%s, e->e_message=%s, errnum=%d\n",
+ status,
+ dsn == NULL ? "<NULL>" : dsn,
+ e->e_message == NULL ? "<NULL>" : e->e_message,
+ errnum);
if (status != EX_TEMPFAIL)
setstat(status);
if (status != EX_OK && (status != EX_TEMPFAIL || e->e_message == NULL))
+ e->e_message = sm_rpool_strdup_x(e->e_rpool, statmsg + off);
+ if (status != EX_OK && to != NULL && to->q_message == NULL)
{
- if (e->e_message != NULL)
- sm_free(e->e_message);
- e->e_message = newstr(statmsg + off);
+ if (!usestat && e->e_message != NULL)
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ e->e_message);
+ else
+ to->q_message = sm_rpool_strdup_x(e->e_rpool,
+ statmsg + off);
}
errno = 0;
-#if NAMED_BIND
SM_SET_H_ERRNO(0);
-#endif /* NAMED_BIND */
}
- /*
+/*
** LOGDELIVERY -- log the delivery in the system log
**
** Care is taken to avoid logging lines that are too long, because
@@ -3484,7 +4062,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
register char *bp;
register char *p;
int l;
- time_t now;
+ time_t now = curtime();
char buf[1024];
#if (SYSLOG_BUFSIZE) >= 256
@@ -3492,68 +4070,74 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
bp = buf;
if (ctladdr != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", ctladdr=",
+ shortenstring(ctladdr->q_paddr, 83));
bp += strlen(bp);
if (bitset(QGOODUID, ctladdr->q_flags))
{
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- (int) ctladdr->q_uid,
- (int) ctladdr->q_gid);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
+ (int) ctladdr->q_uid,
+ (int) ctladdr->q_gid);
bp += strlen(bp);
}
}
/* delay & xdelay: max 41 bytes */
- now = curtime();
- snprintf(bp, SPACELEFT(buf, bp), ", delay=%s",
- pintvl(now - e->e_ctime, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", delay=",
+ pintvl(now - e->e_ctime, true));
bp += strlen(bp);
if (xstart != (time_t) 0)
{
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(now - xstart, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
+ pintvl(now - xstart, true));
bp += strlen(bp);
}
/* mailer: assume about 19 bytes (max 10 byte mailer name) */
if (m != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
+ m->m_name);
bp += strlen(bp);
}
/* pri: changes with each delivery attempt */
- snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld", e->e_msgpriority);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), ", pri=%ld",
+ e->e_msgpriority);
bp += strlen(bp);
/* relay: max 66 bytes for IPv4 addresses */
if (mci != NULL && mci->mci_host != NULL)
{
-# if DAEMON
extern SOCKADDR CurHostAddr;
-# endif /* DAEMON */
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(mci->mci_host, 40));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", relay=",
+ shortenstring(mci->mci_host, 40));
bp += strlen(bp);
-# if DAEMON
if (CurHostAddr.sa.sa_family != 0)
{
- snprintf(bp, SPACELEFT(buf, bp), " [%s]",
- anynet_ntoa(&CurHostAddr));
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " [%s]",
+ anynet_ntoa(&CurHostAddr));
}
-# endif /* DAEMON */
}
+#if _FFR_QUARANTINE
+ else if (strcmp(status, "quarantined") == 0)
+ {
+ if (e->e_quarmsg != NULL)
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", quarantine=%s",
+ shortenstring(e->e_quarmsg, 40));
+ }
+#endif /* _FFR_QUARANTINE */
else if (strcmp(status, "queued") != 0)
{
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
{
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(p, 40));
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", relay=%s", shortenstring(p, 40));
}
}
bp += strlen(bp);
@@ -3561,8 +4145,8 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
/* dsn */
if (dsn != NULL && *dsn != '\0')
{
- snprintf(bp, SPACELEFT(buf, bp), ", dsn=%s",
- shortenstring(dsn, ENHSCLEN));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=",
+ shortenstring(dsn, ENHSCLEN));
bp += strlen(bp);
}
@@ -3581,23 +4165,25 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
{
/* desperation move -- truncate data */
bp = buf + sizeof buf - ((STATLEN) + 17);
- (void) strlcpy(bp, "...", SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, "...", SPACELEFT(buf, bp));
bp += 3;
}
- (void) strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, ", stat=", SPACELEFT(buf, bp));
bp += strlen(bp);
- (void) strlcpy(bp, shortenstring(status, STATLEN), SPACELEFT(buf, bp));
+ (void) sm_strlcpy(bp, shortenstring(status, STATLEN),
+ SPACELEFT(buf, bp));
/* id, to: max 13 + TOBUFSIZE bytes */
l = SYSLOG_BUFSIZE - 100 - strlen(buf);
+ if (l < 0)
+ l = 0;
p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
- while (strlen(p) >= (SIZE_T) l)
+ while (strlen(p) >= l)
{
register char *q;
-#if _FFR_DYNAMIC_TOBUF
for (q = p + l; q > p; q--)
{
if (*q == ',')
@@ -3605,32 +4191,22 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
}
if (p == q)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- q = strchr(p + l, ',');
- if (q == NULL)
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
-
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]%s",
+ sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]%s",
(int) (++q - p), p, buf);
p = q;
}
-#if _FFR_DYNAMIC_TOBUF
sm_syslog(LOG_INFO, e->e_id, "to=%.*s%s", l, p, buf);
-#else /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf);
-#endif /* _FFR_DYNAMIC_TOBUF */
#else /* (SYSLOG_BUFSIZE) >= 256 */
l = SYSLOG_BUFSIZE - 85;
+ if (l < 0)
+ l = 0;
p = e->e_to == NULL ? "NO-TO-LIST" : e->e_to;
- while (strlen(p) >= (SIZE_T) l)
+ while (strlen(p) >= l)
{
register char *q;
-#if _FFR_DYNAMIC_TOBUF
for (q = p + l; q > p; q--)
{
if (*q == ',')
@@ -3638,51 +4214,42 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
}
if (p == q)
break;
-#else /* _FFR_DYNAMIC_TOBUF */
- q = strchr(p + l, ',');
- if (q == NULL)
- break;
-#endif /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]",
+ sm_syslog(LOG_INFO, e->e_id, "to=%.*s [more]",
(int) (++q - p), p);
p = q;
}
-#if _FFR_DYNAMIC_TOBUF
sm_syslog(LOG_INFO, e->e_id, "to=%.*s", l, p);
-#else /* _FFR_DYNAMIC_TOBUF */
- sm_syslog(LOG_INFO, e->e_id, "to=%s", p);
-#endif /* _FFR_DYNAMIC_TOBUF */
if (ctladdr != NULL)
{
bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "ctladdr=",
+ shortenstring(ctladdr->q_paddr, 83));
bp += strlen(bp);
if (bitset(QGOODUID, ctladdr->q_flags))
{
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- ctladdr->q_uid, ctladdr->q_gid);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
+ ctladdr->q_uid, ctladdr->q_gid);
bp += strlen(bp);
}
sm_syslog(LOG_INFO, e->e_id, "%s", buf);
}
bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "delay=%s",
- pintvl(now - e->e_ctime, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, "delay=",
+ pintvl(now - e->e_ctime, true));
bp += strlen(bp);
if (xstart != (time_t) 0)
{
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(now - xstart, TRUE));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", xdelay=",
+ pintvl(now - xstart, true));
bp += strlen(bp);
}
if (m != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", mailer=",
+ m->m_name);
bp += strlen(bp);
}
sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
@@ -3691,24 +4258,31 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
bp = buf;
if (mci != NULL && mci->mci_host != NULL)
{
-# if DAEMON
extern SOCKADDR CurHostAddr;
-# endif /* DAEMON */
- snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s",
+ mci->mci_host);
bp += strlen(bp);
-# if DAEMON
if (CurHostAddr.sa.sa_family != 0)
- snprintf(bp, SPACELEFT(buf, bp), " [%.100s]",
- anynet_ntoa(&CurHostAddr));
-# endif /* DAEMON */
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ " [%.100s]",
+ anynet_ntoa(&CurHostAddr));
+ }
+#if _FFR_QUARANTINE
+ else if (strcmp(status, "quarantined") == 0)
+ {
+ if (e->e_quarmsg != NULL)
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", quarantine=%.100s",
+ e->e_quarmsg);
}
+#endif /* _FFR_QUARANTINE */
else if (strcmp(status, "queued") != 0)
{
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
- snprintf(buf, sizeof buf, "relay=%.100s", p);
+ (void) sm_snprintf(buf, sizeof buf, "relay=%.100s", p);
}
if (buf[0] != '\0')
sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
@@ -3716,7 +4290,7 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e)
sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(status, 63));
#endif /* (SYSLOG_BUFSIZE) >= 256 */
}
- /*
+/*
** PUTFROMLINE -- output a UNIX-style from line (or whatever)
**
** This can be made an arbitrary message separator by changing $l
@@ -3774,23 +4348,23 @@ putfromline(mci, e)
}
else
*at++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- buf, at);
+ (void) sm_snprintf(xbuf, sizeof xbuf,
+ "From %.800s \201d remote from %.100s\n",
+ buf, at);
}
else
{
*bang++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- bang, buf);
+ (void) sm_snprintf(xbuf, sizeof xbuf,
+ "From %.800s \201d remote from %.100s\n",
+ bang, buf);
template = xbuf;
}
}
expand(template, buf, sizeof buf, e);
putxline(buf, strlen(buf), mci, PXLF_HEADER);
}
- /*
+/*
** PUTBODY -- put the body of a message.
**
** Parameters:
@@ -3817,9 +4391,11 @@ putbody(mci, e, separator)
register ENVELOPE *e;
char *separator;
{
- bool dead = FALSE;
+ bool dead = false;
char buf[MAXLINE];
+#if MIME8TO7
char *boundaries[MAXMIMENESTING + 1];
+#endif /* MIME8TO7 */
/*
** Output the body of the message
@@ -3827,9 +4403,10 @@ putbody(mci, e, separator)
if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
{
- char *df = queuename(e, 'd');
+ char *df = queuename(e, DATAFL_LETTER);
- e->e_dfp = fopen(df, "r");
+ e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
+ SM_IO_RDONLY, NULL);
if (e->e_dfp == NULL)
{
char *msg = "!putbody: Cannot open %s for %s from %s";
@@ -3838,6 +4415,7 @@ putbody(mci, e, separator)
msg++;
syserr(msg, df, e->e_to, e->e_from.q_paddr);
}
+
}
if (e->e_dfp == NULL)
{
@@ -3854,7 +4432,8 @@ putbody(mci, e, separator)
{
struct stat stbuf;
- if (fstat(fileno(e->e_dfp), &stbuf) < 0)
+ if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &stbuf)
+ < 0)
e->e_dfino = -1;
else
{
@@ -3863,7 +4442,7 @@ putbody(mci, e, separator)
}
}
- /* paranoia: the df file should always be in a rewound state */
+ /* paranoia: the data file should always be in a rewound state */
(void) bfrewind(e->e_dfp);
#if MIME8TO7
@@ -3879,9 +4458,9 @@ putbody(mci, e, separator)
if (hvalue("Content-Type", e->e_header) == NULL)
{
- snprintf(buf, sizeof buf,
- "Content-Type: text/plain; charset=%s",
- defcharset(e));
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Type: text/plain; charset=%s",
+ defcharset(e));
putline(buf, mci);
}
@@ -3913,7 +4492,7 @@ putbody(mci, e, separator)
*/
if (bitset(EF_DONT_MIME, e->e_flags))
- SuprErrs = TRUE;
+ SuprErrs = true;
(void) mime8to7(mci, e->e_header, e, boundaries,
M87F_OUTER|M87F_NO8TO7);
@@ -3950,22 +4529,22 @@ putbody(mci, e, separator)
ostate = OS_HEAD;
bp = buf;
pbp = peekbuf;
- while (!ferror(mci->mci_out) && !dead)
+ while (!sm_io_error(mci->mci_out) && !dead)
{
if (pbp > peekbuf)
c = *--pbp;
- else if ((c = getc(e->e_dfp)) == EOF)
+ else if ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT))
+ == SM_IO_EOF)
break;
if (bitset(MCIF_7BIT, mci->mci_flags))
c &= 0x7f;
switch (ostate)
{
case OS_HEAD:
-#if _FFR_NONULLS
if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
+ bitnset(M_NONULLS,
+ mci->mci_mailer->m_flags))
break;
-#endif /* _FFR_NONULLS */
if (c != '\r' && c != '\n' && bp < buflim)
{
*bp++ = c;
@@ -3975,10 +4554,10 @@ putbody(mci, e, separator)
/* check beginning of line for special cases */
*bp = '\0';
pos = 0;
- padc = EOF;
+ padc = SM_IO_EOF;
if (buf[0] == 'F' &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
- strncmp(buf, "From ", 5) == 0)
+ bitnset(M_ESCFROM, mci->mci_mailer->m_flags)
+ && strncmp(buf, "From ", 5) == 0)
{
padc = '>';
}
@@ -3988,7 +4567,8 @@ putbody(mci, e, separator)
/* possible separator */
int sl = strlen(separator);
- if (strncmp(&buf[2], separator, sl) == 0)
+ if (strncmp(&buf[2], separator, sl)
+ == 0)
padc = ' ';
}
if (buf[0] == '.' &&
@@ -4000,57 +4580,68 @@ putbody(mci, e, separator)
/* now copy out saved line */
if (TrafficLogFile != NULL)
{
- fprintf(TrafficLogFile, "%05d >>> ",
- (int) getpid());
- if (padc != EOF)
- (void) putc(padc,
- TrafficLogFile);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d >>> ",
+ (int) CurrentPid);
+ if (padc != SM_IO_EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ padc);
for (xp = buf; xp < bp; xp++)
- (void) putc((unsigned char) *xp,
- TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp);
if (c == '\n')
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
}
- if (padc != EOF)
+ if (padc != SM_IO_EOF)
{
- if (putc(padc, mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT, padc)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
}
for (xp = buf; xp < bp; xp++)
{
- if (putc((unsigned char) *xp,
- mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
if (dead)
continue;
if (c == '\n')
{
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos = 0;
}
@@ -4076,19 +4667,22 @@ putbody(mci, e, separator)
if (c == '\n')
{
/* got CRLF */
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
continue;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
{
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
}
ostate = OS_HEAD;
continue;
@@ -4106,11 +4700,10 @@ putbody(mci, e, separator)
ostate = OS_CR;
continue;
}
-#if _FFR_NONULLS
if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
+ bitnset(M_NONULLS,
+ mci->mci_mailer->m_flags))
break;
-#endif /* _FFR_NONULLS */
putch:
if (mci->mci_mailer->m_linelimit > 0 &&
pos >= mci->mci_mailer->m_linelimit - 1 &&
@@ -4121,46 +4714,57 @@ putch:
/* check next character for EOL */
if (pbp > peekbuf)
d = *(pbp - 1);
- else if ((d = getc(e->e_dfp)) != EOF)
+ else if ((d = sm_io_getc(e->e_dfp,
+ SM_TIME_DEFAULT))
+ != SM_IO_EOF)
*pbp++ = d;
- if (d == '\n' || d == EOF)
+ if (d == '\n' || d == SM_IO_EOF)
{
if (TrafficLogFile != NULL)
- (void) putc((unsigned char) c,
- TrafficLogFile);
- if (putc((unsigned char) c,
- mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) c);
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) c)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
continue;
}
- if (putc('!', mci->mci_out) == EOF ||
- fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT, '!')
+ == SM_IO_EOF ||
+ sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
{
- fprintf(TrafficLogFile, "!%s",
- mci->mci_mailer->m_eol);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "!%s",
+ mci->mci_mailer->m_eol);
}
ostate = OS_HEAD;
*pbp++ = c;
@@ -4169,15 +4773,18 @@ putch:
if (c == '\n')
{
if (TrafficLogFile != NULL)
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- if (fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF)
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
+ if (sm_io_fputs(mci->mci_out,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
continue;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos = 0;
ostate = OS_HEAD;
@@ -4185,18 +4792,21 @@ putch:
else
{
if (TrafficLogFile != NULL)
- (void) putc((unsigned char) c,
- TrafficLogFile);
- if (putc((unsigned char) c,
- mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) c);
+ if (sm_io_putc(mci->mci_out,
+ SM_TIME_DEFAULT,
+ (unsigned char) c)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
continue;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
pos++;
ostate = OS_INLINE;
@@ -4211,21 +4821,23 @@ putch:
if (TrafficLogFile != NULL)
{
for (xp = buf; xp < bp; xp++)
- (void) putc((unsigned char) *xp,
- TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char) *xp);
}
for (xp = buf; xp < bp; xp++)
{
- if (putc((unsigned char) *xp, mci->mci_out) ==
- EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ (unsigned char) *xp)
+ == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
pos += bp - buf;
@@ -4233,19 +4845,22 @@ putch:
if (!dead && pos > 0)
{
if (TrafficLogFile != NULL)
- (void) fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- (void) fputs(mci->mci_mailer->m_eol, mci->mci_out);
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
+ (void) sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
- if (ferror(e->e_dfp))
+ if (sm_io_error(e->e_dfp))
{
- syserr("putbody: %s/df%s: read error",
- qid_printqueue(e->e_queuedir), e->e_id);
+ syserr("putbody: %s/%cf%s: read error",
+ qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
+ DATAFL_LETTER, e->e_id);
ExitStat = EX_IOERR;
}
@@ -4269,8 +4884,8 @@ endofmessage:
buf[0] != '\0' && buf[0] != '\n')
putline("", mci);
- (void) fflush(mci->mci_out);
- if (ferror(mci->mci_out) && errno != EPIPE)
+ (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
+ if (sm_io_error(mci->mci_out) && errno != EPIPE)
{
syserr("putbody: write error");
ExitStat = EX_IOERR;
@@ -4278,11 +4893,11 @@ endofmessage:
errno = 0;
}
- /*
+/*
** MAILFILE -- Send a message to a file.
**
-** If the file has the setuid/setgid bits set, but NO execute
-** bits, sendmail will try to become the owner of that file
+** If the file has the set-user-ID/set-group-ID bits set, but NO
+** execute bits, sendmail will try to become the owner of that file
** rather than the real user. Obviously, this only works if
** sendmail runs as root.
**
@@ -4308,6 +4923,8 @@ endofmessage:
** none.
*/
+# define RETURN(st) exit(st);
+
static jmp_buf CtxMailfileTimeout;
int
@@ -4318,7 +4935,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
volatile long sfflags;
register ENVELOPE *e;
{
- register FILE *f;
+ register SM_FILE_T *f;
register pid_t pid = -1;
volatile int mode;
int len;
@@ -4326,28 +4943,28 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
bool suidwarn = geteuid() == 0;
char *p;
char *volatile realfile;
- EVENT *ev;
+ SM_EVENT *ev;
char buf[MAXLINE + 1];
char targetfile[MAXPATHLEN + 1];
if (tTd(11, 1))
{
- dprintf("mailfile %s\n ctladdr=", filename);
- printaddr(ctladdr, FALSE);
+ sm_dprintf("mailfile %s\n ctladdr=", filename);
+ printaddr(ctladdr, false);
}
if (mailer == NULL)
mailer = FileMailer;
if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
/*
** Special case /dev/null. This allows us to restrict file
** delivery to regular files only.
*/
- if (strcmp(filename, "/dev/null") == 0)
+ if (sm_path_isdevnull(filename))
return EX_OK;
/* check for 8-bit available */
@@ -4360,7 +4977,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
e->e_status = "5.6.3";
usrerrenh(e->e_status,
- "554 Cannot send 8-bit data to 7-bit destination");
+ "554 Cannot send 8-bit data to 7-bit destination");
+ errno = 0;
return EX_DATAERR;
}
@@ -4372,19 +4990,19 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (strncmp(SafeFileEnv, filename, len) == 0)
filename += len;
- if (len + strlen(filename) + 1 > MAXPATHLEN)
+ if (len + strlen(filename) + 1 >= sizeof targetfile)
{
syserr("mailfile: filename too long (%s/%s)",
SafeFileEnv, filename);
return EX_CANTCREAT;
}
- (void) strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
+ (void) sm_strlcpy(targetfile, SafeFileEnv, sizeof targetfile);
realfile = targetfile + len;
if (targetfile[len - 1] != '/')
- (void) strlcat(targetfile, "/", sizeof targetfile);
+ (void) sm_strlcat(targetfile, "/", sizeof targetfile);
if (*filename == '/')
filename++;
- (void) strlcat(targetfile, filename, sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename, sizeof targetfile);
}
else if (mailer->m_rootdir != NULL)
{
@@ -4394,7 +5012,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (strncmp(targetfile, filename, len) == 0)
filename += len;
- if (len + strlen(filename) + 1 > MAXPATHLEN)
+ if (len + strlen(filename) + 1 >= sizeof targetfile)
{
syserr("mailfile: filename too long (%s/%s)",
targetfile, filename);
@@ -4402,21 +5020,22 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
}
realfile = targetfile + len;
if (targetfile[len - 1] != '/')
- (void) strlcat(targetfile, "/", sizeof targetfile);
+ (void) sm_strlcat(targetfile, "/", sizeof targetfile);
if (*filename == '/')
- (void) strlcat(targetfile, filename + 1,
- sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename + 1,
+ sizeof targetfile);
else
- (void) strlcat(targetfile, filename, sizeof targetfile);
+ (void) sm_strlcat(targetfile, filename,
+ sizeof targetfile);
}
else
{
- if (strlen(filename) > MAXPATHLEN)
+ if (sm_strlcpy(targetfile, filename, sizeof targetfile) >=
+ sizeof targetfile)
{
syserr("mailfile: filename too long (%s)", filename);
return EX_CANTCREAT;
}
- (void) strlcpy(targetfile, filename, sizeof targetfile);
realfile = targetfile;
}
@@ -4440,31 +5059,34 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
+ CurrentPid = getpid();
if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
+ (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD,
+ NULL));
- (void) setsignal(SIGINT, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_DFL);
- (void) setsignal(SIGTERM, SIG_DFL);
+ (void) sm_signal(SIGINT, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_DFL);
+ (void) sm_signal(SIGTERM, SIG_DFL);
(void) umask(OldUmask);
e->e_to = filename;
ExitStat = EX_OK;
if (setjmp(CtxMailfileTimeout) != 0)
{
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen,
- mailfiletimeout, 0);
+ ev = sm_setevent(TimeOuts.to_fileopen, mailfiletimeout,
+ 0);
else
ev = NULL;
- /* check file mode to see if setuid */
+ /* check file mode to see if set-user-ID */
if (stat(targetfile, &stb) < 0)
mode = FileMode;
else
@@ -4478,18 +5100,19 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if ((ctladdr != NULL && !bitset(QALIAS, ctladdr->q_flags)) ||
bitset(SFF_RUNASREALUID, sfflags))
{
- /* ignore setuid and setgid bits */
+ /* ignore set-user-ID and set-group-ID bits */
mode &= ~(S_ISGID|S_ISUID);
if (tTd(11, 20))
- dprintf("mailfile: ignoring setuid/setgid bits\n");
+ sm_dprintf("mailfile: ignoring set-user-ID/set-group-ID bits\n");
}
- /* we have to open the dfile BEFORE setuid */
+ /* we have to open the data file BEFORE setuid() */
if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
{
- char *df = queuename(e, 'd');
+ char *df = queuename(e, DATAFL_LETTER);
- e->e_dfp = fopen(df, "r");
+ e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, df,
+ SM_IO_RDONLY, NULL);
if (e->e_dfp == NULL)
{
syserr("mailfile: Cannot open %s for %s from %s",
@@ -4507,8 +5130,9 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (RunAsUid != 0 && RealUid != RunAsUid)
{
/* Only root can change the uid */
- syserr("mailfile: insufficient privileges to change uid");
- exit(EX_TEMPFAIL);
+ syserr("mailfile: insufficient privileges to change uid, RunAsUid=%d, RealUid=%d",
+ (int) RunAsUid, (int) RealUid);
+ RETURN(EX_TEMPFAIL);
}
}
else if (bitset(S_ISUID, mode))
@@ -4544,8 +5168,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
RealGid != getegid()))
{
/* Only root can change the gid */
- syserr("mailfile: insufficient privileges to change gid");
- exit(EX_TEMPFAIL);
+ syserr("mailfile: insufficient privileges to change gid, RealGid=%d, RunAsUid=%d, gid=%d, egid=%d",
+ (int) RealGid, (int) RunAsUid,
+ (int) getgid(), (int) getegid());
+ RETURN(EX_TEMPFAIL);
}
}
else if (bitset(S_ISGID, mode))
@@ -4587,7 +5213,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
syserr("mailfile: initgroups(%s, %d) failed",
RealUserName, RealGid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
}
else
@@ -4598,7 +5224,7 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (setgroups(1, gidset) == -1 && suidwarn)
{
syserr("mailfile: setgroups() failed");
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
}
@@ -4610,41 +5236,42 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
*realfile = '\0';
if (tTd(11, 20))
- dprintf("mailfile: chroot %s\n", targetfile);
+ sm_dprintf("mailfile: chroot %s\n", targetfile);
if (chroot(targetfile) < 0)
{
syserr("mailfile: Cannot chroot(%s)",
targetfile);
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
*realfile = '/';
}
if (tTd(11, 40))
- dprintf("mailfile: deliver to %s\n", realfile);
+ sm_dprintf("mailfile: deliver to %s\n", realfile);
if (chdir("/") < 0)
{
syserr("mailfile: cannot chdir(/)");
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
/* now reset the group and user ids */
endpwent();
+ sm_mbdb_terminate();
if (setgid(RealGid) < 0 && suidwarn)
{
syserr("mailfile: setgid(%ld) failed", (long) RealGid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
vendor_set_uid(RealUid);
if (setuid(RealUid) < 0 && suidwarn)
{
syserr("mailfile: setuid(%ld) failed", (long) RealUid);
- exit(EX_TEMPFAIL);
+ RETURN(EX_TEMPFAIL);
}
if (tTd(11, 2))
- dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n",
+ sm_dprintf("mailfile: running as r/euid=%d/%d, r/egid=%d/%d\n",
(int) getuid(), (int) geteuid(),
(int) getgid(), (int) getegid());
@@ -4663,7 +5290,8 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (q != NULL)
*q++ = ':';
if (tTd(11, 20))
- dprintf("mailfile: trydir %s\n", buf);
+ sm_dprintf("mailfile: trydir %s\n",
+ buf);
if (buf[0] != '\0' && chdir(buf) >= 0)
break;
}
@@ -4713,32 +5341,34 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
{
usrerr("454 4.3.0 cannot open %s: %s",
shortenstring(realfile, MAXSHORTSTR),
- errstring(errno));
- exit(EX_TEMPFAIL);
+ sm_errstring(errno));
+ RETURN(EX_TEMPFAIL);
}
else
{
usrerr("554 5.3.0 cannot open %s: %s",
shortenstring(realfile, MAXSHORTSTR),
- errstring(errno));
- exit(EX_CANTCREAT);
+ sm_errstring(errno));
+ RETURN(EX_CANTCREAT);
}
}
- if (filechanged(realfile, fileno(f), &stb))
+ if (filechanged(realfile, sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ &stb))
{
syserr("554 5.3.0 file changed after open");
- exit(EX_CANTCREAT);
+ RETURN(EX_CANTCREAT);
}
- if (fstat(fileno(f), &stb) < 0)
+ if (fstat(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL), &stb) < 0)
{
- syserr("554 5.3.0 cannot fstat %s", errstring(errno));
- exit(EX_CANTCREAT);
+ syserr("554 5.3.0 cannot fstat %s",
+ sm_errstring(errno));
+ RETURN(EX_CANTCREAT);
}
curoff = stb.st_size;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
memset(&mcibuf, '\0', sizeof mcibuf);
mcibuf.mci_mailer = mailer;
@@ -4758,13 +5388,13 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
if (bitnset(M_MAKE8BIT, mailer->m_flags) &&
!bitset(MCIF_7BIT, mcibuf.mci_flags) &&
(p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
- (strcasecmp(p, "quoted-printable") == 0 ||
- strcasecmp(p, "base64") == 0) &&
+ (sm_strcasecmp(p, "quoted-printable") == 0 ||
+ sm_strcasecmp(p, "base64") == 0) &&
(p = hvalue("Content-Type", e->e_header)) != NULL)
{
/* may want to convert 7 -> 8 */
/* XXX should really parse it here -- and use a class XXX */
- if (strncasecmp(p, "text/plain", 10) == 0 &&
+ if (sm_strncasecmp(p, "text/plain", 10) == 0 &&
(p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
mcibuf.mci_flags |= MCIF_CVT7TO8;
}
@@ -4774,25 +5404,28 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
(*e->e_putbody)(&mcibuf, e, NULL);
putline("\n", &mcibuf);
- if (fflush(f) != 0 ||
- (SuperSafe && fsync(fileno(f)) < 0) ||
- ferror(f))
+ if (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
+ (SuperSafe != SAFE_NO &&
+ fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) ||
+ sm_io_error(f))
{
setstat(EX_IOERR);
#if !NOFTRUNCATE
- (void) ftruncate(fileno(f), curoff);
+ (void) ftruncate(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ curoff);
#endif /* !NOFTRUNCATE */
}
/* reset ISUID & ISGID bits for paranoid systems */
#if HASFCHMOD
- (void) fchmod(fileno(f), (MODE_T) mode);
+ (void) fchmod(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL),
+ (MODE_T) mode);
#else /* HASFCHMOD */
(void) chmod(filename, (MODE_T) mode);
#endif /* HASFCHMOD */
- if (fclose(f) < 0)
+ if (sm_io_close(f, SM_TIME_DEFAULT) < 0)
setstat(EX_IOERR);
- (void) fflush(stdout);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
(void) setuid(RealUid);
exit(ExitStat);
/* NOTREACHED */
@@ -4809,7 +5442,10 @@ mailfile(filename, mailer, ctladdr, sfflags, e)
return EX_SOFTWARE;
}
if (WIFEXITED(st))
+ {
+ errno = 0;
return (WEXITSTATUS(st));
+ }
else
{
syserr("mailfile: %s: child died on signal %d",
@@ -4833,7 +5469,7 @@ mailfiletimeout()
errno = ETIMEDOUT;
longjmp(CtxMailfileTimeout, 1);
}
- /*
+/*
** HOSTSIGNATURE -- return the "signature" for a host.
**
** The signature describes how we are going to send this -- it
@@ -4850,15 +5486,17 @@ mailfiletimeout()
** Side Effects:
** Can tweak the symbol table.
*/
+
#define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */
-static char *
+char *
hostsignature(m, host)
register MAILER *m;
char *host;
{
register char *p;
register STAB *s;
+ time_t now;
#if NAMED_BIND
char sep = ':';
char prevsep = ':';
@@ -4866,35 +5504,33 @@ hostsignature(m, host)
int len;
int nmx;
int hl;
- time_t now;
char *hp;
char *endp;
int oldoptions = _res.options;
char *mxhosts[MAXMXHOSTS + 1];
- u_short mxprefs[MAXMXHOSTS + 1];
+ unsigned short mxprefs[MAXMXHOSTS + 1];
#endif /* NAMED_BIND */
if (tTd(17, 3))
- dprintf("hostsignature(%s)\n", host);
+ sm_dprintf("hostsignature(%s)\n", host);
/*
** If local delivery (and not remote), just return a constant.
*/
- p = m->m_mailer;
if (bitnset(M_LOCALMAILER, m->m_flags) &&
- strcmp(p, "[IPC]") != 0 &&
- strcmp(p, "[TCP]") != 0)
+ strcmp(m->m_mailer, "[IPC]") != 0 &&
+ !(m->m_argv[0] != NULL && strcmp(m->m_argv[0], "TCP") == 0))
return "localhost";
/*
** Check to see if this uses IPC -- if not, it can't have MX records.
*/
- if (strcmp(p, "[IPC]") != 0 &&
- strcmp(p, "[TCP]") != 0)
+ if (strcmp(m->m_mailer, "[IPC]") != 0 ||
+ CurEnv->e_sendmode == SM_DEFER)
{
- /* just an ordinary mailer */
+ /* just an ordinary mailer or deferred mode */
return host;
}
#if NETUNIX
@@ -4910,24 +5546,34 @@ hostsignature(m, host)
** Look it up in the symbol table.
*/
+ now = curtime();
s = stab(host, ST_HOSTSIG, ST_ENTER);
- if (s->s_hostsig != NULL)
+ if (s->s_hostsig.hs_sig != NULL)
{
- if (tTd(17, 3))
- dprintf("hostsignature(): stab(%s) found %s\n", host,
- s->s_hostsig);
- return s->s_hostsig;
+ if (s->s_hostsig.hs_exp >= now)
+ {
+ if (tTd(17, 3))
+ sm_dprintf("hostsignature(): stab(%s) found %s\n", host,
+ s->s_hostsig.hs_sig);
+ return s->s_hostsig.hs_sig;
+ }
+
+ /* signature is expired: clear it */
+ sm_free(s->s_hostsig.hs_sig);
+ s->s_hostsig.hs_sig = NULL;
}
+ /* set default TTL */
+ s->s_hostsig.hs_exp = now + SM_DEFAULT_TTL;
+
/*
- ** Not already there -- create a signature.
+ ** Not already there or expired -- create a signature.
*/
#if NAMED_BIND
if (ConfigLevel < 2)
_res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
- now = curtime();
for (hp = host; hp != NULL; hp = endp)
{
#if NETINET6
@@ -4957,8 +5603,10 @@ hostsignature(m, host)
else
{
auto int rcode;
+ int ttl;
- nmx = getmxrr(hp, mxhosts, mxprefs, TRUE, &rcode);
+ nmx = getmxrr(hp, mxhosts, mxprefs, true, &rcode, true,
+ &ttl);
if (nmx <= 0)
{
int save_errno;
@@ -4972,7 +5620,7 @@ hostsignature(m, host)
mci->mci_lastuse = now;
if (rcode == EX_NOHOST)
mci_setstat(mci, rcode, "5.1.2",
- "550 Host unknown");
+ "550 Host unknown");
else
mci_setstat(mci, rcode, NULL, NULL);
@@ -4981,34 +5629,41 @@ hostsignature(m, host)
mxhosts[0] = hp;
}
if (tTd(17, 3))
- dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
- nmx, mxhosts[0]);
+ sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
+ nmx, mxhosts[0]);
+
+ /*
+ ** Set new TTL: we use only one!
+ ** We could try to use the minimum instead.
+ */
+
+ s->s_hostsig.hs_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
}
len = 0;
for (i = 0; i < nmx; i++)
len += strlen(mxhosts[i]) + 1;
- if (s->s_hostsig != NULL)
- len += strlen(s->s_hostsig) + 1;
- if (len >= MAXHOSTSIGNATURE)
+ if (s->s_hostsig.hs_sig != NULL)
+ len += strlen(s->s_hostsig.hs_sig) + 1;
+ if (len < 0 || len >= MAXHOSTSIGNATURE)
{
sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
host, MAXHOSTSIGNATURE, len);
len = MAXHOSTSIGNATURE;
}
- p = xalloc(len);
- if (s->s_hostsig != NULL)
+ p = sm_pmalloc_x(len);
+ if (s->s_hostsig.hs_sig != NULL)
{
- (void) strlcpy(p, s->s_hostsig, len);
- sm_free(s->s_hostsig);
- s->s_hostsig = p;
+ (void) sm_strlcpy(p, s->s_hostsig.hs_sig, len);
+ sm_free(s->s_hostsig.hs_sig); /* XXX */
+ s->s_hostsig.hs_sig = p;
hl = strlen(p);
p += hl;
*p++ = prevsep;
len -= hl + 1;
}
else
- s->s_hostsig = p;
+ s->s_hostsig.hs_sig = p;
for (i = 0; i < nmx; i++)
{
hl = strlen(mxhosts[i]);
@@ -5026,7 +5681,7 @@ hostsignature(m, host)
*p++ = ':';
len--;
}
- (void) strlcpy(p, mxhosts[i], len);
+ (void) sm_strlcpy(p, mxhosts[i], len);
p += hl;
len -= hl;
}
@@ -5043,18 +5698,22 @@ hostsignature(m, host)
*endp++ = sep;
prevsep = sep;
}
- makelower(s->s_hostsig);
+ makelower(s->s_hostsig.hs_sig);
if (ConfigLevel < 2)
_res.options = oldoptions;
#else /* NAMED_BIND */
/* not using BIND -- the signature is just the host name */
- s->s_hostsig = host;
+ /*
+ ** 'host' points to storage that will be freed after we are
+ ** done processing the current envelope, so we copy it.
+ */
+ s->s_hostsig.hs_sig = sm_pstrdup_x(host);
#endif /* NAMED_BIND */
if (tTd(17, 1))
- dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig);
- return s->s_hostsig;
+ sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig);
+ return s->s_hostsig.hs_sig;
}
- /*
+/*
** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
**
** The signature describes how we are going to send this -- it
@@ -5065,6 +5724,7 @@ hostsignature(m, host)
** Parameters:
** sig -- the host signature.
** mxhosts -- array to populate.
+** mailer -- mailer.
**
** Returns:
** The number of hosts inserted into mxhosts array.
@@ -5079,11 +5739,10 @@ parse_hostsignature(sig, mxhosts, mailer)
char **mxhosts;
MAILER *mailer;
{
- int nmx = 0;
- int curpref = 0;
- int i, j;
+ unsigned short curpref = 0;
+ int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */
char *hp, *endp;
- u_short prefer[MAXMXHOSTS];
+ unsigned short prefer[MAXMXHOSTS];
long rndm[MAXMXHOSTS];
for (hp = sig; hp != NULL; hp = endp)
@@ -5149,7 +5808,7 @@ parse_hostsignature(sig, mxhosts, mailer)
if (prefer[i] > prefer[j] ||
(prefer[i] == prefer[j] && rndm[i] > rndm[j]))
{
- register u_short tempp;
+ register unsigned short tempp;
register long tempr;
register char *temp1;
@@ -5168,30 +5827,60 @@ parse_hostsignature(sig, mxhosts, mailer)
return nmx;
}
-#if SMTP
# if STARTTLS
static SSL_CTX *clt_ctx = NULL;
+static bool tls_ok_clt = true;
- /*
-** INITCLTTLS -- initialize client side TLS
+/*
+** SETCLTTLS -- client side TLS: allow/disallow.
**
** Parameters:
+** tls_ok -- should tls be done?
+**
+** Returns:
** none.
**
+** Side Effects:
+** sets tls_ok_clt (static variable in this module)
+*/
+
+void
+setclttls(tls_ok)
+ bool tls_ok;
+{
+ tls_ok_clt = tls_ok;
+ return;
+}
+/*
+** INITCLTTLS -- initialize client side TLS
+**
+** Parameters:
+** tls_ok -- should tls initialization be done?
+**
** Returns:
** succeeded?
+**
+** Side Effects:
+** sets tls_ok_clt (static variable in this module)
*/
bool
-initclttls()
+initclttls(tls_ok)
+ bool tls_ok;
{
+ if (!tls_ok_clt)
+ return false;
+ tls_ok_clt = tls_ok;
+ if (!tls_ok_clt)
+ return false;
if (clt_ctx != NULL)
- return TRUE; /* already done */
- return inittls(&clt_ctx, TLS_I_CLT, FALSE, CltCERTfile, Cltkeyfile,
- CACERTpath, CACERTfile, DHParams);
+ return true; /* already done */
+ tls_ok_clt = inittls(&clt_ctx, TLS_I_CLT, false, CltCERTfile,
+ Cltkeyfile, CACERTpath, CACERTfile, DHParams);
+ return tls_ok_clt;
}
- /*
+/*
** STARTTLS -- try to start secure connection (client side)
**
** Parameters:
@@ -5215,14 +5904,14 @@ starttls(m, mci, e)
int result = 0;
int rfd, wfd;
SSL *clt_ssl = NULL;
+ time_t tlsstart;
- if (clt_ctx == NULL && !initclttls())
+ if (clt_ctx == NULL && !initclttls(true))
return EX_TEMPFAIL;
smtpmessage("STARTTLS", m, mci);
/* get the reply */
- smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, NULL, NULL);
- /* which timeout? XXX */
+ smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL);
/* check return code from server */
if (smtpresult == 454)
@@ -5235,78 +5924,127 @@ starttls(m, mci, e)
return EX_PROTOCOL;
if (LogLevel > 13)
- sm_syslog(LOG_INFO, e->e_id, "TLS: start client");
+ sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok");
/* start connection */
if ((clt_ssl = SSL_new(clt_ctx)) == NULL)
{
if (LogLevel > 5)
{
- sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: client: SSL_new failed");
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, error: SSL_new failed");
if (LogLevel > 9)
- tlslogerr();
+ tlslogerr("client");
}
return EX_SOFTWARE;
}
- rfd = fileno(mci->mci_in);
- wfd = fileno(mci->mci_out);
+ rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL);
+ wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL);
/* SSL_clear(clt_ssl); ? */
if (rfd < 0 || wfd < 0 ||
- (result = SSL_set_rfd(clt_ssl, rfd)) <= 0 ||
- (result = SSL_set_wfd(clt_ssl, wfd)) <= 0)
+ (result = SSL_set_rfd(clt_ssl, rfd)) != 1 ||
+ (result = SSL_set_wfd(clt_ssl, wfd)) != 1)
{
if (LogLevel > 5)
{
- sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: SSL_set_xfd failed=%d", result);
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, error: SSL_set_xfd failed=%d",
+ result);
if (LogLevel > 9)
- tlslogerr();
+ tlslogerr("client");
}
return EX_SOFTWARE;
}
SSL_set_connect_state(clt_ssl);
+ tlsstart = curtime();
+
+ssl_retry:
if ((result = SSL_connect(clt_ssl)) <= 0)
{
int i;
+ bool timedout;
+ time_t left;
+ time_t now = curtime();
+ struct timeval tv;
/* what to do in this case? */
i = SSL_get_error(clt_ssl, result);
+
+ /*
+ ** For SSL_ERROR_WANT_{READ,WRITE}:
+ ** There is not a complete SSL record available yet
+ ** or there is only a partial SSL record removed from
+ ** the network (socket) buffer into the SSL buffer.
+ ** The SSL_connect will only succeed when a full
+ ** SSL record is available (assuming a "real" error
+ ** doesn't happen). To handle when a "real" error
+ ** does happen the select is set for exceptions too.
+ ** The connection may be re-negotiated during this time
+ ** so both read and write "want errors" need to be handled.
+ ** A select() exception loops back so that a proper SSL
+ ** error message can be gotten.
+ */
+
+ left = TimeOuts.to_starttls - (now - tlsstart);
+ timedout = left <= 0;
+ if (!timedout)
+ {
+ tv.tv_sec = left;
+ tv.tv_usec = 0;
+ }
+
+ if (!timedout && i == SSL_ERROR_WANT_READ)
+ {
+ fd_set ssl_maskr, ssl_maskx;
+
+ FD_ZERO(&ssl_maskr);
+ FD_SET(rfd, &ssl_maskr);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, &tv)
+ > 0)
+ goto ssl_retry;
+ }
+ if (!timedout && i == SSL_ERROR_WANT_WRITE)
+ {
+ fd_set ssl_maskw, ssl_maskx;
+
+ FD_ZERO(&ssl_maskw);
+ FD_SET(wfd, &ssl_maskw);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, &tv)
+ > 0)
+ goto ssl_retry;
+ }
if (LogLevel > 5)
{
sm_syslog(LOG_ERR, e->e_id,
- "TLS: error: SSL_connect failed=%d (%d)",
- result, i);
- if (LogLevel > 9)
- tlslogerr();
+ "STARTTLS=client, error: connect failed=%d, SSL_error=%d, timedout=%d",
+ result, i, (int) timedout);
+ if (LogLevel > 8)
+ tlslogerr("client");
}
SSL_free(clt_ssl);
clt_ssl = NULL;
return EX_SOFTWARE;
}
mci->mci_ssl = clt_ssl;
- result = tls_get_info(clt_ssl, e, FALSE, mci->mci_host, TRUE);
+ result = tls_get_info(mci->mci_ssl, false, mci->mci_host,
+ &mci->mci_macro, true);
- /* switch to use SSL... */
-#if SFIO
- if (sfdctls(mci->mci_in, mci->mci_out, mci->mci_ssl) == 0)
- return EX_OK;
-#else /* SFIO */
-# if _FFR_TLS_TOREK
+ /* switch to use TLS... */
if (sfdctls(&mci->mci_in, &mci->mci_out, mci->mci_ssl) == 0)
return EX_OK;
-# endif /* _FFR_TLS_TOREK */
-#endif /* SFIO */
/* failure */
SSL_free(clt_ssl);
clt_ssl = NULL;
return EX_SOFTWARE;
}
-
- /*
+/*
** ENDTLSCLT -- shutdown secure connection (client side)
**
** Parameters:
@@ -5315,7 +6053,8 @@ starttls(m, mci, e)
** Returns:
** success?
*/
-int
+
+static int
endtlsclt(mci)
MCI *mci;
{
@@ -5327,48 +6066,35 @@ endtlsclt(mci)
mci->mci_flags &= ~MCIF_TLSACT;
return r;
}
- /*
-** ENDTLS -- shutdown secure connection
+# endif /* STARTTLS */
+# if STARTTLS || SASL
+/*
+** ISCLTFLGSET -- check whether client flag is set.
**
** Parameters:
-** ssl -- SSL connection information.
-** side -- srv/clt (for logging).
+** e -- envelope.
+** flag -- flag to check in {client_flags}
**
** Returns:
-** success?
+** true iff flag is set.
*/
-int
-endtls(ssl, side)
- SSL *ssl;
- char *side;
+static bool
+iscltflgset(e, flag)
+ ENVELOPE *e;
+ int flag;
{
- int ret = EX_OK;
+ char *p;
- if (ssl != NULL)
+ p = macvalue(macid("{client_flags}"), e);
+ if (p == NULL)
+ return false;
+ for (; *p != '\0'; p++)
{
- int r;
-
- if ((r = SSL_shutdown(ssl)) < 0)
- {
- if (LogLevel > 11)
- sm_syslog(LOG_WARNING, NOQID,
- "SSL_shutdown %s failed: %d",
- side, r);
- ret = EX_SOFTWARE;
- }
- else if (r == 0)
- {
- if (LogLevel > 13)
- sm_syslog(LOG_WARNING, NOQID,
- "SSL_shutdown %s not done",
- side);
- ret = EX_SOFTWARE;
- }
- SSL_free(ssl);
- ssl = NULL;
+ /* look for just this one flag */
+ if (*p == (char) flag)
+ return true;
}
- return ret;
+ return false;
}
-# endif /* STARTTLS */
-#endif /* SMTP */
+# endif /* STARTTLS || SASL */
diff --git a/contrib/sendmail/src/domain.c b/contrib/sendmail/src/domain.c
index 18a092b..f34df4c 100644
--- a/contrib/sendmail/src/domain.c
+++ b/contrib/sendmail/src/domain.c
@@ -13,19 +13,17 @@
#include <sendmail.h>
-#ifndef lint
-# if NAMED_BIND
-static char id[] = "@(#)$Id: domain.c,v 8.114.6.1.2.8 2001/02/12 21:40:19 gshapiro Exp $ (with name server)";
-# else /* NAMED_BIND */
-static char id[] = "@(#)$Id: domain.c,v 8.114.6.1.2.8 2001/02/12 21:40:19 gshapiro Exp $ (without name server)";
-# endif /* NAMED_BIND */
-#endif /* ! lint */
-
+#if NAMED_BIND
+SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca Exp $ (with name server)")
+#else /* NAMED_BIND */
+SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca Exp $ (without name server)")
+#endif /* NAMED_BIND */
#if NAMED_BIND
# include <arpa/inet.h>
+
/*
** The standard udp packet size PACKETSZ (512) is not sufficient for some
** nameserver answers containing very many resource records. The resolver
@@ -41,8 +39,8 @@ static char id[] = "@(#)$Id: domain.c,v 8.114.6.1.2.8 2001/02/12 21:40:19 gshapi
typedef union
{
- HEADER qb1;
- u_char qb2[MAXPACKET];
+ HEADER qb1;
+ unsigned char qb2[MAXPACKET];
} querybuf;
# ifndef MXHOSTBUFSIZE
@@ -50,6 +48,9 @@ typedef union
# endif /* ! MXHOSTBUFSIZE */
static char MXHostBuf[MXHOSTBUFSIZE];
+#if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
+ ERROR: _MXHOSTBUFSIZE is out of range
+#endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */
# ifndef MAXDNSRCH
# define MAXDNSRCH 6 /* number of possible domains to search */
@@ -59,10 +60,6 @@ static char MXHostBuf[MXHOSTBUFSIZE];
# define RES_DNSRCH_VARIABLE _res.dnsrch
# endif /* ! RES_DNSRCH_VARIABLE */
-# ifndef MAX
-# define MAX(a, b) ((a) > (b) ? (a) : (b))
-# endif /* ! MAX */
-
# ifndef NO_DATA
# define NO_DATA NO_ADDRESS
# endif /* ! NO_DATA */
@@ -76,13 +73,108 @@ static char MXHostBuf[MXHOSTBUFSIZE];
# if defined(__RES) && (__RES >= 19940415)
# define RES_UNC_T char *
# else /* defined(__RES) && (__RES >= 19940415) */
-# define RES_UNC_T u_char *
+# define RES_UNC_T unsigned char *
# endif /* defined(__RES) && (__RES >= 19940415) */
static char *gethostalias __P((char *));
static int mxrand __P((char *));
+static int fallbackmxrr __P((int, unsigned short *, char **));
+
+/*
+** GETFALLBACKMXRR -- get MX resource records for fallback MX host.
+**
+** We have to initialize this once before doing anything else.
+** Moreover, we have to repeat this from time to time to avoid
+** stale data, e.g., in persistent queue runners.
+** This should be done in a parent process so the child
+** processes have the right data.
+**
+** Parameters:
+** host -- the name of the fallback MX host.
+**
+** Returns:
+** number of MX records.
+**
+** Side Effects:
+** Populates NumFallBackMXHosts and fbhosts.
+** Sets renewal time (based on TTL).
+*/
+
+int NumFallBackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */
+static char *fbhosts[MAXMXHOSTS + 1];
+
+int
+getfallbackmxrr(host)
+ char *host;
+{
+ int i, rcode;
+ int ttl;
+ static time_t renew = 0;
+
+#if 0
+ /* This is currently done before this function is called. */
+ if (host == NULL || *host == '\0')
+ return 0;
+#endif /* 0 */
+ if (NumFallBackMXHosts > 0 && renew > curtime())
+ return NumFallBackMXHosts;
+ if (host[0] == '[')
+ {
+ fbhosts[0] = host;
+ NumFallBackMXHosts = 1;
+ }
+ else
+ {
+ /* free old data */
+ for (i = 0; i < NumFallBackMXHosts; i++)
+ sm_free(fbhosts[i]);
+
+ /* get new data */
+ NumFallBackMXHosts = getmxrr(host, fbhosts, NULL, false,
+ &rcode, false, &ttl);
+ renew = curtime() + ttl;
+ for (i = 0; i < NumFallBackMXHosts; i++)
+ fbhosts[i] = newstr(fbhosts[i]);
+ }
+ return NumFallBackMXHosts;
+}
+
+/*
+** FALLBACKMXRR -- add MX resource records for fallback MX host to list.
+**
+** Parameters:
+** nmx -- current number of MX records.
+** prefs -- array of preferences.
+** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS)
+**
+** Returns:
+** new number of MX records.
+**
+** Side Effects:
+** If FallBackMX was set, it appends the MX records for
+** that host to mxhosts (and modifies prefs accordingly).
+*/
- /*
+static int
+fallbackmxrr(nmx, prefs, mxhosts)
+ int nmx;
+ unsigned short *prefs;
+ char **mxhosts;
+{
+ int i;
+
+ for (i = 0; i < NumFallBackMXHosts && nmx < MAXMXHOSTS; i++)
+ {
+ if (nmx > 0)
+ prefs[nmx] = prefs[nmx - 1] + 1;
+ else
+ prefs[nmx] = 0;
+ mxhosts[nmx++] = fbhosts[i];
+ }
+ return nmx;
+}
+
+/*
** GETMXRR -- get MX resource records for a domain
**
** Parameters:
@@ -90,50 +182,60 @@ static int mxrand __P((char *));
** mxhosts -- a pointer to a return buffer of MX records.
** mxprefs -- a pointer to a return buffer of MX preferences.
** If NULL, don't try to populate.
-** droplocalhost -- If TRUE, all MX records less preferred
+** droplocalhost -- If true, all MX records less preferred
** than the local host (as determined by $=w) will
** be discarded.
** rcode -- a pointer to an EX_ status code.
+** tryfallback -- add also fallback MX host?
+** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
** The number of MX records found.
** -1 if there is an internal failure.
** If no MX records are found, mxhosts[0] is set to host
** and 1 is returned.
+**
+** Side Effects:
+** The entries made for mxhosts point to a static array
+** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
+** if it must be preserved across calls to this function.
*/
int
-getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
+getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl)
char *host;
char **mxhosts;
- u_short *mxprefs;
+ unsigned short *mxprefs;
bool droplocalhost;
int *rcode;
+ bool tryfallback;
+ int *pttl;
{
- register u_char *eom, *cp;
+ register unsigned char *eom, *cp;
register int i, j, n;
int nmx = 0;
register char *bp;
HEADER *hp;
querybuf answer;
int ancount, qdcount, buflen;
- bool seenlocal = FALSE;
- u_short pref, type;
- u_short localpref = 256;
+ bool seenlocal = false;
+ unsigned short pref, type;
+ unsigned short localpref = 256;
char *fallbackMX = FallBackMX;
- bool trycanon = FALSE;
- u_short *prefs;
+ bool trycanon = false;
+ unsigned short *prefs;
int (*resfunc)();
- u_short prefer[MAXMXHOSTS];
+ unsigned short prefer[MAXMXHOSTS];
int weight[MAXMXHOSTS];
+ int ttl = 0;
extern int res_query(), res_search();
if (tTd(8, 2))
- dprintf("getmxrr(%s, droplocalhost=%d)\n",
- host, droplocalhost);
+ sm_dprintf("getmxrr(%s, droplocalhost=%d)\n",
+ host, droplocalhost);
- if (fallbackMX != NULL && droplocalhost &&
- wordinclass(fallbackMX, 'w'))
+ if ((fallbackMX != NULL && droplocalhost &&
+ wordinclass(fallbackMX, 'w')) || !tryfallback)
{
/* don't use fallback for this pass */
fallbackMX = NULL;
@@ -146,7 +248,6 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
else
prefs = prefer;
-
/* efficiency hack -- numeric or non-MX lookups */
if (host[0] == '[')
goto punt;
@@ -167,16 +268,17 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
resfunc = res_search;
errno = 0;
- n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer));
+ n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
+ sizeof(answer));
if (n < 0)
{
if (tTd(8, 1))
- dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
- (host == NULL) ? "<NULL>" : host, errno, h_errno);
+ sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
+ host == NULL ? "<NULL>" : host, errno, h_errno);
switch (h_errno)
{
case NO_DATA:
- trycanon = TRUE;
+ trycanon = true;
/* FALLTHROUGH */
case NO_RECOVERY:
@@ -188,7 +290,7 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
case 0: /* Ultrix resolver retns failure w/ h_errno=0 */
# endif /* BROKEN_RES_SEARCH */
/* host doesn't exist in DNS; might be in /etc/hosts */
- trycanon = TRUE;
+ trycanon = true;
*rcode = EX_NOHOST;
goto punt;
@@ -198,19 +300,14 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
if (fallbackMX != NULL)
{
/* name server is hosed -- push to fallback */
- if (nmx > 0)
- prefs[nmx] = prefs[nmx - 1] + 1;
- else
- prefs[nmx] = 0;
- mxhosts[nmx++] = fallbackMX;
- return nmx;
+ return fallbackmxrr(nmx, prefs, mxhosts);
}
/* it might come up later; better queue it up */
*rcode = EX_TEMPFAIL;
break;
default:
- syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n",
+ syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
host, h_errno);
*rcode = EX_OSERR;
break;
@@ -226,50 +323,69 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
/* find first satisfactory answer */
hp = (HEADER *)&answer;
- cp = (u_char *)&answer + HFIXEDSZ;
- eom = (u_char *)&answer + n;
- for (qdcount = ntohs((u_short)hp->qdcount);
+ cp = (unsigned char *)&answer + HFIXEDSZ;
+ eom = (unsigned char *)&answer + n;
+ for (qdcount = ntohs((unsigned short) hp->qdcount);
qdcount--;
cp += n + QFIXEDSZ)
{
if ((n = dn_skipname(cp, eom)) < 0)
goto punt;
}
+
+ /* NOTE: see definition of MXHostBuf! */
buflen = sizeof(MXHostBuf) - 1;
+ SM_ASSERT(buflen > 0);
bp = MXHostBuf;
- ancount = ntohs((u_short)hp->ancount);
+ ancount = ntohs((unsigned short) hp->ancount);
+
+ /* See RFC 1035 for layout of RRs. */
+ /* XXX leave room for FallBackMX ? */
while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
{
- if ((n = dn_expand((u_char *)&answer,
- eom, cp, (RES_UNC_T) bp, buflen)) < 0)
+ if ((n = dn_expand((unsigned char *)&answer, eom, cp,
+ (RES_UNC_T) bp, buflen)) < 0)
break;
cp += n;
GETSHORT(type, cp);
- cp += INT16SZ + INT32SZ;
- GETSHORT(n, cp);
+ cp += INT16SZ; /* skip over class */
+ GETLONG(ttl, cp);
+ GETSHORT(n, cp); /* rdlength */
if (type != T_MX)
{
if (tTd(8, 8) || _res.options & RES_DEBUG)
- dprintf("unexpected answer type %d, size %d\n",
+ sm_dprintf("unexpected answer type %d, size %d\n",
type, n);
cp += n;
continue;
}
GETSHORT(pref, cp);
- if ((n = dn_expand((u_char *)&answer, eom, cp,
+ if ((n = dn_expand((unsigned char *)&answer, eom, cp,
(RES_UNC_T) bp, buflen)) < 0)
break;
cp += n;
+ n = strlen(bp);
+# if 0
+ /* Can this happen? */
+ if (n == 0)
+ {
+ if (LogLevel > 4)
+ sm_syslog(LOG_ERR, NOQID,
+ "MX records for %s contain empty string",
+ host);
+ continue;
+ }
+# endif /* 0 */
if (wordinclass(bp, 'w'))
{
if (tTd(8, 3))
- dprintf("found localhost (%s) in MX list, pref=%d\n",
+ sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
bp, pref);
if (droplocalhost)
{
if (!seenlocal || pref < localpref)
localpref = pref;
- seenlocal = TRUE;
+ seenlocal = true;
continue;
}
weight[nmx] = 0;
@@ -278,7 +394,6 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
weight[nmx] = mxrand(bp);
prefs[nmx] = pref;
mxhosts[nmx++] = bp;
- n = strlen(bp);
bp += n;
if (bp[-1] != '.')
{
@@ -286,9 +401,18 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
n++;
}
*bp++ = '\0';
+ if (buflen < n + 1)
+ {
+ /* don't want to wrap buflen */
+ break;
+ }
buflen -= n + 1;
}
+ /* return only one TTL entry, that should be sufficient */
+ if (ttl > 0 && pttl != NULL)
+ *pttl = ttl;
+
/* sort the records */
for (i = 0; i < nmx; i++)
{
@@ -321,7 +445,7 @@ getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
/* delete duplicates from list (yes, some bozos have duplicates) */
for (i = 0; i < nmx - 1; )
{
- if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
+ if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
i++;
else
{
@@ -393,19 +517,19 @@ punt:
host, MyHostName);
return -1;
}
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
freehostent(h);
hp = NULL;
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
}
- if (strlen(host) >= (SIZE_T) sizeof MXHostBuf)
+ if (strlen(host) >= sizeof MXHostBuf)
{
*rcode = EX_CONFIG;
syserr("Host name %s too long",
shortenstring(host, MAXSHORTSTR));
return -1;
}
- snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host);
+ (void) sm_strlcpy(MXHostBuf, host, sizeof MXHostBuf);
mxhosts[0] = MXHostBuf;
prefs[0] = 0;
if (host[0] == '[')
@@ -427,8 +551,8 @@ punt:
*p = ']';
}
# if NETINET6
- else if (inet_pton(AF_INET6, &MXHostBuf[1],
- &tmp6.sin6_addr) == 1)
+ else if (anynet_pton(AF_INET6, &MXHostBuf[1],
+ &tmp6.sin6_addr) == 1)
{
nmx++;
*p = ']';
@@ -436,14 +560,15 @@ punt:
# endif /* NETINET6 */
else
{
- trycanon = TRUE;
+ trycanon = true;
mxhosts[0]++;
}
}
}
if (trycanon &&
- getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
+ getcanonname(mxhosts[0], sizeof MXHostBuf - 2, false, pttl))
{
+ /* XXX MXHostBuf == "" ? is that possible? */
bp = &MXHostBuf[strlen(MXHostBuf)];
if (bp[-1] != '.')
{
@@ -457,16 +582,11 @@ punt:
/* if we have a default lowest preference, include that */
if (fallbackMX != NULL && !seenlocal)
{
- if (nmx > 0)
- prefs[nmx] = prefs[nmx - 1] + 1;
- else
- prefs[nmx] = 0;
- mxhosts[nmx++] = fallbackMX;
+ nmx = fallbackmxrr(nmx, prefs, mxhosts);
}
-
return nmx;
}
- /*
+/*
** MXRAND -- create a randomizer for equal MX preferences
**
** If two MX hosts have equal preferences we want to randomize
@@ -479,9 +599,6 @@ punt:
**
** Returns:
** A random but repeatable value based on the host name.
-**
-** Side Effects:
-** none.
*/
static int
@@ -499,7 +616,7 @@ mxrand(host)
}
if (tTd(17, 9))
- dprintf("mxrand(%s)", host);
+ sm_dprintf("mxrand(%s)", host);
hfunc = seed;
while (*host != '\0')
@@ -515,10 +632,10 @@ mxrand(host)
hfunc++;
if (tTd(17, 9))
- dprintf(" = %d\n", hfunc);
+ sm_dprintf(" = %d\n", hfunc);
return hfunc;
}
- /*
+/*
** BESTMX -- find the best MX for a name
**
** This is really a hack, but I don't see any obvious way
@@ -535,13 +652,19 @@ bestmx_map_lookup(map, name, av, statp)
{
int nmx;
int saveopts = _res.options;
- int i, len = 0;
- char *p;
+ int i;
+ ssize_t len = 0;
+ char *result;
char *mxhosts[MAXMXHOSTS + 1];
+#if _FFR_BESTMX_BETTER_TRUNCATION
+ char *buf;
+#else /* _FFR_BESTMX_BETTER_TRUNCATION */
+ char *p;
char buf[PSBUFSIZE / 2];
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
- nmx = getmxrr(name, mxhosts, NULL, FALSE, statp);
+ nmx = getmxrr(name, mxhosts, NULL, false, statp, true, NULL);
_res.options = saveopts;
if (nmx <= 0)
return NULL;
@@ -554,10 +677,49 @@ bestmx_map_lookup(map, name, av, statp)
** We were given a -z flag (return all MXs) and there are multiple
** ones. We need to build them all into a list.
*/
+
+#if _FFR_BESTMX_BETTER_TRUNCATION
+ for (i = 0; i < nmx; i++)
+ {
+ if (strchr(mxhosts[i], map->map_coldelim) != NULL)
+ {
+ syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
+ mxhosts[i], map->map_coldelim);
+ return NULL;
+ }
+ len += strlen(mxhosts[i]) + 1;
+ if (len < 0)
+ {
+ len -= strlen(mxhosts[i]) + 1;
+ break;
+ }
+ }
+ buf = (char *) sm_malloc(len);
+ if (buf == NULL)
+ {
+ *statp = EX_UNAVAILABLE;
+ return NULL;
+ }
+ *buf = '\0';
+ for (i = 0; i < nmx; i++)
+ {
+ int end;
+
+ end = sm_strlcat(buf, mxhosts[i], len);
+ if (i != nmx && end + 1 < len)
+ {
+ buf[end] = map->map_coldelim;
+ buf[end + 1] = '\0';
+ }
+ }
+
+ /* Cleanly truncate for rulesets */
+ truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
+#else /* _FFR_BESTMX_BETTER_TRUNCATION */
p = buf;
for (i = 0; i < nmx; i++)
{
- int slen;
+ size_t slen;
if (strchr(mxhosts[i], map->map_coldelim) != NULL)
{
@@ -573,13 +735,19 @@ bestmx_map_lookup(map, name, av, statp)
*p++ = map->map_coldelim;
len++;
}
- (void) strlcpy(p, mxhosts[i], sizeof buf - len);
+ (void) sm_strlcpy(p, mxhosts[i], sizeof buf - len);
p += slen;
len += slen;
}
- return map_rewrite(map, buf, len, av);
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+
+ result = map_rewrite(map, buf, len, av);
+#if _FFR_BESTMX_BETTER_TRUNCATION
+ sm_free(buf);
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION */
+ return result;
}
- /*
+/*
** DNS_GETCANONNAME -- get the canonical name for named host using DNS
**
** This algorithm tries to be smart about wildcard MX records.
@@ -603,20 +771,28 @@ bestmx_map_lookup(map, name, av, statp)
** hbsize -- the size of the host buffer.
** trymx -- if set, try MX records as well as A and CNAME.
** statp -- pointer to place to store status.
+** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
-** TRUE -- if the host matched.
-** FALSE -- otherwise.
+** true -- if the host matched.
+** false -- otherwise.
*/
+# if NETINET6
+# define SM_T_INITIAL T_AAAA
+# else /* NETINET6 */
+# define SM_T_INITIAL T_A
+# endif /* NETINET6 */
+
bool
-dns_getcanonname(host, hbsize, trymx, statp)
+dns_getcanonname(host, hbsize, trymx, statp, pttl)
char *host;
int hbsize;
bool trymx;
int *statp;
+ int *pttl;
{
- register u_char *eom, *ap;
+ register unsigned char *eom, *ap;
register char *cp;
register int n;
HEADER *hp;
@@ -625,23 +801,24 @@ dns_getcanonname(host, hbsize, trymx, statp)
int ret;
char **domain;
int type;
+ int ttl = 0;
char **dp;
char *mxmatch;
bool amatch;
- bool gotmx = FALSE;
+ bool gotmx = false;
int qtype;
int loopcnt;
char *xp;
- char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)];
+ char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
char *searchlist[MAXDNSRCH+2];
if (tTd(8, 2))
- dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
+ sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
*statp = EX_OK;
@@ -669,6 +846,7 @@ cnameloop:
** If this is a simple name, determine whether it matches an
** alias in the file defined by the environment variable HOSTALIASES.
*/
+
if (n == 0 && (xp = gethostalias(host)) != NULL)
{
if (loopcnt++ > MAXCNAMEDEPTH)
@@ -677,7 +855,7 @@ cnameloop:
}
else
{
- (void) strlcpy(host, xp, hbsize);
+ (void) sm_strlcpy(host, xp, hbsize);
goto cnameloop;
}
}
@@ -720,16 +898,15 @@ cnameloop:
*/
mxmatch = NULL;
- qtype = T_ANY;
+ qtype = SM_T_INITIAL;
for (dp = searchlist; *dp != NULL; )
{
- if (qtype == T_ANY)
- gotmx = FALSE;
+ if (qtype == SM_T_INITIAL)
+ gotmx = false;
if (tTd(8, 5))
- dprintf("dns_getcanonname: trying %s.%s (%s)\n",
+ sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
host, *dp,
- qtype == T_ANY ? "ANY" :
# if NETINET6
qtype == T_AAAA ? "AAAA" :
# endif /* NETINET6 */
@@ -741,34 +918,21 @@ cnameloop:
answer.qb2, sizeof(answer.qb2));
if (ret <= 0)
{
+ int save_errno = errno;
+
if (tTd(8, 7))
- dprintf("\tNO: errno=%d, h_errno=%d\n",
- errno, h_errno);
+ sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
+ save_errno, h_errno);
- if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
+ if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
{
/*
- ** the name server seems to be down or
- ** broken.
+ ** the name server seems to be down or broken.
*/
SM_SET_H_ERRNO(TRY_AGAIN);
*statp = EX_TEMPFAIL;
- /*
- ** If the ANY query is larger than the
- ** UDP packet size, the resolver will
- ** fall back to TCP. However, some
- ** misconfigured firewalls block 53/TCP
- ** so the ANY lookup fails whereas an MX
- ** or A record might work. Therefore,
- ** don't fail on ANY queries.
- **
- ** The ANY query is really meant to prime
- ** the cache so this isn't dangerous.
- */
-
-#if _FFR_WORKAROUND_BROKEN_NAMESERVERS
if (WorkAroundBrokenAAAA)
{
/*
@@ -781,37 +945,26 @@ cnameloop:
** didn't give an answer).
*/
- if (qtype != T_ANY &&
- errno != ETIMEDOUT)
- return FALSE;
+ if (save_errno != ETIMEDOUT)
+ return false;
}
-#else /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */
- if (qtype != T_ANY)
- return FALSE;
-#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */
+ else
+ return false;
}
if (h_errno != HOST_NOT_FOUND)
{
/* might have another type of interest */
- if (qtype == T_ANY)
- {
# if NETINET6
- qtype = T_AAAA;
-# else /* NETINET6 */
- qtype = T_A;
-# endif /* NETINET6 */
- continue;
- }
-# if NETINET6
- else if (qtype == T_AAAA)
+ if (qtype == T_AAAA)
{
qtype = T_A;
continue;
}
+ else
# endif /* NETINET6 */
- else if (qtype == T_A && !gotmx &&
- (trymx || **dp == '\0'))
+ if (qtype == T_A && !gotmx &&
+ (trymx || **dp == '\0'))
{
qtype = T_MX;
continue;
@@ -820,15 +973,20 @@ cnameloop:
/* definite no -- try the next domain */
dp++;
- qtype = T_ANY;
+ qtype = SM_T_INITIAL;
continue;
}
else if (tTd(8, 7))
- dprintf("\tYES\n");
+ sm_dprintf("\tYES\n");
/* avoid problems after truncation in tcp packets */
if (ret > sizeof(answer))
ret = sizeof(answer);
+ if (ret < 0)
+ {
+ *statp = EX_SOFTWARE;
+ return false;
+ }
/*
** Appear to have a match. Confirm it by searching for A or
@@ -837,41 +995,42 @@ cnameloop:
*/
hp = (HEADER *) &answer;
- ap = (u_char *) &answer + HFIXEDSZ;
- eom = (u_char *) &answer + ret;
+ ap = (unsigned char *) &answer + HFIXEDSZ;
+ eom = (unsigned char *) &answer + ret;
/* skip question part of response -- we know what we asked */
- for (qdcount = ntohs((u_short)hp->qdcount);
+ for (qdcount = ntohs((unsigned short) hp->qdcount);
qdcount--;
ap += ret + QFIXEDSZ)
{
if ((ret = dn_skipname(ap, eom)) < 0)
{
if (tTd(8, 20))
- dprintf("qdcount failure (%d)\n",
- ntohs((u_short)hp->qdcount));
+ sm_dprintf("qdcount failure (%d)\n",
+ ntohs((unsigned short) hp->qdcount));
*statp = EX_SOFTWARE;
- return FALSE; /* ???XXX??? */
+ return false; /* ???XXX??? */
}
}
- amatch = FALSE;
- for (ancount = ntohs((u_short)hp->ancount);
+ amatch = false;
+ for (ancount = ntohs((unsigned short) hp->ancount);
--ancount >= 0 && ap < eom;
ap += n)
{
- n = dn_expand((u_char *) &answer, eom, ap,
+ n = dn_expand((unsigned char *) &answer, eom, ap,
(RES_UNC_T) nbuf, sizeof nbuf);
if (n < 0)
break;
ap += n;
GETSHORT(type, ap);
- ap += INT16SZ + INT32SZ;
- GETSHORT(n, ap);
+ ap += INT16SZ; /* skip over class */
+ GETLONG(ttl, ap);
+ GETSHORT(n, ap); /* rdlength */
switch (type)
{
case T_MX:
- gotmx = TRUE;
+ gotmx = true;
if (**dp != '\0' && HasWildcardMX)
{
/*
@@ -900,7 +1059,7 @@ cnameloop:
# if NETINET6
case T_AAAA:
/* Flag that a good match was found */
- amatch = TRUE;
+ amatch = true;
/* continue in case a CNAME also exists */
continue;
@@ -908,7 +1067,7 @@ cnameloop:
case T_A:
/* Flag that a good match was found */
- amatch = TRUE;
+ amatch = true;
/* continue in case a CNAME also exists */
continue;
@@ -917,7 +1076,7 @@ cnameloop:
if (DontExpandCnames)
{
/* got CNAME -- guaranteed canonical */
- amatch = TRUE;
+ amatch = true;
break;
}
@@ -930,21 +1089,25 @@ cnameloop:
{
char ebuf[MAXLINE];
- snprintf(ebuf, sizeof ebuf,
+ (void) sm_snprintf(ebuf,
+ sizeof ebuf,
"Deferred: DNS failure: CNAME loop for %.100s",
host);
- CurEnv->e_message = newstr(ebuf);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(
+ CurEnv->e_rpool, ebuf);
}
SM_SET_H_ERRNO(NO_RECOVERY);
*statp = EX_CONFIG;
- return FALSE;
+ return false;
}
/* value points at name */
- if ((ret = dn_expand((u_char *)&answer,
- eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0)
+ if ((ret = dn_expand((unsigned char *)&answer,
+ eom, ap, (RES_UNC_T) nbuf,
+ sizeof(nbuf))) < 0)
break;
- (void)strlcpy(host, nbuf, hbsize);
+ (void) sm_strlcpy(host, nbuf, hbsize);
/*
** RFC 1034 section 3.6 specifies that CNAME
@@ -973,32 +1136,21 @@ cnameloop:
/*
** Nothing definitive yet.
- ** If this was a T_ANY query, we don't really know what
- ** was returned -- it might have been a T_NS,
- ** for example. Try T_A to be more specific
- ** during the next pass.
** If this was a T_A query and we haven't yet found a MX
** match, try T_MX if allowed to do so.
** Otherwise, try the next domain.
*/
- if (qtype == T_ANY)
- {
# if NETINET6
- qtype = T_AAAA;
-# else /* NETINET6 */
- qtype = T_A;
-# endif /* NETINET6 */
- }
-# if NETINET6
- else if (qtype == T_AAAA)
+ if (qtype == T_AAAA)
qtype = T_A;
+ else
# endif /* NETINET6 */
- else if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
+ if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
qtype = T_MX;
else
{
- qtype = T_ANY;
+ qtype = SM_T_INITIAL;
dp++;
}
}
@@ -1008,7 +1160,7 @@ cnameloop:
{
if (*statp == EX_OK)
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
/*
@@ -1017,14 +1169,18 @@ cnameloop:
** Otherwise append the saved domain name.
*/
- (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host,
- *mxmatch == '\0' ? "" : ".",
- MAXDNAME, mxmatch);
- (void) strlcpy(host, nbuf, hbsize);
+ (void) sm_snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host,
+ *mxmatch == '\0' ? "" : ".",
+ MAXDNAME, mxmatch);
+ (void) sm_strlcpy(host, nbuf, hbsize);
if (tTd(8, 5))
- dprintf("dns_getcanonname: %s\n", host);
+ sm_dprintf("dns_getcanonname: %s\n", host);
*statp = EX_OK;
- return TRUE;
+
+ /* return only one TTL entry, that should be sufficient */
+ if (ttl > 0 && pttl != NULL)
+ *pttl = ttl;
+ return true;
}
static char *
@@ -1032,19 +1188,21 @@ gethostalias(host)
char *host;
{
char *fname;
- FILE *fp;
+ SM_FILE_T *fp;
register char *p = NULL;
long sff = SFF_REGONLY;
char buf[MAXLINE];
static char hbuf[MAXDNAME];
+ if (ResNoAliases)
+ return NULL;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
fname = getenv("HOSTALIASES");
if (fname == NULL ||
(fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL)
return NULL;
- while (fgets(buf, sizeof buf, fp) != NULL)
+ while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++)
continue;
@@ -1054,17 +1212,17 @@ gethostalias(host)
continue;
}
*p++ = '\0';
- if (strcasecmp(buf, host) == 0)
+ if (sm_strcasecmp(buf, host) == 0)
break;
}
- if (feof(fp))
+ if (sm_io_eof(fp))
{
/* no match */
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
return NULL;
}
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
/* got a match; extract the equivalent name */
while (*p != '\0' && isascii(*p) && isspace(*p))
@@ -1073,7 +1231,7 @@ gethostalias(host)
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
*p = '\0';
- (void) strlcpy(hbuf, host, sizeof hbuf);
+ (void) sm_strlcpy(hbuf, host, sizeof hbuf);
return hbuf;
}
#endif /* NAMED_BIND */
diff --git a/contrib/sendmail/src/envelope.c b/contrib/sendmail/src/envelope.c
index bed63e4..16449f1 100644
--- a/contrib/sendmail/src/envelope.c
+++ b/contrib/sendmail/src/envelope.c
@@ -11,21 +11,21 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: envelope.c,v 8.180.14.10 2001/05/03 17:24:06 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: envelope.c,v 8.279 2001/12/10 19:56:04 ca Exp $")
/*
-** NEWENVELOPE -- allocate a new envelope
+** NEWENVELOPE -- fill in a new envelope
**
** Supports inheritance.
**
** Parameters:
** e -- the new envelope to fill in.
** parent -- the envelope to be the parent of e.
+** rpool -- either NULL, or a pointer to a resource pool
+** from which envelope memory is allocated, and
+** to which envelope resources are attached.
**
** Returns:
** e.
@@ -35,13 +35,23 @@ static char id[] = "@(#)$Id: envelope.c,v 8.180.14.10 2001/05/03 17:24:06 gshapi
*/
ENVELOPE *
-newenvelope(e, parent)
+newenvelope(e, parent, rpool)
register ENVELOPE *e;
register ENVELOPE *parent;
+ SM_RPOOL_T *rpool;
{
- if (e == parent && e->e_parent != NULL)
+ /*
+ ** This code used to read:
+ ** if (e == parent && e->e_parent != NULL)
+ ** parent = e->e_parent;
+ ** So if e == parent && e->e_parent == NULL then we would
+ ** set e->e_parent = e, which creates a loop in the e_parent chain.
+ ** This meant macvalue() could go into an infinite loop.
+ */
+
+ if (e == parent)
parent = e->e_parent;
- clearenvelope(e, TRUE);
+ clearenvelope(e, true, rpool);
if (e == CurEnv)
memmove((char *) &e->e_from,
(char *) &NullAddress,
@@ -54,20 +64,52 @@ newenvelope(e, parent)
assign_queueid(e);
e->e_ctime = curtime();
if (parent != NULL)
+ {
e->e_msgpriority = parent->e_msgsize;
+#if _FFR_QUARANTINE
+ if (parent->e_quarmsg == NULL)
+ {
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), "");
+ }
+ else
+ {
+ e->e_quarmsg = sm_rpool_strdup_x(rpool,
+ parent->e_quarmsg);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
+ }
+#endif /* _FFR_QUARANTINE */
+ }
e->e_puthdr = putheader;
e->e_putbody = putbody;
if (CurEnv->e_xfp != NULL)
- (void) fflush(CurEnv->e_xfp);
+ (void) sm_io_flush(CurEnv->e_xfp, SM_TIME_DEFAULT);
return e;
}
- /*
+
+/* values for msg_timeout, see also IS_* below for usage (bit layout) */
+#define MSG_T_O 0x01 /* normal timeout */
+#define MSG_T_O_NOW 0x02 /* NOW timeout */
+#define MSG_NOT_BY 0x04 /* Deliver-By time exceeded, mode R */
+#define MSG_WARN 0x10 /* normal queue warning */
+#define MSG_WARN_BY 0x20 /* Deliver-By time exceeded, mode N */
+
+#define IS_MSG_ERR(x) (((x) & 0x0f) != 0) /* return an error */
+
+/* immediate return */
+#define IS_IMM_RET(x) (((x) & (MSG_T_O_NOW|MSG_NOT_BY)) != 0)
+#define IS_MSG_WARN(x) (((x) & 0xf0) != 0) /* return a warning */
+
+/*
** DROPENVELOPE -- deallocate an envelope.
**
** Parameters:
** e -- the envelope to deallocate.
** fulldrop -- if set, do return receipts.
+** split -- if true, split by recipient if message is queued up
**
** Returns:
** none.
@@ -78,17 +120,19 @@ newenvelope(e, parent)
*/
void
-dropenvelope(e, fulldrop)
+dropenvelope(e, fulldrop, split)
register ENVELOPE *e;
bool fulldrop;
+ bool split;
{
- bool queueit = FALSE;
- bool message_timeout = FALSE;
- bool failure_return = FALSE;
- bool delay_return = FALSE;
- bool success_return = FALSE;
+ bool panic = false;
+ bool queueit = false;
+ int msg_timeout = 0;
+ bool failure_return = false;
+ bool delay_return = false;
+ bool success_return = false;
bool pmnotify = bitset(EF_PM_NOTIFY, e->e_flags);
- bool done = FALSE;
+ bool done = false;
register ADDRESS *q;
char *id = e->e_id;
time_t now;
@@ -96,21 +140,21 @@ dropenvelope(e, fulldrop)
if (tTd(50, 1))
{
- dprintf("dropenvelope %lx: id=", (u_long) e);
+ sm_dprintf("dropenvelope %p: id=", e);
xputs(e->e_id);
- dprintf(", flags=");
+ sm_dprintf(", flags=");
printenvflags(e);
if (tTd(50, 10))
{
- dprintf("sendq=");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("sendq=");
+ printaddr(e->e_sendqueue, true);
}
}
if (LogLevel > 84)
sm_syslog(LOG_DEBUG, id,
"dropenvelope, e_flags=0x%lx, OpMode=%c, pid=%d",
- e->e_flags, OpMode, getpid());
+ e->e_flags, OpMode, (int) CurrentPid);
/* we must have an id to remove disk files */
if (id == NULL)
@@ -133,12 +177,18 @@ dropenvelope(e, fulldrop)
now = curtime();
if (now >= e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
- message_timeout = TRUE;
-
- if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
+ msg_timeout = MSG_T_O;
+ if (IS_DLVR_RETURN(e) && e->e_deliver_by > 0 &&
+ now >= e->e_ctime + e->e_deliver_by &&
!bitset(EF_RESPONSE, e->e_flags))
{
- message_timeout = TRUE;
+ msg_timeout = MSG_NOT_BY;
+ e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
+ }
+ else if (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
+ !bitset(EF_RESPONSE, e->e_flags))
+ {
+ msg_timeout = MSG_T_O_NOW;
e->e_flags |= EF_FATALERRS|EF_CLRQUEUE;
}
@@ -146,31 +196,32 @@ dropenvelope(e, fulldrop)
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_UNDELIVERED(q->q_state))
- queueit = TRUE;
+ queueit = true;
/* see if a notification is needed */
if (bitset(QPINGONFAILURE, q->q_flags) &&
- ((message_timeout && QS_IS_UNDELIVERED(q->q_state)) ||
+ ((IS_MSG_ERR(msg_timeout) &&
+ QS_IS_UNDELIVERED(q->q_state)) ||
QS_IS_BADADDR(q->q_state) ||
- (TimeOuts.to_q_return[e->e_timeoutclass] == NOW &&
- !bitset(EF_RESPONSE, e->e_flags))))
-
+ IS_IMM_RET(msg_timeout)))
{
- failure_return = TRUE;
+ failure_return = true;
if (!done && q->q_owner == NULL &&
!emptyaddr(&e->e_from))
{
(void) sendtolist(e->e_from.q_paddr, NULLADDR,
&e->e_errorqueue, 0, e);
- done = TRUE;
+ done = true;
}
}
- else if (bitset(QPINGONSUCCESS, q->q_flags) &&
- ((QS_IS_SENT(q->q_state) &&
- bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
- bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags)))
+ else if ((bitset(QPINGONSUCCESS, q->q_flags) &&
+ ((QS_IS_SENT(q->q_state) &&
+ bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
+ bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags))) ||
+ bitset(QBYTRACE, q->q_flags) ||
+ bitset(QBYNRELAY, q->q_flags))
{
- success_return = TRUE;
+ success_return = true;
}
}
@@ -184,75 +235,146 @@ dropenvelope(e, fulldrop)
if (!queueit)
/* EMPTY */
/* nothing to do */ ;
- else if (message_timeout)
+ else if (IS_MSG_ERR(msg_timeout))
{
if (failure_return)
{
- (void) snprintf(buf, sizeof buf,
+ if (msg_timeout == MSG_NOT_BY)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ "delivery time expired %lds",
+ e->e_deliver_by);
+ }
+ else
+ {
+ (void) sm_snprintf(buf, sizeof buf,
"Cannot send message for %s",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
- if (e->e_message != NULL)
- sm_free(e->e_message);
- e->e_message = newstr(buf);
+ pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
+ false));
+ }
+
+ /* don't free, allocated from e_rpool */
+ e->e_message = sm_rpool_strdup_x(e->e_rpool, buf);
message(buf);
e->e_flags |= EF_CLRQUEUE;
}
- fprintf(e->e_xfp, "Message could not be delivered for %s\n",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
- fprintf(e->e_xfp, "Message will be deleted from queue\n");
+ if (msg_timeout == MSG_NOT_BY)
+ {
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Delivery time (%lds) expired\n",
+ e->e_deliver_by);
+ }
+ else
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Message could not be delivered for %s\n",
+ pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
+ false));
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Message will be deleted from queue\n");
for (q = e->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_UNDELIVERED(q->q_state))
{
q->q_state = QS_BADADDR;
- q->q_status = "4.4.7";
+ if (msg_timeout == MSG_NOT_BY)
+ q->q_status = "5.4.7";
+ else
+ q->q_status = "4.4.7";
}
}
}
- else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
- now >= e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
+ else
{
- if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
- e->e_class >= 0 &&
- e->e_from.q_paddr != NULL &&
- strcmp(e->e_from.q_paddr, "<>") != 0 &&
- strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
- (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 ||
- strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
+ if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
+ now >= e->e_ctime +
+ TimeOuts.to_q_warning[e->e_timeoutclass])
+ msg_timeout = MSG_WARN;
+ else if (IS_DLVR_NOTIFY(e) &&
+ e->e_deliver_by > 0 &&
+ now >= e->e_ctime + e->e_deliver_by)
+ msg_timeout = MSG_WARN_BY;
+
+ if (IS_MSG_WARN(msg_timeout))
{
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
+ e->e_class >= 0 &&
+ e->e_from.q_paddr != NULL &&
+ strcmp(e->e_from.q_paddr, "<>") != 0 &&
+ sm_strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
+ (strlen(e->e_from.q_paddr) <= 8 ||
+ sm_strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8],
+ "-request") != 0))
{
- if (QS_IS_UNDELIVERED(q->q_state) &&
+ for (q = e->e_sendqueue; q != NULL;
+ q = q->q_next)
+ {
+ if (QS_IS_UNDELIVERED(q->q_state)
#if _FFR_NODELAYDSN_ON_HOLD
- !bitnset(M_HOLD, q->q_mailer->m_flags) &&
+ && !bitnset(M_HOLD,
+ q->q_mailer->m_flags)
#endif /* _FFR_NODELAYDSN_ON_HOLD */
- bitset(QPINGONDELAY, q->q_flags))
+ )
+ {
+ if (msg_timeout ==
+ MSG_WARN_BY &&
+ (bitset(QPINGONDELAY,
+ q->q_flags) ||
+ !bitset(QHASNOTIFY,
+ q->q_flags))
+ )
+ {
+ q->q_flags |= QBYNDELAY;
+ delay_return = true;
+ }
+ if (bitset(QPINGONDELAY,
+ q->q_flags))
+ {
+ q->q_flags |= QDELAYED;
+ delay_return = true;
+ }
+ }
+ }
+ }
+ if (delay_return)
+ {
+ if (msg_timeout == MSG_WARN_BY)
{
- q->q_flags |= QDELAYED;
- delay_return = TRUE;
+ (void) sm_snprintf(buf, sizeof buf,
+ "Warning: Delivery time (%lds) exceeded",
+ e->e_deliver_by);
}
+ else
+ (void) sm_snprintf(buf, sizeof buf,
+ "Warning: could not send message for past %s",
+ pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
+ false));
+
+ /* don't free, allocated from e_rpool */
+ e->e_message = sm_rpool_strdup_x(e->e_rpool,
+ buf);
+ message(buf);
+ e->e_flags |= EF_WARNING;
}
+ if (msg_timeout == MSG_WARN_BY)
+ {
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Warning: Delivery time (%lds) exceeded\n",
+ e->e_deliver_by);
+ }
+ else
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Warning: message still undelivered after %s\n",
+ pintvl(TimeOuts.to_q_warning[e->e_timeoutclass],
+ false));
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Will keep trying until message is %s old\n",
+ pintvl(TimeOuts.to_q_return[e->e_timeoutclass],
+ false));
}
- if (delay_return)
- {
- (void) snprintf(buf, sizeof buf,
- "Warning: could not send message for past %s",
- pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
- if (e->e_message != NULL)
- sm_free(e->e_message);
- e->e_message = newstr(buf);
- message(buf);
- e->e_flags |= EF_WARNING;
- }
- fprintf(e->e_xfp,
- "Warning: message still undelivered after %s\n",
- pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
- fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
}
if (tTd(50, 2))
- dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
+ sm_dprintf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
failure_return, delay_return, success_return, queueit);
/*
@@ -268,7 +390,7 @@ dropenvelope(e, fulldrop)
QS_IS_VERIFIED(q->q_state)) &&
bitset(QPINGONFAILURE, q->q_flags))
{
- failure_return = TRUE;
+ failure_return = true;
q->q_state = QS_BADADDR;
}
}
@@ -285,7 +407,7 @@ dropenvelope(e, fulldrop)
auto ADDRESS *rlist = NULL;
if (tTd(50, 8))
- dprintf("dropenvelope(%s): sending return receipt\n",
+ sm_dprintf("dropenvelope(%s): sending return receipt\n",
id);
e->e_flags |= EF_SENDRECEIPT;
(void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
@@ -300,8 +422,8 @@ dropenvelope(e, fulldrop)
if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
{
if (tTd(50, 8))
- dprintf("dropenvelope(%s): saving mail\n", id);
- savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
+ sm_dprintf("dropenvelope(%s): saving mail\n", id);
+ panic = savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
}
/*
@@ -321,7 +443,7 @@ dropenvelope(e, fulldrop)
expand(PostMasterCopy, pcopy, sizeof pcopy, e);
if (tTd(50, 8))
- dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
+ sm_dprintf("dropenvelope(%s): sending postmaster copy to %s\n",
id, pcopy);
(void) sendtolist(pcopy, NULLADDR, &rlist, 0, e);
}
@@ -338,47 +460,110 @@ dropenvelope(e, fulldrop)
simpledrop:
if (tTd(50, 8))
- dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
+ sm_dprintf("dropenvelope(%s): at simpledrop, queueit=%d\n",
id, queueit);
if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
{
if (tTd(50, 1))
{
- dprintf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
+ sm_dprintf("\n===== Dropping queue files for %s... queueit=%d, e_flags=",
e->e_id, queueit);
printenvflags(e);
}
- xunlink(queuename(e, 'd'));
- xunlink(queuename(e, 'q'));
+ if (!panic)
+ (void) xunlink(queuename(e, DATAFL_LETTER));
+#if _FFR_QUARANTINE
+ if (panic && QueueMode == QM_LOST)
+ {
+ /*
+ ** leave the Qf file behind as
+ ** the delivery attempt failed.
+ */
+
+ /* EMPTY */
+ }
+ else
+#endif /* _FFR_QUARANTINE */
+ if (xunlink(queuename(e, ANYQFL_LETTER)) == 0)
+ {
+ /* add to available space in filesystem */
+ updfs(e, true, !panic);
+ }
if (e->e_ntries > 0 && LogLevel > 9)
sm_syslog(LOG_INFO, id, "done; delay=%s, ntries=%d",
- pintvl(curtime() - e->e_ctime, TRUE),
+ pintvl(curtime() - e->e_ctime, true),
e->e_ntries);
}
else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
{
-#if QUEUE
- queueup(e, FALSE);
-#else /* QUEUE */
- syserr("554 5.3.0 dropenvelope: queueup");
-#endif /* QUEUE */
+ if (!split)
+ queueup(e, false, true);
+ else
+ {
+ ENVELOPE *oldsib;
+ ENVELOPE *ee;
+
+ /*
+ ** Save old sibling and set it to NULL to avoid
+ ** queueing up the same envelopes again.
+ ** This requires that envelopes in that list have
+ ** been take care of before (or at some other place).
+ */
+
+ oldsib = e->e_sibling;
+ e->e_sibling = NULL;
+ if (!split_by_recipient(e) &&
+ bitset(EF_FATALERRS, e->e_flags))
+ {
+ syserr("!dropenvelope(%s): cannot commit data file %s, uid=%d",
+ e->e_id, queuename(e, DATAFL_LETTER),
+ geteuid());
+ }
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ queueup(ee, false, true);
+ queueup(e, false, true);
+
+ /* clean up */
+ for (ee = e->e_sibling; ee != NULL; ee = ee->e_sibling)
+ {
+ /* now unlock the job */
+ if (tTd(50, 8))
+ sm_dprintf("dropenvelope(%s): unlocking job\n",
+ ee->e_id);
+ closexscript(ee);
+ unlockqueue(ee);
+
+ /* this envelope is marked unused */
+ if (ee->e_dfp != NULL)
+ {
+ (void) sm_io_close(ee->e_dfp,
+ SM_TIME_DEFAULT);
+ ee->e_dfp = NULL;
+ }
+ ee->e_id = NULL;
+ ee->e_flags &= ~EF_HAS_DF;
+ }
+ e->e_sibling = oldsib;
+ }
}
/* now unlock the job */
if (tTd(50, 8))
- dprintf("dropenvelope(%s): unlocking job\n", id);
+ sm_dprintf("dropenvelope(%s): unlocking job\n", id);
closexscript(e);
unlockqueue(e);
/* make sure that this envelope is marked unused */
if (e->e_dfp != NULL)
- (void) bfclose(e->e_dfp);
- e->e_dfp = NULL;
+ {
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
+ e->e_dfp = NULL;
+ }
e->e_id = NULL;
e->e_flags &= ~EF_HAS_DF;
}
- /*
+/*
** CLEARENVELOPE -- clear an envelope without unlocking
**
** This is normally used by a child process to get a clean
@@ -389,6 +574,9 @@ simpledrop:
** fullclear - if set, the current envelope is total
** garbage and should be ignored; otherwise,
** release any resources it may indicate.
+** rpool -- either NULL, or a pointer to a resource pool
+** from which envelope memory is allocated, and
+** to which envelope resources are attached.
**
** Returns:
** none.
@@ -399,40 +587,81 @@ simpledrop:
*/
void
-clearenvelope(e, fullclear)
+clearenvelope(e, fullclear, rpool)
register ENVELOPE *e;
bool fullclear;
+ SM_RPOOL_T *rpool;
{
register HDR *bh;
register HDR **nhp;
extern ENVELOPE BlankEnvelope;
+ char **p;
if (!fullclear)
{
/* clear out any file information */
if (e->e_xfp != NULL)
- (void) bfclose(e->e_xfp);
+ (void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
if (e->e_dfp != NULL)
- (void) bfclose(e->e_dfp);
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
e->e_xfp = e->e_dfp = NULL;
}
- /* now clear out the data */
- STRUCTCOPY(BlankEnvelope, *e);
+ /*
+ ** Copy BlankEnvelope into *e.
+ ** It is not safe to simply copy pointers to strings;
+ ** the strings themselves must be copied (or set to NULL).
+ ** The problem is that when we assign a new string value to
+ ** a member of BlankEnvelope, we free the old string.
+ ** We did not need to do this copying in sendmail 8.11 :-(
+ ** and it is a potential performance hit. Reference counted
+ ** strings are one way out.
+ */
+
+ *e = BlankEnvelope;
e->e_message = NULL;
+#if _FFR_QUARANTINE
+ e->e_qfletter = '\0';
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
+#endif /* _FFR_QUARANTINE */
+
+ /*
+ ** Copy the macro table.
+ ** We might be able to avoid this by zeroing the macro table
+ ** and always searching BlankEnvelope.e_macro after e->e_macro
+ ** in macvalue().
+ */
+
+ for (p = &e->e_macro.mac_table[0];
+ p <= &e->e_macro.mac_table[MAXMACROID];
+ ++p)
+ {
+ if (*p != NULL)
+ *p = sm_rpool_strdup_x(rpool, *p);
+ }
+
+ /*
+ ** XXX There are many strings in the envelope structure
+ ** XXX that we are not attempting to copy here.
+ ** XXX Investigate this further.
+ */
+
+ e->e_rpool = rpool;
+ e->e_macro.mac_rpool = rpool;
if (Verbose)
set_delivery_mode(SM_DELIVER, e);
bh = BlankEnvelope.e_header;
nhp = &e->e_header;
while (bh != NULL)
{
- *nhp = (HDR *) xalloc(sizeof *bh);
+ *nhp = (HDR *) sm_rpool_malloc_x(rpool, sizeof *bh);
memmove((char *) *nhp, (char *) bh, sizeof *bh);
bh = bh->h_link;
nhp = &(*nhp)->h_link;
}
}
- /*
+/*
** INITSYS -- initialize instantiation of system
**
** In Daemon mode, this is done in the child.
@@ -453,8 +682,7 @@ void
initsys(e)
register ENVELOPE *e;
{
- char cbuf[5]; /* holds hop count */
- char pbuf[10]; /* holds pid */
+ char buf[10];
#ifdef TTYNAME
static char ybuf[60]; /* holds tty id */
register char *p;
@@ -464,11 +692,14 @@ initsys(e)
/*
** Give this envelope a reality.
** I.e., an id, a transcript, and a creation time.
+ ** We don't select the queue until all of the recipients are known.
*/
- setnewqueue(e);
openxscript(e);
e->e_ctime = curtime();
+#if _FFR_QUARANTINE
+ e->e_qfletter = '\0';
+#endif /* _FFR_QUARANTINE */
#if _FFR_QUEUEDELAY
e->e_queuealg = QueueAlg;
e->e_queuedelay = QueueInitDelay;
@@ -490,18 +721,18 @@ initsys(e)
*/
/* process id */
- (void) snprintf(pbuf, sizeof pbuf, "%d", (int) getpid());
- define('p', newstr(pbuf), e);
+ (void) sm_snprintf(buf, sizeof buf, "%d", (int) CurrentPid);
+ macdefine(&e->e_macro, A_TEMP, 'p', buf);
/* hop count */
- (void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount);
- define('c', newstr(cbuf), e);
+ (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
+ macdefine(&e->e_macro, A_TEMP, 'c', buf);
/* time as integer, unix time, arpa time */
settime(e);
/* Load average */
- (void)sm_getla(e);
+ sm_getla();
#ifdef TTYNAME
/* tty name */
@@ -512,13 +743,13 @@ initsys(e)
{
if (strrchr(p, '/') != NULL)
p = strrchr(p, '/') + 1;
- snprintf(ybuf, sizeof ybuf, "%s", p);
- define('y', ybuf, e);
+ (void) sm_strlcpy(ybuf, sizeof ybuf, p);
+ macdefine(&e->e_macro, A_PERM, 'y', ybuf);
}
}
#endif /* TTYNAME */
}
- /*
+/*
** SETTIME -- set the current time.
**
** Parameters:
@@ -537,27 +768,25 @@ settime(e)
{
register char *p;
auto time_t now;
- char tbuf[20]; /* holds "current" time */
- char dbuf[30]; /* holds ctime(tbuf) */
+ char buf[30];
register struct tm *tm;
now = curtime();
tm = gmtime(&now);
- (void) snprintf(tbuf, sizeof tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
- tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
- define('t', newstr(tbuf), e);
- (void) strlcpy(dbuf, ctime(&now), sizeof dbuf);
- p = strchr(dbuf, '\n');
+ (void) sm_snprintf(buf, sizeof buf, "%04d%02d%02d%02d%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ macdefine(&e->e_macro, A_TEMP, 't', buf);
+ (void) sm_strlcpy(buf, ctime(&now), sizeof buf);
+ p = strchr(buf, '\n');
if (p != NULL)
*p = '\0';
- define('d', newstr(dbuf), e);
- p = arpadate(dbuf);
- p = newstr(p);
+ macdefine(&e->e_macro, A_TEMP, 'd', buf);
+ macdefine(&e->e_macro, A_TEMP, 'b', arpadate(buf));
if (macvalue('a', e) == NULL)
- define('a', p, e);
- define('b', p, e);
+ macdefine(&e->e_macro, A_PERM, 'a', macvalue('b', e));
}
- /*
+/*
** OPENXSCRIPT -- Open transcript file
**
** Creates a transcript file for possible eventual mailing or
@@ -591,29 +820,27 @@ openxscript(e)
syserr("openxscript: job not locked");
#endif /* 0 */
- p = queuename(e, 'x');
+ p = queuename(e, XSCRPT_LETTER);
e->e_xfp = bfopen(p, FileMode, XscriptFileBufferSize,
SFF_NOTEXCL|SFF_OPENASROOT);
if (e->e_xfp == NULL)
{
syserr("Can't create transcript file %s", p);
- e->e_xfp = fopen("/dev/null", "r+");
+ e->e_xfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
+ SM_PATH_DEVNULL, SM_IO_RDWR, NULL);
if (e->e_xfp == NULL)
- syserr("!Can't open /dev/null");
+ syserr("!Can't open %s", SM_PATH_DEVNULL);
}
-#if HASSETVBUF
- (void) setvbuf(e->e_xfp, NULL, _IOLBF, 0);
-#else /* HASSETVBUF */
- (void) setlinebuf(e->e_xfp);
-#endif /* HASSETVBUF */
+ (void) sm_io_setvbuf(e->e_xfp, SM_TIME_DEFAULT, NULL, SM_IO_LBF, 0);
if (tTd(46, 9))
{
- dprintf("openxscript(%s):\n ", p);
- dumpfd(fileno(e->e_xfp), TRUE, FALSE);
+ sm_dprintf("openxscript(%s):\n ", p);
+ dumpfd(sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL), true,
+ false);
}
}
- /*
+/*
** CLOSEXSCRIPT -- close the transcript file.
**
** Parameters:
@@ -636,10 +863,10 @@ closexscript(e)
if (e->e_lockfp == NULL)
syserr("closexscript: job not locked");
#endif /* 0 */
- (void) bfclose(e->e_xfp);
+ (void) sm_io_close(e->e_xfp, SM_TIME_DEFAULT);
e->e_xfp = NULL;
}
- /*
+/*
** SETSENDER -- set the person who this message is from
**
** Under certain circumstances allow the user to say who
@@ -688,14 +915,13 @@ setsender(from, e, delimptr, delimchar, internal)
{
register char **pvp;
char *realname = NULL;
- register struct passwd *pw;
char *bp;
char buf[MAXNAME + 2];
char pvpbuf[PSBUFSIZE];
extern char *FullName;
if (tTd(45, 1))
- dprintf("setsender(%s)\n", from == NULL ? "" : from);
+ sm_dprintf("setsender(%s)\n", from == NULL ? "" : from);
/*
** Figure out the real user executing us.
@@ -709,17 +935,16 @@ setsender(from, e, delimptr, delimchar, internal)
realname = username();
if (ConfigLevel < 2)
- SuprErrs = TRUE;
+ SuprErrs = true;
+
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e s", e);
-#endif /* _FFR_ADDR_TYPE */
/* preset state for then clause in case from == NULL */
e->e_from.q_state = QS_BADADDR;
e->e_from.q_flags = 0;
if (from == NULL ||
parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
- delimchar, delimptr, e) == NULL ||
+ delimchar, delimptr, e, false) == NULL ||
QS_IS_BADADDR(e->e_from.q_state) ||
e->e_from.q_mailer == ProgMailer ||
e->e_from.q_mailer == FileMailer ||
@@ -738,9 +963,9 @@ setsender(from, e, delimptr, delimchar, internal)
if (host == NULL)
host = MyHostName;
- (void) snprintf(ebuf, sizeof ebuf, "%.*s@%.*s",
- MAXNAME, realname,
- MAXNAME, host);
+ (void) sm_snprintf(ebuf, sizeof ebuf,
+ "%.*s@%.*s", MAXNAME,
+ realname, MAXNAME, host);
p = ebuf;
}
sm_syslog(LOG_NOTICE, e->e_id,
@@ -756,39 +981,41 @@ setsender(from, e, delimptr, delimchar, internal)
usrerrenh(e->e_status,
"553 Invalid sender address");
}
- SuprErrs = TRUE;
+ SuprErrs = true;
}
if (from == realname ||
- parseaddr(from = newstr(realname), &e->e_from,
- RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
+ parseaddr(from = realname,
+ &e->e_from, RF_COPYALL|RF_SENDERADDR, ' ',
+ NULL, e, false) == NULL)
{
char nbuf[100];
- SuprErrs = TRUE;
+ SuprErrs = true;
expand("\201n", nbuf, sizeof nbuf, e);
- if (parseaddr(from = newstr(nbuf), &e->e_from,
- RF_COPYALL, ' ', NULL, e) == NULL &&
+ from = sm_rpool_strdup_x(e->e_rpool, nbuf);
+ if (parseaddr(from, &e->e_from, RF_COPYALL, ' ',
+ NULL, e, false) == NULL &&
parseaddr(from = "postmaster", &e->e_from,
- RF_COPYALL, ' ', NULL, e) == NULL)
+ RF_COPYALL, ' ', NULL, e, false) == NULL)
syserr("553 5.3.0 setsender: can't even parse postmaster!");
}
}
else
- FromFlag = TRUE;
+ FromFlag = true;
e->e_from.q_state = QS_SENDER;
if (tTd(45, 5))
{
- dprintf("setsender: QS_SENDER ");
- printaddr(&e->e_from, FALSE);
+ sm_dprintf("setsender: QS_SENDER ");
+ printaddr(&e->e_from, false);
}
- SuprErrs = FALSE;
+ SuprErrs = false;
#if USERDB
if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
{
register char *p;
- p = udbsender(e->e_from.q_user);
+ p = udbsender(e->e_from.q_user, e->e_rpool);
if (p != NULL)
from = p;
}
@@ -796,6 +1023,8 @@ setsender(from, e, delimptr, delimchar, internal)
if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
{
+ SM_MBDB_T user;
+
if (!internal)
{
/* if the user already given fullname don't redefine */
@@ -806,34 +1035,36 @@ setsender(from, e, delimptr, delimchar, internal)
}
if (e->e_from.q_user[0] != '\0' &&
- (pw = sm_getpwnam(e->e_from.q_user)) != NULL)
+ sm_mbdb_lookup(e->e_from.q_user, &user) == EX_OK)
{
/*
** Process passwd file entry.
*/
/* extract home directory */
- if (*pw->pw_dir == '\0')
+ if (*user.mbdb_homedir == '\0')
e->e_from.q_home = NULL;
- else if (strcmp(pw->pw_dir, "/") == 0)
- e->e_from.q_home = newstr("");
+ else if (strcmp(user.mbdb_homedir, "/") == 0)
+ e->e_from.q_home = "";
else
- e->e_from.q_home = newstr(pw->pw_dir);
- define('z', e->e_from.q_home, e);
+ e->e_from.q_home = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_homedir);
+ macdefine(&e->e_macro, A_PERM, 'z', e->e_from.q_home);
/* extract user and group id */
- e->e_from.q_uid = pw->pw_uid;
- e->e_from.q_gid = pw->pw_gid;
- e->e_from.q_flags |= QGOODUID;
+ if (user.mbdb_uid != SM_NO_UID)
+ {
+ e->e_from.q_uid = user.mbdb_uid;
+ e->e_from.q_gid = user.mbdb_gid;
+ e->e_from.q_flags |= QGOODUID;
+ }
/* extract full name from passwd file */
- if (FullName == NULL && pw->pw_gecos != NULL &&
- strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
- !internal)
+ if (FullName == NULL && !internal &&
+ user.mbdb_fullname[0] != '\0' &&
+ strcmp(user.mbdb_name, e->e_from.q_user) == 0)
{
- buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf);
- if (buf[0] != '\0')
- FullName = newstr(buf);
+ FullName = newstr(user.mbdb_fullname);
}
}
else
@@ -841,7 +1072,7 @@ setsender(from, e, delimptr, delimchar, internal)
e->e_from.q_home = NULL;
}
if (FullName != NULL && !internal)
- define('x', FullName, e);
+ macdefine(&e->e_macro, A_PERM, 'x', FullName);
}
else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
{
@@ -874,24 +1105,22 @@ setsender(from, e, delimptr, delimchar, internal)
sm_syslog(LOG_NOTICE, e->e_id,
"cannot prescan from (%s)",
shortenstring(from, MAXSHORTSTR));
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
}
- (void) rewrite(pvp, 3, 0, e);
- (void) rewrite(pvp, 1, 0, e);
- (void) rewrite(pvp, 4, 0, e);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ (void) REWRITE(pvp, 3, e);
+ (void) REWRITE(pvp, 1, e);
+ (void) REWRITE(pvp, 4, e);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
bp = buf + 1;
cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
{
/* heuristic: route-addr: add angle brackets */
- (void) strlcat(bp, ">", sizeof buf - 1);
+ (void) sm_strlcat(bp, ">", sizeof buf - 1);
*--bp = '<';
}
- e->e_sender = newstr(bp);
- define('f', e->e_sender, e);
+ e->e_sender = sm_rpool_strdup_x(e->e_rpool, bp);
+ macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
/* save the domain spec if this mailer wants it */
if (e->e_from.q_mailer != NULL &&
@@ -900,15 +1129,11 @@ setsender(from, e, delimptr, delimchar, internal)
char **lastat;
/* get rid of any pesky angle brackets */
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e s", e);
-#endif /* _FFR_ADDR_TYPE */
- (void) rewrite(pvp, 3, 0, e);
- (void) rewrite(pvp, 1, 0, e);
- (void) rewrite(pvp, 4, 0, e);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e s");
+ (void) REWRITE(pvp, 3, e);
+ (void) REWRITE(pvp, 1, e);
+ (void) REWRITE(pvp, 4, e);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
/* strip off to the last "@" sign */
for (lastat = NULL; *pvp != NULL; pvp++)
@@ -916,16 +1141,16 @@ setsender(from, e, delimptr, delimchar, internal)
lastat = pvp;
if (lastat != NULL)
{
- e->e_fromdomain = copyplist(lastat, TRUE);
+ e->e_fromdomain = copyplist(lastat, true, e->e_rpool);
if (tTd(45, 3))
{
- dprintf("Saving from domain: ");
+ sm_dprintf("Saving from domain: ");
printav(e->e_fromdomain);
}
}
}
}
- /*
+/*
** PRINTENVFLAGS -- print envelope flags for debugging
**
** Parameters:
@@ -937,8 +1162,8 @@ setsender(from, e, delimptr, delimchar, internal)
struct eflags
{
- char *ef_name;
- u_long ef_bit;
+ char *ef_name;
+ unsigned long ef_bit;
};
static struct eflags EnvelopeFlags[] =
@@ -967,6 +1192,10 @@ static struct eflags EnvelopeFlags[] =
{ "HAS_DF", EF_HAS_DF },
{ "IS_MIME", EF_IS_MIME },
{ "DONT_MIME", EF_DONT_MIME },
+ { "DISCARD", EF_DISCARD },
+ { "TOOBIG", EF_TOOBIG },
+ { "SPLIT", EF_SPLIT },
+ { "UNSAFE", EF_UNSAFE },
{ NULL, 0 }
};
@@ -975,19 +1204,21 @@ printenvflags(e)
register ENVELOPE *e;
{
register struct eflags *ef;
- bool first = TRUE;
+ bool first = true;
- printf("%lx", e->e_flags);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%lx", e->e_flags);
for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
{
if (!bitset(ef->ef_bit, e->e_flags))
continue;
if (first)
- printf("<%s", ef->ef_name);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "<%s",
+ ef->ef_name);
else
- printf(",%s", ef->ef_name);
- first = FALSE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ",%s",
+ ef->ef_name);
+ first = false;
}
if (!first)
- printf(">\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n");
}
diff --git a/contrib/sendmail/src/err.c b/contrib/sendmail/src/err.c
index d259db2..484af9e 100644
--- a/contrib/sendmail/src/err.c
+++ b/contrib/sendmail/src/err.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,42 +11,97 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: err.c,v 8.120.4.5 2001/08/17 22:09:40 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-#ifdef LDAPMAP
+
+SM_RCSID("@(#)$Id: err.c,v 8.189 2002/01/09 18:52:30 ca Exp $")
+
+#if LDAPMAP
# include <lber.h>
# include <ldap.h> /* for LDAP error codes */
#endif /* LDAPMAP */
-
static void putoutmsg __P((char *, bool, bool));
static void puterrmsg __P((char *));
static char *fmtmsg __P((char *, const char *, const char *, const char *,
int, const char *, va_list));
/*
+** FATAL_ERROR -- handle a fatal exception
+**
+** This function is installed as the default exception handler
+** in the main sendmail process, and in all child processes
+** that we create. Its job is to handle exceptions that are not
+** handled at a lower level.
+**
+** The theory is that unhandled exceptions will be 'fatal' class
+** exceptions (with an "F:" prefix), such as the out-of-memory
+** exception "F:sm.heap". As such, they are handled by exiting
+** the process in exactly the same way that xalloc() in Sendmail 8.10
+** exits the process when it fails due to lack of memory:
+** we call syserr with a message beginning with "!".
+**
+** Parameters:
+** exc -- exception which is terminating this process
+**
+** Returns:
+** none
+*/
+
+void
+fatal_error(exc)
+ SM_EXC_T *exc;
+{
+ static char buf[256];
+ SM_FILE_T f;
+
+ /*
+ ** This function may be called when the heap is exhausted.
+ ** The following code writes the message for 'exc' into our
+ ** static buffer without allocating memory or raising exceptions.
+ */
+
+ sm_strio_init(&f, buf, sizeof(buf));
+ sm_exc_write(exc, &f);
+ (void) sm_io_flush(&f, SM_TIME_DEFAULT);
+
+ /*
+ ** Terminate the process after logging an error and cleaning up.
+ ** Problems:
+ ** - syserr decides what class of error this is by looking at errno.
+ ** That's no good; we should look at the exc structure.
+ ** - The cleanup code should be moved out of syserr
+ ** and into individual exception handlers
+ ** that are part of the module they clean up after.
+ */
+
+ errno = ENOMEM;
+ syserr("!%s", buf);
+}
+
+/*
** SYSERR -- Print error message.
**
-** Prints an error message via printf to the diagnostic output.
+** Prints an error message via sm_io_printf to the diagnostic output.
**
** If the first character of the syserr message is `!' it will
** log this as an ALERT message and exit immediately. This can
** leave queue files in an indeterminate state, so it should not
** be used lightly.
**
+** If the first character of the syserr message is '!' or '@'
+** then syserr knows that the process is about to be terminated,
+** so the SMTP reply code defaults to 421. Otherwise, the
+** reply code defaults to 451 or 554, depending on errno.
+**
** Parameters:
-** fmt -- the format string. If it does not begin with
-** a three-digit SMTP reply code, either 554 or
-** 451 is assumed depending on whether errno
-** is set.
+** fmt -- the format string. An optional '!' or '@',
+** followed by an optional three-digit SMTP
+** reply code, followed by message text.
** (others) -- parameters
**
** Returns:
** none
-** Through TopFrame if QuickAbort is set.
+** Raises E:mta.quickabort if QuickAbort is set.
**
** Side Effects:
** increments Errors.
@@ -73,22 +128,45 @@ syserr(fmt, va_alist)
register char *p;
int save_errno = errno;
bool panic;
+ bool exiting;
char *user;
char *enhsc;
char *errtxt;
struct passwd *pw;
char ubuf[80];
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
- panic = *fmt == '!';
- if (panic)
+ switch (*fmt)
{
- fmt++;
- HoldErrs = FALSE;
+ case '!':
+ ++fmt;
+ panic = true;
+ exiting = true;
+ break;
+ case '@':
+ ++fmt;
+ panic = false;
+ exiting = true;
+ break;
+ default:
+ panic = false;
+ exiting = false;
+ break;
}
/* format and output the error message */
- if (save_errno == 0)
+ if (exiting)
+ {
+ /*
+ ** Since we are terminating the process,
+ ** we are aborting the entire SMTP session,
+ ** rather than just the current transaction.
+ */
+
+ p = "421";
+ enhsc = "4.0.0";
+ }
+ else if (save_errno == 0)
{
p = "554";
enhsc = "5.0.0";
@@ -98,17 +176,19 @@ syserr(fmt, va_alist)
p = "451";
enhsc = "4.0.0";
}
- VA_START(fmt);
+ SM_VA_START(ap, fmt);
errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
- VA_END;
+ SM_VA_END(ap);
puterrmsg(MsgBuf);
/* save this message for mailq printing */
if (!panic && CurEnv != NULL)
{
- if (CurEnv->e_message != NULL)
+ char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
+
+ if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
sm_free(CurEnv->e_message);
- CurEnv->e_message = newstr(errtxt);
+ CurEnv->e_message = nmsg;
}
/* determine exit status if not already set */
@@ -119,7 +199,7 @@ syserr(fmt, va_alist)
else
ExitStat = EX_OSERR;
if (tTd(54, 1))
- dprintf("syserr: ExitStat = %d\n", ExitStat);
+ sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
}
pw = sm_getpwuid(RealUid);
@@ -128,7 +208,7 @@ syserr(fmt, va_alist)
else
{
user = ubuf;
- snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid);
+ (void) sm_snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid);
}
if (LogLevel > 0)
@@ -157,13 +237,13 @@ syserr(fmt, va_alist)
#ifdef ESTALE
case ESTALE:
#endif /* ESTALE */
- printopenfds(TRUE);
- mci_dump_all(TRUE);
+ printopenfds(true);
+ mci_dump_all(true);
break;
}
if (panic)
{
-#ifdef XLA
+#if XLA
xla_all_end();
#endif /* XLA */
sync_queue_time();
@@ -173,21 +253,21 @@ syserr(fmt, va_alist)
}
errno = 0;
if (QuickAbort)
- longjmp(TopFrame, 2);
+ sm_exc_raisenew_x(&EtypeQuickAbort, 2);
}
- /*
+/*
** USRERR -- Signal user error.
**
** This is much like syserr except it is for user errors.
**
** Parameters:
** fmt -- the format string. If it does not begin with
-** a three-digit SMTP reply code, 501 is assumed.
-** (others) -- printf strings
+** a three-digit SMTP reply code, 550 is assumed.
+** (others) -- sm_io_printf strings
**
** Returns:
** none
-** Through TopFrame if QuickAbort is set.
+** Raises E:mta.quickabort if QuickAbort is set.
**
** Side Effects:
** increments Errors.
@@ -205,7 +285,7 @@ usrerr(fmt, va_alist)
{
char *enhsc;
char *errtxt;
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
if (fmt[0] == '5' || fmt[0] == '6')
enhsc = "5.0.0";
@@ -215,9 +295,9 @@ usrerr(fmt, va_alist)
enhsc = "2.0.0";
else
enhsc = NULL;
- VA_START(fmt);
- errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap);
- VA_END;
+ SM_VA_START(ap, fmt);
+ errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
+ SM_VA_END(ap);
if (SuprErrs)
return;
@@ -234,32 +314,33 @@ usrerr(fmt, va_alist)
case '5':
case '6':
- if (CurEnv->e_message != NULL)
+ if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
sm_free(CurEnv->e_message);
if (MsgBuf[0] == '6')
{
char buf[MAXLINE];
- snprintf(buf, sizeof buf, "Postmaster warning: %.*s",
- (int) sizeof buf - 22, errtxt);
- CurEnv->e_message = newstr(buf);
+ (void) sm_snprintf(buf, sizeof buf,
+ "Postmaster warning: %.*s",
+ (int) sizeof buf - 22, errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, buf);
}
else
{
- CurEnv->e_message = newstr(errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
}
break;
}
puterrmsg(MsgBuf);
-
if (LogLevel > 3 && LogUsrErrs)
sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
-
if (QuickAbort)
- longjmp(TopFrame, 1);
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
- /*
+/*
** USRERRENH -- Signal user error.
**
** Same as usrerr but with enhanced status code.
@@ -267,12 +348,12 @@ usrerr(fmt, va_alist)
** Parameters:
** enhsc -- the enhanced status code.
** fmt -- the format string. If it does not begin with
-** a three-digit SMTP reply code, 501 is assumed.
-** (others) -- printf strings
+** a three-digit SMTP reply code, 550 is assumed.
+** (others) -- sm_io_printf strings
**
** Returns:
** none
-** Through TopFrame if QuickAbort is set.
+** Raises E:mta.quickabort if QuickAbort is set.
**
** Side Effects:
** increments Errors.
@@ -290,7 +371,7 @@ usrerrenh(enhsc, fmt, va_alist)
#endif /* __STDC__ */
{
char *errtxt;
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
if (enhsc == NULL || *enhsc == '\0')
{
@@ -301,9 +382,9 @@ usrerrenh(enhsc, fmt, va_alist)
else if (fmt[0] == '2')
enhsc = "2.0.0";
}
- VA_START(fmt);
- errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap);
- VA_END;
+ SM_VA_START(ap, fmt);
+ errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
+ SM_VA_END(ap);
if (SuprErrs)
return;
@@ -320,38 +401,39 @@ usrerrenh(enhsc, fmt, va_alist)
case '5':
case '6':
- if (CurEnv->e_message != NULL)
+ if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
sm_free(CurEnv->e_message);
if (MsgBuf[0] == '6')
{
char buf[MAXLINE];
- snprintf(buf, sizeof buf, "Postmaster warning: %.*s",
- (int) sizeof buf - 22, errtxt);
- CurEnv->e_message = newstr(buf);
+ (void) sm_snprintf(buf, sizeof buf,
+ "Postmaster warning: %.*s",
+ (int) sizeof buf - 22, errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, buf);
}
else
{
- CurEnv->e_message = newstr(errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
}
break;
}
puterrmsg(MsgBuf);
-
if (LogLevel > 3 && LogUsrErrs)
sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
-
if (QuickAbort)
- longjmp(TopFrame, 1);
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
- /*
+/*
** MESSAGE -- print message (not necessarily an error)
**
** Parameters:
-** msg -- the message (printf fmt) -- it can begin with
+** msg -- the message (sm_io_printf fmt) -- it can begin with
** an SMTP reply code. If not, 050 is assumed.
-** (others) -- printf arguments
+** (others) -- sm_io_printf arguments
**
** Returns:
** none
@@ -371,13 +453,13 @@ message(msg, va_alist)
#endif /* __STDC__ */
{
char *errtxt;
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
errno = 0;
- VA_START(msg);
+ SM_VA_START(ap, msg);
errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
- VA_END;
- putoutmsg(MsgBuf, FALSE, FALSE);
+ SM_VA_END(ap);
+ putoutmsg(MsgBuf, false, false);
/* save this message for mailq printing */
switch (MsgBuf[0])
@@ -389,22 +471,23 @@ message(msg, va_alist)
/* FALLTHROUGH */
case '5':
- if (CurEnv->e_message != NULL)
+ if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
sm_free(CurEnv->e_message);
- CurEnv->e_message = newstr(errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
break;
}
}
- /*
+/*
** NMESSAGE -- print message (not necessarily an error)
**
** Just like "message" except it never puts the to... tag on.
**
** Parameters:
-** msg -- the message (printf fmt) -- if it begins
+** msg -- the message (sm_io_printf fmt) -- if it begins
** with a three digit SMTP reply code, that is used,
** otherwise 050 is assumed.
-** (others) -- printf arguments
+** (others) -- sm_io_printf arguments
**
** Returns:
** none
@@ -424,14 +507,14 @@ nmessage(msg, va_alist)
#endif /* __STDC__ */
{
char *errtxt;
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
errno = 0;
- VA_START(msg);
+ SM_VA_START(ap, msg);
errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
(char *) NULL, 0, msg, ap);
- VA_END;
- putoutmsg(MsgBuf, FALSE, FALSE);
+ SM_VA_END(ap);
+ putoutmsg(MsgBuf, false, false);
/* save this message for mailq printing */
switch (MsgBuf[0])
@@ -443,20 +526,21 @@ nmessage(msg, va_alist)
/* FALLTHROUGH */
case '5':
- if (CurEnv->e_message != NULL)
+ if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
sm_free(CurEnv->e_message);
- CurEnv->e_message = newstr(errtxt);
+ CurEnv->e_message =
+ sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
break;
}
}
- /*
+/*
** PUTOUTMSG -- output error message to transcript and channel
**
** Parameters:
** msg -- message to output (in SMTP format).
-** holdmsg -- if TRUE, don't output a copy of the message to
+** holdmsg -- if true, don't output a copy of the message to
** our output channel.
-** heldmsg -- if TRUE, this is a previously held message;
+** heldmsg -- if true, this is a previously held message;
** don't log it to the transcript file.
**
** Returns:
@@ -479,7 +563,7 @@ putoutmsg(msg, holdmsg, heldmsg)
/* display for debugging */
if (tTd(54, 8))
- dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
+ sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
heldmsg ? " (held)" : "");
/* map warnings to something SMTP can handle */
@@ -491,12 +575,13 @@ putoutmsg(msg, holdmsg, heldmsg)
/* output to transcript if serious */
if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
strchr("45", msg[0]) != NULL)
- fprintf(CurEnv->e_xfp, "%s\n", msg);
+ (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
+ msg);
- if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+ if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
sm_syslog(LOG_INFO, CurEnv->e_id,
- "--> %s%s",
- msg, holdmsg ? " (held)" : "");
+ "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
+ heldmsg ? " (held)" : "");
if (msgcode == '8')
msg[0] = '0';
@@ -510,11 +595,11 @@ putoutmsg(msg, holdmsg, heldmsg)
msg[0] = msgcode;
if (HeldMessageBuf[0] == '5' && msgcode == '4')
return;
- snprintf(HeldMessageBuf, sizeof HeldMessageBuf, "%s", msg);
+ (void) sm_strlcpy(HeldMessageBuf, msg, sizeof HeldMessageBuf);
return;
}
- (void) fflush(stdout);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
if (OutChannel == NULL)
return;
@@ -535,15 +620,21 @@ putoutmsg(msg, holdmsg, heldmsg)
/* if DisConnected, OutChannel now points to the transcript */
if (!DisConnected &&
(OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
- fprintf(OutChannel, "%s\r\n", msg);
+ (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
+ msg);
else
- fprintf(OutChannel, "%s\n", errtxt);
+ (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
+ errtxt);
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> %s\n", (int) getpid(),
- (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : errtxt);
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> %s\n", (int) CurrentPid,
+ (OpMode == MD_SMTP || OpMode == MD_DAEMON)
+ ? msg : errtxt);
+#if !PIPELINING
+ /* XXX can't flush here for SMTP pipelining */
if (msg[3] == ' ')
- (void) fflush(OutChannel);
- if (!ferror(OutChannel) || DisConnected)
+ (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
+ if (!sm_io_error(OutChannel) || DisConnected)
return;
/*
@@ -552,19 +643,20 @@ putoutmsg(msg, holdmsg, heldmsg)
** rude servers don't read result.
*/
- if (InChannel == NULL || feof(InChannel) || ferror(InChannel) ||
- strncmp(msg, "221", 3) == 0)
+ if (InChannel == NULL || sm_io_eof(InChannel) ||
+ sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
return;
/* can't call syserr, 'cause we are using MsgBuf */
- HoldErrs = TRUE;
+ HoldErrs = true;
if (LogLevel > 0)
sm_syslog(LOG_CRIT, CurEnv->e_id,
"SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
- CurHostName == NULL ? "NO-HOST" : CurHostName,
- shortenstring(msg, MAXSHORTSTR), errstring(errno));
+ CURHOSTNAME,
+ shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
+#endif /* !PIPELINING */
}
- /*
+/*
** PUTERRMSG -- like putoutmsg, but does special processing for error messages
**
** Parameters:
@@ -584,11 +676,11 @@ puterrmsg(msg)
char msgcode = msg[0];
/* output the message as usual */
- putoutmsg(msg, HoldErrs, FALSE);
+ putoutmsg(msg, HoldErrs, false);
/* be careful about multiple error messages */
if (OnlyOneError)
- HoldErrs = TRUE;
+ HoldErrs = true;
/* signal the error */
Errors++;
@@ -607,7 +699,7 @@ puterrmsg(msg)
CurEnv->e_flags |= EF_FATALERRS;
}
}
- /*
+/*
** ISENHSC -- check whether a string contains an enhanced status code
**
** Parameters:
@@ -646,7 +738,7 @@ isenhsc(s, delim)
return 0;
return l + h;
}
- /*
+/*
** EXTENHSC -- check and extract an enhanced status code
**
** Parameters:
@@ -663,6 +755,7 @@ isenhsc(s, delim)
** Side Effects:
** fills e with enhanced status code.
*/
+
int
extenhsc(s, delim, e)
const char *s;
@@ -699,7 +792,7 @@ extenhsc(s, delim, e)
e[l + h] = '\0';
return l + h;
}
- /*
+/*
** FMTMSG -- format a message into buffer.
**
** Parameters:
@@ -726,7 +819,7 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
const char *enhsc;
int eno;
const char *fmt;
- va_list ap;
+ SM_VA_LOCAL_DECL
{
char del;
int l;
@@ -743,7 +836,15 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
del = '-';
else
del = ' ';
- (void) snprintf(eb, spaceleft, "%3.3s%c", num, del);
+#if _FFR_SOFT_BOUNCE
+ if (SoftBounce && num[0] == '5')
+ {
+ /* replace 5 by 4 */
+ (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
+ }
+ else
+#endif /* _FFR_SOFT_BOUNCE */
+ (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
eb += 4;
spaceleft -= 4;
@@ -751,7 +852,7 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
{
/* copy enh.status code including trailing blank */
l++;
- (void) strlcpy(eb, fmt, l + 1);
+ (void) sm_strlcpy(eb, fmt, l + 1);
eb += l;
spaceleft -= l;
fmt += l;
@@ -759,19 +860,26 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
{
/* copy enh.status code */
- (void) strlcpy(eb, enhsc, l + 1);
+ (void) sm_strlcpy(eb, enhsc, l + 1);
eb[l] = ' ';
eb[++l] = '\0';
eb += l;
spaceleft -= l;
}
+#if _FFR_SOFT_BOUNCE
+ if (SoftBounce && eb[-l] == '5')
+ {
+ /* replace 5 by 4 */
+ eb[-l] = '4';
+ }
+#endif /* _FFR_SOFT_BOUNCE */
errtxt = eb;
/* output the file name and line number */
if (FileName != NULL)
{
- (void) snprintf(eb, spaceleft, "%s: line %d: ",
- shortenstring(FileName, 83), LineNumber);
+ (void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
+ shortenstring(FileName, 83), LineNumber);
eb += (l = strlen(eb));
spaceleft -= l;
}
@@ -798,26 +906,26 @@ fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
strncmp(num, "550", 3) == 0 ||
strncmp(num, "553", 3) == 0))
{
- (void) snprintf(eb, spaceleft, "%s... ",
- shortenstring(to, MAXSHORTSTR));
+ (void) sm_strlcpyn(eb, spaceleft, 2,
+ shortenstring(to, MAXSHORTSTR), "... ");
spaceleft -= strlen(eb);
while (*eb != '\0')
*eb++ &= 0177;
}
/* output the message */
- (void) vsnprintf(eb, spaceleft, fmt, ap);
+ (void) sm_vsnprintf(eb, spaceleft, fmt, ap);
spaceleft -= strlen(eb);
while (*eb != '\0')
*eb++ &= 0177;
/* output the error code, if any */
if (eno != 0)
- (void) snprintf(eb, spaceleft, ": %s", errstring(eno));
+ (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
return errtxt;
}
- /*
+/*
** BUFFER_ERRORS -- arrange to buffer future error messages
**
** Parameters:
@@ -831,9 +939,9 @@ void
buffer_errors()
{
HeldMessageBuf[0] = '\0';
- HoldErrs = TRUE;
+ HoldErrs = true;
}
- /*
+/*
** FLUSH_ERRORS -- flush the held error message buffer
**
** Parameters:
@@ -849,12 +957,12 @@ flush_errors(print)
bool print;
{
if (print && HeldMessageBuf[0] != '\0')
- putoutmsg(HeldMessageBuf, FALSE, TRUE);
+ putoutmsg(HeldMessageBuf, false, true);
HeldMessageBuf[0] = '\0';
- HoldErrs = FALSE;
+ HoldErrs = false;
}
- /*
-** ERRSTRING -- return string description of error code
+/*
+** SM_ERRSTRING -- return string description of error code
**
** Parameters:
** errnum -- the error number to translate
@@ -867,12 +975,16 @@ flush_errors(print)
*/
const char *
-errstring(errnum)
+sm_errstring(errnum)
int errnum;
{
char *dnsmsg;
char *bp;
static char buf[MAXLINE];
+#if HASSTRERROR
+ char *err;
+ char errbuf[30];
+#endif /* HASSTRERROR */
#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
extern char *sys_errlist[];
extern int sys_nerr;
@@ -887,58 +999,67 @@ errstring(errnum)
dnsmsg = NULL;
switch (errnum)
{
-#if defined(DAEMON) && defined(ETIMEDOUT)
case ETIMEDOUT:
case ECONNRESET:
bp = buf;
-# if HASSTRERROR
- snprintf(bp, SPACELEFT(buf, bp), "%s", strerror(errnum));
-# else /* HASSTRERROR */
+#if HASSTRERROR
+ err = strerror(errnum);
+ if (err == NULL)
+ {
+ (void) sm_snprintf(errbuf, sizeof errbuf,
+ "Error %d", errnum);
+ err = errbuf;
+ }
+ (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
+#else /* HASSTRERROR */
if (errnum >= 0 && errnum < sys_nerr)
- snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]);
+ (void) sm_strlcpy(bp, sys_errlist[errnum],
+ SPACELEFT(buf, bp));
else
- snprintf(bp, SPACELEFT(buf, bp), "Error %d", errnum);
-# endif /* HASSTRERROR */
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ "Error %d", errnum);
+#endif /* HASSTRERROR */
bp += strlen(bp);
if (CurHostName != NULL)
{
if (errnum == ETIMEDOUT)
{
- snprintf(bp, SPACELEFT(buf, bp), " with ");
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ " with ");
bp += strlen(bp);
}
else
{
bp = buf;
- snprintf(bp, SPACELEFT(buf, bp),
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
"Connection reset by ");
bp += strlen(bp);
}
- snprintf(bp, SPACELEFT(buf, bp), "%s",
- shortenstring(CurHostName, MAXSHORTSTR));
+ (void) sm_strlcpy(bp,
+ shortenstring(CurHostName, MAXSHORTSTR),
+ SPACELEFT(buf, bp));
bp += strlen(buf);
}
if (SmtpPhase != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), " during %s",
- SmtpPhase);
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ " during %s", SmtpPhase);
}
return buf;
case EHOSTDOWN:
if (CurHostName == NULL)
break;
- (void) snprintf(buf, sizeof buf, "Host %s is down",
+ (void) sm_snprintf(buf, sizeof buf, "Host %s is down",
shortenstring(CurHostName, MAXSHORTSTR));
return buf;
case ECONNREFUSED:
if (CurHostName == NULL)
break;
- (void) snprintf(buf, sizeof buf, "Connection refused by %s",
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Connection refused by ",
shortenstring(CurHostName, MAXSHORTSTR));
return buf;
-#endif /* defined(DAEMON) && defined(ETIMEDOUT) */
#if NAMED_BIND
case HOST_NOT_FOUND + E_DNSBASE:
@@ -1006,29 +1127,35 @@ errstring(errnum)
if (dnsmsg != NULL)
{
bp = buf;
- bp += strlcpy(bp, "Name server: ", sizeof buf);
+ bp += sm_strlcpy(bp, "Name server: ", sizeof buf);
if (CurHostName != NULL)
{
- snprintf(bp, SPACELEFT(buf, bp), "%s: ",
- shortenstring(CurHostName, MAXSHORTSTR));
+ (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
+ shortenstring(CurHostName, MAXSHORTSTR), ": ");
bp += strlen(bp);
}
- snprintf(bp, SPACELEFT(buf, bp), "%s", dnsmsg);
+ (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
return buf;
}
-#ifdef LDAPMAP
+#if LDAPMAP
if (errnum >= E_LDAPBASE)
return ldap_err2string(errnum - E_LDAPBASE);
#endif /* LDAPMAP */
#if HASSTRERROR
- return strerror(errnum);
+ err = strerror(errnum);
+ if (err == NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
+ return buf;
+ }
+ return err;
#else /* HASSTRERROR */
if (errnum > 0 && errnum < sys_nerr)
return sys_errlist[errnum];
- (void) snprintf(buf, sizeof buf, "Error %d", errnum);
+ (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
return buf;
#endif /* HASSTRERROR */
}
diff --git a/contrib/sendmail/src/headers.c b/contrib/sendmail/src/headers.c
index 4c6259d..a56266e 100644
--- a/contrib/sendmail/src/headers.c
+++ b/contrib/sendmail/src/headers.c
@@ -11,12 +11,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: headers.c,v 8.203.4.13 2001/05/03 17:24:06 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: headers.c,v 8.266 2001/10/12 01:50:12 gshapiro Exp $")
+
static size_t fix_mime_header __P((char *));
static int priencode __P((char *));
static void put_vanilla_header __P((HDR *, char *, MCI *));
@@ -44,7 +42,7 @@ setupheaders()
s->s_header.hi_ruleset = NULL;
}
}
- /*
+/*
** CHOMPHEADER -- process and save a header line.
**
** Called by collect, readcf, and readqf to deal with header lines.
@@ -65,32 +63,32 @@ setupheaders()
static struct hdrinfo NormalHeader = { NULL, 0, NULL };
-u_long
+unsigned long
chompheader(line, pflag, hdrp, e)
char *line;
int pflag;
HDR **hdrp;
register ENVELOPE *e;
{
- u_char mid = '\0';
+ unsigned char mid = '\0';
register char *p;
register HDR *h;
HDR **hp;
char *fname;
char *fvalue;
- bool cond = FALSE;
+ bool cond = false;
bool dropfrom;
bool headeronly;
STAB *s;
struct hdrinfo *hi;
- bool nullheader = FALSE;
+ bool nullheader = false;
BITMAP256 mopts;
if (tTd(31, 6))
{
- dprintf("chompheader: ");
+ sm_dprintf("chompheader: ");
xputs(line);
- dprintf("\n");
+ sm_dprintf("\n");
}
headeronly = hdrp != NULL;
@@ -122,7 +120,7 @@ chompheader(line, pflag, hdrp, e)
goto hse;
}
- mid = (u_char) *p++;
+ mid = (unsigned char) *p++;
/* catch ?$abc? */
if (*p != '\0')
@@ -140,7 +138,7 @@ chompheader(line, pflag, hdrp, e)
goto hse;
}
- mid = (u_char)macid(p, NULL);
+ mid = (unsigned char) macid(p);
if (bitset(0200, mid))
p += strlen(macname(mid)) + 2;
else
@@ -152,7 +150,6 @@ chompheader(line, pflag, hdrp, e)
*q = '?';
goto hse;
}
-
}
else
{
@@ -165,7 +162,7 @@ chompheader(line, pflag, hdrp, e)
}
setbitn(bitidx(*p), mopts);
- cond = TRUE;
+ cond = true;
p++;
}
}
@@ -196,7 +193,7 @@ hse:
while (isascii(*p) && isspace(*p))
p++;
if (*p == '\0')
- nullheader = TRUE;
+ nullheader = true;
/* security scan: long field names are end-of-header */
if (strlen(fname) > 100)
@@ -222,6 +219,12 @@ hse:
{
*endp = '\0';
s = stab(fname, ST_HEADER, ST_ENTER);
+ if (LogLevel > 9 &&
+ s->s_header.hi_ruleset != NULL)
+ sm_syslog(LOG_WARNING, NOQID,
+ "Warning: redefined ruleset for header=%s, old=%s, new=%s",
+ fname,
+ s->s_header.hi_ruleset, p);
s->s_header.hi_ruleset = newstr(p);
if (!strc)
s->s_header.hi_flags |= H_STRIPCOMM;
@@ -240,11 +243,12 @@ hse:
if (tTd(31, 9))
{
if (s == NULL)
- dprintf("no header flags match\n");
+ sm_dprintf("no header flags match\n");
else
- dprintf("header match, flags=%lx, ruleset=%s\n",
- hi->hi_flags,
- hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
+ sm_dprintf("header match, flags=%lx, ruleset=%s\n",
+ hi->hi_flags,
+ hi->hi_ruleset == NULL ? "<NULL>"
+ : hi->hi_ruleset);
}
/* see if this is a resent message */
@@ -281,7 +285,7 @@ hse:
if (bitset(pflag, CHHDR_CHECK))
{
- bool stripcom = FALSE;
+ bool stripcom = false;
char *rs;
/* no ruleset? look for default */
@@ -300,52 +304,70 @@ hse:
stripcom = bitset(hi->hi_flags, H_STRIPCOMM);
if (rs != NULL)
{
- int l;
+ int l, k;
char qval[MAXNAME];
- char hlen[16];
- char *sp, *dp;
- dp = qval;
l = 0;
- dp[l++] = '"';
- for (sp = fvalue; *sp != '\0' && l < MAXNAME - 3; sp++)
+ qval[l++] = '"';
+
+ /* - 3 to avoid problems with " at the end */
+ for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
{
- switch(*sp)
+ switch (fvalue[k])
{
+ /* XXX other control chars? */
case '\011': /* ht */
case '\012': /* nl */
case '\013': /* vt */
case '\014': /* np */
case '\015': /* cr */
- dp[l++] = ' ';
+ qval[l++] = ' ';
break;
case '"':
- dp[l++] = '\\';
+ qval[l++] = '\\';
/* FALLTHROUGH */
default:
- dp[l++] = *sp;
+ qval[l++] = fvalue[k];
break;
}
}
- dp[l++] = '"';
- dp[l++] = '\0';
- l = strlen(fvalue);
- snprintf(hlen, sizeof hlen, "%d", l);
- define(macid("{hdrlen}", NULL), newstr(hlen), e);
- if (l >= MAXNAME)
+ qval[l++] = '"';
+ qval[l] = '\0';
+ k += strlen(fvalue + k);
+ if (k >= MAXNAME)
{
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"Warning: truncated header '%s' before check with '%s' len=%d max=%d",
- fname, rs, l, MAXNAME - 1);
+ fname, rs, k, MAXNAME - 1);
}
- if ((sp = macvalue(macid("{currHeader}", NULL), e)) !=
- NULL)
- sm_free(sp);
- define(macid("{currHeader}", NULL), newstr(qval), e);
- define(macid("{hdr_name}", NULL), newstr(fname), e);
- (void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4,
- NULL);
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{currHeader}"), qval);
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{hdr_name}"), fname);
+
+ (void) sm_snprintf(qval, sizeof qval, "%d", k);
+ macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
+#if _FFR_HDR_TYPE
+ /*
+ ** XXX: h isn't set yet
+ ** If we really want to be precise then we have
+ ** to lookup the header (see below).
+ ** It's probably not worth the effort.
+ */
+
+ if (bitset(H_FROM, h->h_flags))
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "h s");
+ else if (bitset(H_RCPT, h->h_flags))
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "h r");
+ else
+#endif /* _FFR_HDR_TYPE */
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "h");
+ (void) rscheck(rs, fvalue, NULL, e, stripcom, true, 3,
+ NULL, e->e_id);
}
}
@@ -355,16 +377,16 @@ hse:
** insert the full name information in all circumstances.
*/
- dropfrom = FALSE;
+ dropfrom = false;
p = "resent-from";
if (!bitset(EF_RESENT, e->e_flags))
p += 7;
if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
- !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
+ !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
{
if (tTd(31, 2))
{
- dprintf("comparing header from (%s) against default (%s or %s)\n",
+ sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
fvalue, e->e_from.q_paddr, e->e_from.q_user);
}
if (e->e_from.q_paddr != NULL &&
@@ -372,13 +394,13 @@ hse:
bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
(strcmp(fvalue, e->e_from.q_paddr) == 0 ||
strcmp(fvalue, e->e_from.q_user) == 0))
- dropfrom = TRUE;
+ dropfrom = true;
}
/* delete default value for this header */
for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
{
- if (strcasecmp(fname, h->h_field) == 0 &&
+ if (sm_strcasecmp(fname, h->h_field) == 0 &&
!bitset(H_USER, h->h_flags) &&
!bitset(H_FORCE, h->h_flags))
{
@@ -397,7 +419,7 @@ hse:
if (!cond)
{
/* copy conditions from default case */
- memmove((char *)mopts, (char *)h->h_mflags,
+ memmove((char *) mopts, (char *) h->h_mflags,
sizeof mopts);
}
h->h_macro = mid;
@@ -405,9 +427,9 @@ hse:
}
/* create a new node */
- h = (HDR *) xalloc(sizeof *h);
- h->h_field = newstr(fname);
- h->h_value = newstr(fvalue);
+ h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
+ h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
+ h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
h->h_link = NULL;
memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
h->h_macro = mid;
@@ -435,7 +457,7 @@ hse:
return h->h_flags;
}
- /*
+/*
** ADDHEADER -- add a header entry to the end of the queue.
**
** This bypasses the special checking of chompheader.
@@ -444,7 +466,7 @@ hse:
** field -- the name of the header field.
** value -- the value of the field.
** flags -- flags to add to h_flags.
-** hdrlist -- an indirect pointer to the header structure list.
+** e -- envelope.
**
** Returns:
** none.
@@ -454,15 +476,16 @@ hse:
*/
void
-addheader(field, value, flags, hdrlist)
+addheader(field, value, flags, e)
char *field;
char *value;
int flags;
- HDR **hdrlist;
+ ENVELOPE *e;
{
register HDR *h;
STAB *s;
HDR **hp;
+ HDR **hdrlist = &e->e_header;
/* find info struct */
s = stab(field, ST_HEADER, ST_FIND);
@@ -470,14 +493,14 @@ addheader(field, value, flags, hdrlist)
/* find current place in list -- keep back pointer? */
for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
{
- if (strcasecmp(field, h->h_field) == 0)
+ if (sm_strcasecmp(field, h->h_field) == 0)
break;
}
/* allocate space for new header */
- h = (HDR *) xalloc(sizeof *h);
+ h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
h->h_field = field;
- h->h_value = newstr(value);
+ h->h_value = sm_rpool_strdup_x(e->e_rpool, value);
h->h_link = *hp;
h->h_flags = flags;
if (s != NULL)
@@ -486,7 +509,7 @@ addheader(field, value, flags, hdrlist)
h->h_macro = '\0';
*hp = h;
}
- /*
+/*
** HVALUE -- return value of a header.
**
** Only "real" fields (i.e., ones that have not been supplied
@@ -514,12 +537,12 @@ hvalue(field, header)
for (h = header; h != NULL; h = h->h_link)
{
if (!bitset(H_DEFAULT, h->h_flags) &&
- strcasecmp(h->h_field, field) == 0)
+ sm_strcasecmp(h->h_field, field) == 0)
return h->h_value;
}
return NULL;
}
- /*
+/*
** ISHEADER -- predicate telling if argument is a header.
**
** A line is a header if it has a single word followed by
@@ -535,8 +558,8 @@ hvalue(field, header)
** h -- string to check for possible headerness.
**
** Returns:
-** TRUE if h is a header.
-** FALSE otherwise.
+** true if h is a header.
+** false otherwise.
**
** Side Effects:
** none.
@@ -549,13 +572,13 @@ isheader(h)
register char *s = h;
if (s[0] == '-' && s[1] == '-')
- return FALSE;
+ return false;
while (*s > ' ' && *s != ':' && *s != '\0')
s++;
if (h == s)
- return FALSE;
+ return false;
/* following technically violates RFC822 */
while (isascii(*s) && isspace(*s))
@@ -563,7 +586,7 @@ isheader(h)
return (*s == ':');
}
- /*
+/*
** EATHEADER -- run through the stored header and extract info.
**
** Parameters:
@@ -572,6 +595,7 @@ isheader(h)
** message priority). This should not be set
** when reading a queue file because some info
** needed to compute the priority is wrong.
+** log -- call logsender()?
**
** Returns:
** none.
@@ -579,30 +603,29 @@ isheader(h)
** Side Effects:
** Sets a bunch of global variables from information
** in the collected header.
-** Aborts the message if the hop count is exceeded.
*/
void
-eatheader(e, full)
+eatheader(e, full, log)
register ENVELOPE *e;
bool full;
+ bool log;
{
register HDR *h;
register char *p;
int hopcnt = 0;
- char *msgid;
char buf[MAXLINE];
/*
** Set up macros for possible expansion in headers.
*/
- define('f', e->e_sender, e);
- define('g', e->e_sender, e);
+ macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
+ macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
- define('u', e->e_origrcpt, e);
+ macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
else
- define('u', NULL, e);
+ macdefine(&e->e_macro, A_PERM, 'u', NULL);
/* full name of from person */
p = hvalue("full-name", e->e_header);
@@ -615,22 +638,23 @@ eatheader(e, full)
** as a comment so crackaddr() doesn't destroy
** the name portion of the address.
*/
- p = addquotes(p);
+
+ p = addquotes(p, e->e_rpool);
}
- define('x', p, e);
+ macdefine(&e->e_macro, A_PERM, 'x', p);
}
if (tTd(32, 1))
- dprintf("----- collected header -----\n");
- msgid = NULL;
+ sm_dprintf("----- collected header -----\n");
+ e->e_msgid = NULL;
for (h = e->e_header; h != NULL; h = h->h_link)
{
if (tTd(32, 1))
- dprintf("%s: ", h->h_field);
+ sm_dprintf("%s: ", h->h_field);
if (h->h_value == NULL)
{
if (tTd(32, 1))
- dprintf("<NULL>\n");
+ sm_dprintf("<NULL>\n");
continue;
}
@@ -640,24 +664,24 @@ eatheader(e, full)
{
if (tTd(32, 1))
{
- dprintf("(");
+ sm_dprintf("(");
xputs(h->h_value);
- dprintf(") ");
+ sm_dprintf(") ");
}
expand(h->h_value, buf, sizeof buf, e);
if (buf[0] != '\0')
{
if (bitset(H_FROM, h->h_flags))
- expand(crackaddr(buf), buf, sizeof buf, e);
- h->h_value = newstr(buf);
+ expand(crackaddr(buf), buf, sizeof buf,
+ e);
+ h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
h->h_flags &= ~H_DEFAULT;
}
}
-
if (tTd(32, 1))
{
xputs(h->h_value);
- dprintf("\n");
+ sm_dprintf("\n");
}
/* count the number of times it has been processed */
@@ -667,14 +691,15 @@ eatheader(e, full)
/* send to this person if we so desire */
if (GrabTo && bitset(H_RCPT, h->h_flags) &&
!bitset(H_DEFAULT, h->h_flags) &&
- (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
+ (!bitset(EF_RESENT, e->e_flags) ||
+ bitset(H_RESENT, h->h_flags)))
{
#if 0
int saveflags = e->e_flags;
#endif /* 0 */
- (void) sendtolist(h->h_value, NULLADDR,
- &e->e_sendqueue, 0, e);
+ (void) sendtolist(denlstring(h->h_value, true, false),
+ NULLADDR, &e->e_sendqueue, 0, e);
#if 0
/*
@@ -692,15 +717,15 @@ eatheader(e, full)
p = "resent-message-id";
if (!bitset(EF_RESENT, e->e_flags))
p += 7;
- if (strcasecmp(h->h_field, p) == 0)
+ if (sm_strcasecmp(h->h_field, p) == 0)
{
- msgid = h->h_value;
- while (isascii(*msgid) && isspace(*msgid))
- msgid++;
+ e->e_msgid = h->h_value;
+ while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
+ e->e_msgid++;
}
}
if (tTd(32, 1))
- dprintf("----------------------------\n");
+ sm_dprintf("----------------------------\n");
/* if we are just verifying (that is, sendmail -t -bv), drop out now */
if (OpMode == MD_VERIFY)
@@ -708,7 +733,11 @@ eatheader(e, full)
/* store hop count */
if (hopcnt > e->e_hopcount)
+ {
e->e_hopcount = hopcnt;
+ (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
+ macdefine(&e->e_macro, A_TEMP, 'c', buf);
+ }
/* message priority */
p = hvalue("precedence", e->e_header);
@@ -730,11 +759,11 @@ eatheader(e, full)
if (p != NULL)
{
/* (this should be in the configuration file) */
- if (strcasecmp(p, "urgent") == 0)
+ if (sm_strcasecmp(p, "urgent") == 0)
e->e_timeoutclass = TOC_URGENT;
- else if (strcasecmp(p, "normal") == 0)
+ else if (sm_strcasecmp(p, "normal") == 0)
e->e_timeoutclass = TOC_NORMAL;
- else if (strcasecmp(p, "non-urgent") == 0)
+ else if (sm_strcasecmp(p, "non-urgent") == 0)
e->e_timeoutclass = TOC_NONURGENT;
}
@@ -743,11 +772,11 @@ eatheader(e, full)
if (p == NULL)
p = hvalue("date", e->e_header);
if (p != NULL)
- define('a', p, e);
+ macdefine(&e->e_macro, A_PERM, 'a', p);
/* check to see if this is a MIME message */
if ((e->e_bodytype != NULL &&
- strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
+ sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
hvalue("MIME-Version", e->e_header) != NULL)
{
e->e_flags |= EF_IS_MIME;
@@ -785,9 +814,9 @@ eatheader(e, full)
if (hi->hi_field != NULL)
{
if (tTd(32, 2))
- dprintf("eatheader: setsender(*%s == %s)\n",
+ sm_dprintf("eatheader: setsender(*%s == %s)\n",
hi->hi_field, p);
- setsender(p, e, NULL, '\0', TRUE);
+ setsender(p, e, NULL, '\0', true);
}
}
@@ -795,11 +824,13 @@ eatheader(e, full)
** Log collection information.
*/
- if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
- logsender(e, msgid);
- e->e_flags &= ~EF_LOGSENDER;
+ if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
+ {
+ logsender(e, e->e_msgid);
+ e->e_flags &= ~EF_LOGSENDER;
+ }
}
- /*
+/*
** LOGSENDER -- log sender information
**
** Parameters:
@@ -824,6 +855,7 @@ logsender(e, msgid)
char mbuf[MAXNAME + 1];
/* don't allow newlines in the message-id */
+ /* XXX do we still need this? sm_syslog() replaces control chars */
if (msgid != NULL)
{
l = strlen(msgid);
@@ -848,70 +880,59 @@ logsender(e, msgid)
else
{
name = hbuf;
- (void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
+ (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
if (RealHostAddr.sa.sa_family != 0)
{
p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
- anynet_ntoa(&RealHostAddr));
+ (void) sm_snprintf(p, SPACELEFT(hbuf, p),
+ " (%.100s)",
+ anynet_ntoa(&RealHostAddr));
}
}
/* some versions of syslog only take 5 printf args */
#if (SYSLOG_BUFSIZE) >= 256
sbp = sbuf;
- snprintf(sbp, SPACELEFT(sbuf, sbp),
- "from=%.200s, size=%ld, class=%d, nrcpts=%d",
- e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
- e->e_msgsize, e->e_class, e->e_nrcpts);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ "from=%.200s, size=%ld, class=%d, nrcpts=%d",
+ e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
+ e->e_msgsize, e->e_class, e->e_nrcpts);
sbp += strlen(sbp);
if (msgid != NULL)
{
- snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ ", msgid=%.100s", mbuf);
sbp += strlen(sbp);
}
if (e->e_bodytype != NULL)
{
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
- e->e_bodytype);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ ", bodytype=%.20s", e->e_bodytype);
sbp += strlen(sbp);
}
p = macvalue('r', e);
if (p != NULL)
{
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
- sbp += strlen(sbp);
- }
- p = macvalue(macid("{daemon_name}", NULL), e);
- if (p != NULL)
- {
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ ", proto=%.20s", p);
sbp += strlen(sbp);
}
-# if SASL
- p = macvalue(macid("{auth_type}", NULL), e);
+ p = macvalue(macid("{daemon_name}"), e);
if (p != NULL)
{
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ ", daemon=%.20s", p);
sbp += strlen(sbp);
}
- p = macvalue(macid("{auth_author}", NULL), e);
- if (p != NULL)
- {
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p);
- sbp += strlen(sbp);
- }
-# endif /* SASL */
- sm_syslog(LOG_INFO, e->e_id,
- "%.850s, relay=%.100s",
- sbuf, name);
+ sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%.100s", sbuf, name);
#else /* (SYSLOG_BUFSIZE) >= 256 */
sm_syslog(LOG_INFO, e->e_id,
"from=%s",
e->e_from.q_paddr == NULL ? "<NONE>"
- : shortenstring(e->e_from.q_paddr, 83));
+ : shortenstring(e->e_from.q_paddr,
+ 83));
sm_syslog(LOG_INFO, e->e_id,
"size=%ld, class=%ld, nrcpts=%d",
e->e_msgsize, e->e_class, e->e_nrcpts);
@@ -923,20 +944,22 @@ logsender(e, msgid)
*sbp = '\0';
if (e->e_bodytype != NULL)
{
- snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ "bodytype=%.20s, ", e->e_bodytype);
sbp += strlen(sbp);
}
p = macvalue('r', e);
if (p != NULL)
{
- snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
+ (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
+ "proto=%.20s, ", p);
sbp += strlen(sbp);
}
sm_syslog(LOG_INFO, e->e_id,
"%.400srelay=%.100s", sbuf, name);
#endif /* (SYSLOG_BUFSIZE) >= 256 */
}
- /*
+/*
** PRIENCODE -- encode external priority names into internal values.
**
** Parameters:
@@ -957,14 +980,14 @@ priencode(p)
for (i = 0; i < NumPriorities; i++)
{
- if (strcasecmp(p, Priorities[i].pri_name) == 0)
+ if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
return Priorities[i].pri_val;
}
/* unknown priority */
return 0;
}
- /*
+/*
** CRACKADDR -- parse an address and turn it into a macro
**
** This doesn't actually parse the address -- it just extracts
@@ -1006,10 +1029,10 @@ crackaddr(addr)
bool qmode;
bool realqmode;
bool skipping;
- bool putgmac = FALSE;
- bool quoteit = FALSE;
- bool gotangle = FALSE;
- bool gotcolon = FALSE;
+ bool putgmac = false;
+ bool quoteit = false;
+ bool gotangle = false;
+ bool gotcolon = false;
register char *bp;
char *buflim;
char *bufhead;
@@ -1017,7 +1040,7 @@ crackaddr(addr)
static char buf[MAXNAME + 1];
if (tTd(33, 1))
- dprintf("crackaddr(%s)\n", addr);
+ sm_dprintf("crackaddr(%s)\n", addr);
/* strip leading spaces */
while (*addr != '\0' && isascii(*addr) && isspace(*addr))
@@ -1033,7 +1056,7 @@ crackaddr(addr)
p = addrhead = addr;
copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
bracklev = 0;
- qmode = realqmode = FALSE;
+ qmode = realqmode = false;
while ((c = *p++) != '\0')
{
@@ -1053,7 +1076,7 @@ crackaddr(addr)
{
/* arrange to quote the address */
if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
+ quoteit = true;
if ((c = *p++) == '\0')
{
@@ -1138,7 +1161,7 @@ crackaddr(addr)
if (*p == ':' || *p == '.')
{
if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
+ quoteit = true;
if (copylev > 0 && !skipping)
{
*bp++ = c;
@@ -1148,7 +1171,7 @@ crackaddr(addr)
goto putg;
}
- gotcolon = TRUE;
+ gotcolon = true;
bp = bufhead;
if (quoteit)
@@ -1189,7 +1212,7 @@ crackaddr(addr)
while (isascii(*p) && isspace(*p) && bp < buflim)
*bp++ = *p++;
copylev = 0;
- putgmac = quoteit = FALSE;
+ putgmac = quoteit = false;
bufhead = bp;
addrhead = p;
continue;
@@ -1212,7 +1235,7 @@ crackaddr(addr)
*/
if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
+ quoteit = true;
}
/* check for angle brackets */
@@ -1222,8 +1245,8 @@ crackaddr(addr)
/* assume first of two angles is bogus */
if (gotangle)
- quoteit = TRUE;
- gotangle = TRUE;
+ quoteit = true;
+ gotangle = true;
/* oops -- have to change our mind */
anglelev = 1;
@@ -1265,7 +1288,7 @@ crackaddr(addr)
*bp++ = c;
}
copylev = 0;
- putgmac = quoteit = FALSE;
+ putgmac = quoteit = false;
continue;
}
@@ -1285,7 +1308,7 @@ crackaddr(addr)
/* syntax error: unmatched > */
if (copylev > 0)
bp--;
- quoteit = TRUE;
+ quoteit = true;
continue;
}
if (copylev++ <= 0)
@@ -1301,7 +1324,7 @@ crackaddr(addr)
*bp++ = ' ';
*bp++ = MACROEXPAND;
*bp++ = 'g';
- putgmac = TRUE;
+ putgmac = true;
}
}
@@ -1316,14 +1339,14 @@ crackaddr(addr)
if (tTd(33, 1))
{
- dprintf("crackaddr=>`");
+ sm_dprintf("crackaddr=>`");
xputs(buf);
- dprintf("'\n");
+ sm_dprintf("'\n");
}
return buf;
}
- /*
+/*
** PUTHEADER -- put the header part of a message from the in-core copy
**
** Parameters:
@@ -1339,13 +1362,6 @@ crackaddr(addr)
** none.
*/
-/*
- * Macro for fast max (not available in e.g. DG/UX, 386/ix).
- */
-#ifndef MAX
-# define MAX(a,b) (((a)>(b))?(a):(b))
-#endif /* ! MAX */
-
void
putheader(mci, hdr, e, flags)
register MCI *mci;
@@ -1354,11 +1370,11 @@ putheader(mci, hdr, e, flags)
int flags;
{
register HDR *h;
- char buf[MAX(MAXLINE,BUFSIZ)];
+ char buf[SM_MAX(MAXLINE,BUFSIZ)];
char obuf[MAXLINE];
if (tTd(34, 1))
- dprintf("--- putheader, mailer = %s ---\n",
+ sm_dprintf("--- putheader, mailer = %s ---\n",
mci->mci_mailer->m_name);
/*
@@ -1373,10 +1389,11 @@ putheader(mci, hdr, e, flags)
for (h = hdr; h != NULL; h = h->h_link)
{
register char *p = h->h_value;
+ char *q;
if (tTd(34, 11))
{
- dprintf(" %s: ", h->h_field);
+ sm_dprintf(" %s: ", h->h_field);
xputs(p);
}
@@ -1387,7 +1404,7 @@ putheader(mci, hdr, e, flags)
/* heuristic shortening of MIME fields to avoid MUA overflows */
if (MaxMimeFieldLength > 0 &&
wordinclass(h->h_field,
- macid("{checkMIMEFieldHeaders}", NULL)))
+ macid("{checkMIMEFieldHeaders}")))
{
size_t len;
@@ -1398,15 +1415,15 @@ putheader(mci, hdr, e, flags)
"Truncated MIME %s header due to field size (length = %ld) (possible attack)",
h->h_field, (unsigned long) len);
if (tTd(34, 11))
- dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
- h->h_field,
- (unsigned long) len);
+ sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
+ h->h_field,
+ (unsigned long) len);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
- macid("{checkMIMETextHeaders}", NULL)))
+ macid("{checkMIMETextHeaders}")))
{
size_t len;
@@ -1418,15 +1435,15 @@ putheader(mci, hdr, e, flags)
"Truncated long MIME %s header (length = %ld) (possible attack)",
h->h_field, (unsigned long) len);
if (tTd(34, 11))
- dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
- h->h_field,
- (unsigned long) len);
+ sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
+ h->h_field,
+ (unsigned long) len);
}
}
if (MaxMimeHeaderLength > 0 &&
wordinclass(h->h_field,
- macid("{checkMIMEHeaders}", NULL)))
+ macid("{checkMIMEHeaders}")))
{
size_t len;
@@ -1438,9 +1455,9 @@ putheader(mci, hdr, e, flags)
"Truncated long MIME %s header (length = %ld) (possible attack)",
h->h_field, (unsigned long) len);
if (tTd(34, 11))
- dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
- h->h_field,
- (unsigned long) len);
+ sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
+ h->h_field,
+ (unsigned long) len);
}
}
@@ -1450,20 +1467,21 @@ putheader(mci, hdr, e, flags)
** MIME. If converting, add a new CTE header in
** mime8to7().
*/
+
if (bitset(H_CTE, h->h_flags) &&
bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
mci->mci_flags) &&
!bitset(M87F_NO8TO7, flags))
{
if (tTd(34, 11))
- dprintf(" (skipped (content-transfer-encoding))\n");
+ sm_dprintf(" (skipped (content-transfer-encoding))\n");
continue;
}
if (bitset(MCIF_INMIME, mci->mci_flags))
{
if (tTd(34, 11))
- dprintf("\n");
+ sm_dprintf("\n");
put_vanilla_header(h, p, mci);
continue;
}
@@ -1471,10 +1489,11 @@ putheader(mci, hdr, e, flags)
if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
!bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
(h->h_macro == '\0' ||
- macvalue(bitidx(h->h_macro), e) == NULL))
+ (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
+ *q == '\0'))
{
if (tTd(34, 11))
- dprintf(" (skipped)\n");
+ sm_dprintf(" (skipped)\n");
continue;
}
@@ -1482,7 +1501,7 @@ putheader(mci, hdr, e, flags)
if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
{
if (tTd(34, 11))
- dprintf(" (skipped (resent))\n");
+ sm_dprintf(" (skipped (resent))\n");
continue;
}
@@ -1491,7 +1510,7 @@ putheader(mci, hdr, e, flags)
(RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
{
if (tTd(34, 11))
- dprintf(" (skipped (receipt))\n");
+ sm_dprintf(" (skipped (receipt))\n");
continue;
}
@@ -1504,7 +1523,7 @@ putheader(mci, hdr, e, flags)
if (*p == '\0')
{
if (tTd(34, 11))
- dprintf(" (skipped -- null value)\n");
+ sm_dprintf(" (skipped -- null value)\n");
continue;
}
}
@@ -1515,20 +1534,20 @@ putheader(mci, hdr, e, flags)
if (bitset(EF_DELETE_BCC, e->e_flags))
{
if (tTd(34, 11))
- dprintf(" (skipped -- bcc)\n");
+ sm_dprintf(" (skipped -- bcc)\n");
}
else
{
/* no other recipient headers: truncate value */
- (void) snprintf(obuf, sizeof obuf, "%s:",
- h->h_field);
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2,
+ h->h_field, ":");
putline(obuf, mci);
}
continue;
}
if (tTd(34, 11))
- dprintf("\n");
+ sm_dprintf("\n");
if (bitset(H_FROM|H_RCPT, h->h_flags))
{
@@ -1536,7 +1555,7 @@ putheader(mci, hdr, e, flags)
bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
if (bitset(H_FROM, h->h_flags))
- oldstyle = FALSE;
+ oldstyle = false;
commaize(h, p, oldstyle, mci, e);
}
else
@@ -1561,9 +1580,9 @@ putheader(mci, hdr, e, flags)
putline("MIME-Version: 1.0", mci);
if (hvalue("Content-Type", e->e_header) == NULL)
{
- snprintf(obuf, sizeof obuf,
- "Content-Type: text/plain; charset=%s",
- defcharset(e));
+ (void) sm_snprintf(obuf, sizeof obuf,
+ "Content-Type: text/plain; charset=%s",
+ defcharset(e));
putline(obuf, mci);
}
if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
@@ -1571,7 +1590,7 @@ putheader(mci, hdr, e, flags)
}
#endif /* MIME8TO7 */
}
- /*
+/*
** PUT_VANILLA_HEADER -- output a fairly ordinary header
**
** Parameters:
@@ -1597,34 +1616,34 @@ put_vanilla_header(h, v, mci)
putflags = PXLF_HEADER;
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
- (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
+ (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
obp = obuf + strlen(obuf);
while ((nlp = strchr(v, '\n')) != NULL)
{
int l;
l = nlp - v;
- if (SPACELEFT(obuf, obp) - 1 < (size_t)l)
+ if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
l = SPACELEFT(obuf, obp) - 1;
- snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
+ (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
putxline(obuf, strlen(obuf), mci, putflags);
v += l + 1;
obp = obuf;
if (*v != ' ' && *v != '\t')
*obp++ = ' ';
}
- snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
- (int) sizeof obuf - (obp - obuf) - 1, v);
+ (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
+ (int) (SPACELEFT(obuf, obp) - 1), v);
putxline(obuf, strlen(obuf), mci, putflags);
}
- /*
+/*
** COMMAIZE -- output a header field, making a comma-translated list.
**
** Parameters:
** h -- the header field to output.
** p -- the value to put in it.
-** oldstyle -- TRUE if this is an old style header.
+** oldstyle -- true if this is an old style header.
** mci -- the connection information.
** e -- the envelope containing the message.
**
@@ -1646,7 +1665,7 @@ commaize(h, p, oldstyle, mci, e)
register char *obp;
int opos;
int omax;
- bool firstone = TRUE;
+ bool firstone = true;
int putflags = PXLF_HEADER;
char obuf[MAXLINE + 3];
@@ -1656,13 +1675,14 @@ commaize(h, p, oldstyle, mci, e)
*/
if (tTd(14, 2))
- dprintf("commaize(%s: %s)\n", h->h_field, p);
+ sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
putflags |= PXLF_STRIP8BIT;
obp = obuf;
- (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
+ (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
+ h->h_field);
opos = strlen(h->h_field) + 2;
if (opos > 202)
opos = 202;
@@ -1713,7 +1733,7 @@ commaize(h, p, oldstyle, mci, e)
p = oldp;
break;
}
- p += *p == '@' ? 1 : 2;
+ ++p;
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
}
@@ -1738,7 +1758,7 @@ commaize(h, p, oldstyle, mci, e)
{
char *q;
- q = udbsender(name);
+ q = udbsender(name, e->e_rpool);
if (q != NULL)
name = q;
}
@@ -1750,14 +1770,14 @@ commaize(h, p, oldstyle, mci, e)
*p = savechar;
continue;
}
- name = denlstring(name, FALSE, TRUE);
+ name = denlstring(name, false, true);
/*
** record data progress so DNS timeouts
** don't cause DATA timeouts
*/
- DataProgress = TRUE;
+ DataProgress = true;
/* output the name with nice formatting */
opos += strlen(name);
@@ -1765,35 +1785,36 @@ commaize(h, p, oldstyle, mci, e)
opos += 2;
if (opos > omax && !firstone)
{
- snprintf(obp, SPACELEFT(obuf, obp), ",\n");
+ (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
putxline(obuf, strlen(obuf), mci, putflags);
obp = obuf;
- (void) strlcpy(obp, " ", sizeof obp);
+ (void) sm_strlcpy(obp, " ", sizeof obp);
opos = strlen(obp);
obp += opos;
opos += strlen(name);
}
else if (!firstone)
{
- snprintf(obp, SPACELEFT(obuf, obp), ", ");
+ (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
obp += 2;
}
while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
*obp++ = c;
- firstone = FALSE;
+ firstone = false;
*p = savechar;
}
*obp = '\0';
putxline(obuf, strlen(obuf), mci, putflags);
}
- /*
+/*
** COPYHEADER -- copy header list
**
** This routine is the equivalent of newstr for header lists
**
** Parameters:
** header -- list of header structures to copy.
+** rpool -- resource pool, or NULL
**
** Returns:
** a copy of 'header'.
@@ -1803,8 +1824,9 @@ commaize(h, p, oldstyle, mci, e)
*/
HDR *
-copyheader(header)
+copyheader(header, rpool)
register HDR *header;
+ SM_RPOOL_T *rpool;
{
register HDR *newhdr;
HDR *ret;
@@ -1812,7 +1834,7 @@ copyheader(header)
while (header != NULL)
{
- newhdr = (HDR *) xalloc(sizeof *newhdr);
+ newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
STRUCTCOPY(*header, *newhdr);
*tail = newhdr;
tail = &newhdr->h_link;
@@ -1822,7 +1844,7 @@ copyheader(header)
return ret;
}
- /*
+/*
** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
**
** Run through all of the parameters of a MIME header and
diff --git a/contrib/sendmail/src/helpfile b/contrib/sendmail/src/helpfile
index 5731626..02e6138 100644
--- a/contrib/sendmail/src/helpfile
+++ b/contrib/sendmail/src/helpfile
@@ -11,7 +11,7 @@ cpyr By using this file, you agree to the terms and conditions set
cpyr forth in the LICENSE file which can be found at the top level of
cpyr the sendmail distribution.
cpyr
-cpyr $$Id: helpfile,v 8.31.16.4 2000/09/17 14:21:00 ca Exp $$
+cpyr $$Id: helpfile,v 8.38 2000/10/15 17:18:44 ca Exp $$
cpyr
smtp This is sendmail version $v
smtp Topics:
@@ -39,7 +39,6 @@ ehlo TURN Turn the operation around [RFC821]
ehlo 8BITMIME Use 8-bit data [RFC1652]
ehlo SIZE Message size declaration [RFC1870]
ehlo VERB Verbose [Allman]
-ehlo ONEX One message transaction only [Allman]
ehlo CHUNKING Chunking [RFC1830]
ehlo BINARYMIME Binary MIME [RFC1830]
ehlo PIPELINING Command Pipelining [RFC1854]
@@ -47,8 +46,8 @@ ehlo DSN Delivery Status Notification [RFC1891]
ehlo ETRN Remote Message Queue Starting [RFC1985]
ehlo STARTTLS Secure SMTP [RFC2487]
ehlo AUTH Authentication [RFC2554]
-ehlo XUSR Initial (user) submission [Allman]
ehlo ENHANCEDSTATUSCODES Enhanced status codes [RFC2034]
+ehlo DELIVERBY Deliver By [RFC2852]
mail MAIL FROM: <sender> [ <parameters> ]
mail Specifies the sender. Parameters are ESMTP extensions.
mail See "HELP DSN" for details.
@@ -134,3 +133,4 @@ control help This message.
control restart Restart sendmail.
control shutdown Shutdown sendmail.
control status Show sendmail status.
+control memdump Dump allocated memory list.
diff --git a/contrib/sendmail/src/macro.c b/contrib/sendmail/src/macro.c
index 70e18e4..fc7a2c2 100644
--- a/contrib/sendmail/src/macro.c
+++ b/contrib/sendmail/src/macro.c
@@ -11,19 +11,89 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: macro.c,v 8.40.16.9 2001/02/22 01:16:55 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: macro.c,v 8.86 2001/09/11 04:05:14 gshapiro Exp $")
+
#if MAXMACROID != (BITMAPBITS - 1)
ERROR Read the comment in conf.h
#endif /* MAXMACROID != (BITMAPBITS - 1) */
-char *MacroName[MAXMACROID + 1]; /* macro id to name table */
-int NextMacroId = 0240; /* codes for long named macros */
+static char *MacroName[MAXMACROID + 1]; /* macro id to name table */
+int NextMacroId = 0240; /* codes for long named macros */
+
+/*
+** INITMACROS -- initialize the macro system
+**
+** This just involves defining some macros that are actually
+** used internally as metasymbols to be themselves.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** initializes several macros to be themselves.
+*/
+
+struct metamac MetaMacros[] =
+{
+ /* LHS pattern matching characters */
+ { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
+ { '=', MATCHCLASS }, { '~', MATCHNCLASS },
+
+ /* these are RHS metasymbols */
+ { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
+ { '>', CALLSUBR },
+
+ /* the conditional operations */
+ { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
+
+ /* the hostname lookup characters */
+ { '[', HOSTBEGIN }, { ']', HOSTEND },
+ { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
+
+ /* miscellaneous control characters */
+ { '&', MACRODEXPAND },
+
+ { '\0', '\0' }
+};
+
+#define MACBINDING(name, mid) \
+ stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
+ MacroName[mid] = name;
+void
+initmacros(e)
+ register ENVELOPE *e;
+{
+ register struct metamac *m;
+ register int c;
+ char buf[5];
+
+ for (m = MetaMacros; m->metaname != '\0'; m++)
+ {
+ buf[0] = m->metaval;
+ buf[1] = '\0';
+ macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
+ }
+ buf[0] = MATCHREPL;
+ buf[2] = '\0';
+ for (c = '0'; c <= '9'; c++)
+ {
+ buf[1] = c;
+ macdefine(&e->e_macro, A_TEMP, c, buf);
+ }
+
+ /* set defaults for some macros sendmail will use later */
+ macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
+
+ /* set up external names for some internal macros */
+ MACBINDING("opMode", MID_OPMODE);
+ /*XXX should probably add equivalents for all short macros here XXX*/
+}
/*
** EXPAND -- macro expand a string using $x escapes.
**
@@ -50,8 +120,8 @@ expand(s, buf, bufsize, e)
register char *xp;
register char *q;
bool skipping; /* set if conditionally skipping output */
- bool recurse = FALSE; /* set if recursion required */
- int i;
+ bool recurse; /* set if recursion required */
+ size_t i;
int skiplev; /* skipping nesting level */
int iflev; /* if nesting level */
char xbuf[MACBUFSIZE];
@@ -59,12 +129,13 @@ expand(s, buf, bufsize, e)
if (tTd(35, 24))
{
- dprintf("expand(");
+ sm_dprintf("expand(");
xputs(s);
- dprintf(")\n");
+ sm_dprintf(")\n");
}
- skipping = FALSE;
+ recurse = false;
+ skipping = false;
skiplev = 0;
iflev = 0;
if (s == NULL)
@@ -98,17 +169,17 @@ expand(s, buf, bufsize, e)
case CONDELSE: /* change state of skipping */
if (iflev == 0)
- break;
+ break; /* XXX: error */
if (skiplev == 0)
skipping = !skipping;
continue;
case CONDFI: /* stop skipping */
if (iflev == 0)
- break;
+ break; /* XXX: error */
iflev--;
if (skiplev == 0)
- skipping = FALSE;
+ skipping = false;
if (skipping)
skiplev--;
continue;
@@ -142,7 +213,7 @@ expand(s, buf, bufsize, e)
{
/* check for any sendmail metacharacters */
if ((c & 0340) == 0200)
- recurse = TRUE;
+ recurse = true;
*xp++ = c;
}
}
@@ -151,9 +222,9 @@ expand(s, buf, bufsize, e)
if (tTd(35, 24))
{
- dprintf("expand ==> ");
+ sm_dprintf("expand ==> ");
xputs(xbuf);
- dprintf("\n");
+ sm_dprintf("\n");
}
/* recurse as appropriate */
@@ -172,109 +243,155 @@ expand(s, buf, bufsize, e)
/* copy results out */
i = xp - xbuf;
- if ((size_t)i >= bufsize)
+ if (i >= bufsize)
i = bufsize - 1;
memmove(buf, xbuf, i);
buf[i] = '\0';
}
- /*
-** DEFINE -- define a macro.
+
+/*
+** MACDEFINE -- bind a macro name to a value
**
-** this would be better done using a #define macro.
+** Set a macro to a value, with fancy storage management.
+** macdefine will make a copy of the value, if required,
+** and will ensure that the storage for the previous value
+** is not leaked.
**
** Parameters:
-** n -- the macro name.
-** v -- the macro value.
-** e -- the envelope to store the definition in.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** e->e_macro[n] is defined.
-**
-** Notes:
-** There is one macro for each ASCII character,
-** although they are not all used. The currently
-** defined macros are:
-**
-** $a date in ARPANET format (preferring the Date: line
-** of the message)
-** $b the current date (as opposed to the date as found
-** the message) in ARPANET format
-** $c hop count
-** $d (current) date in UNIX (ctime) format
-** $e the SMTP entry message+
-** $f raw from address
-** $g translated from address
-** $h to host
-** $i queue id
-** $j official SMTP hostname, used in messages+
-** $k UUCP node name
-** $l UNIX-style from line+
-** $m The domain part of our full name.
-** $n name of sendmail ("MAILER-DAEMON" on local
-** net typically)+
-** $o delimiters ("operators") for address tokens+
-** (set via OperatorChars option in V6 or later
-** sendmail.cf files)
-** $p my process id in decimal
-** $q the string that becomes an address -- this is
-** normally used to combine $g & $x.
-** $r protocol used to talk to sender
-** $s sender's host name
-** $t the current time in seconds since 1/1/1970
-** $u to user
-** $v version number of sendmail
-** $w our host name (if it can be determined)
-** $x signature (full name) of from person
-** $y the tty id of our terminal
-** $z home directory of to person
-** $_ RFC1413 authenticated sender address
-**
-** Macros marked with + must be defined in the
-** configuration file and are used internally, but
-** are not set.
-**
-** There are also some macros that can be used
-** arbitrarily to make the configuration file
-** cleaner. In general all upper-case letters
-** are available.
+** mac -- Macro table.
+** vclass -- storage class of 'value', ignored if value==NULL.
+** A_HEAP means that the value was allocated by
+** malloc, and that macdefine owns the storage.
+** A_TEMP means that value points to temporary storage,
+** and thus macdefine needs to make a copy.
+** A_PERM means that value points to storage that
+** will remain allocated and unchanged for
+** at least the lifetime of mac. Use A_PERM if:
+** -- value == NULL,
+** -- value points to a string literal,
+** -- value was allocated from mac->mac_rpool
+** or (in the case of an envelope macro)
+** from e->e_rpool,
+** -- in the case of an envelope macro,
+** value is a string member of the envelope
+** such as e->e_sender.
+** id -- Macro id. This is a single character macro name
+** such as 'g', or a value returned by macid().
+** value -- Macro value: either NULL, or a string.
*/
void
-define(n, v, e)
- int n;
- char *v;
- register ENVELOPE *e;
+#if SM_HEAP_CHECK
+macdefine_tagged(mac, vclass, id, value, file, line, grp)
+#else /* SM_HEAP_CHECK */
+macdefine(mac, vclass, id, value)
+#endif /* SM_HEAP_CHECK */
+ MACROS_T *mac;
+ ARGCLASS_T vclass;
+ int id;
+ char *value;
+#if SM_HEAP_CHECK
+ char *file;
+ int line;
+ int grp;
+#endif /* SM_HEAP_CHECK */
{
- int m;
+ char *newvalue;
+
+ if (id < 0 || id > MAXMACROID)
+ return;
- m = bitidx(n);
if (tTd(35, 9))
{
- dprintf("%sdefine(%s as ",
- (e->e_macro[m] == NULL) ? ""
- : "re", macname(n));
- xputs(v);
- dprintf(")\n");
+ sm_dprintf("%sdefine(%s as ",
+ mac->mac_table[id] == NULL ? "" : "re", macname(id));
+ xputs(value);
+ sm_dprintf(")\n");
+ }
+
+ if (mac->mac_rpool == NULL)
+ {
+ char *freeit = NULL;
+
+ if (mac->mac_table[id] != NULL &&
+ bitnset(id, mac->mac_allocated))
+ freeit = mac->mac_table[id];
+
+ if (value == NULL || vclass == A_HEAP)
+ {
+ sm_heap_checkptr_tagged(value, file, line);
+ newvalue = value;
+ clrbitn(id, mac->mac_allocated);
+ }
+ else
+ {
+ newvalue = sm_strdup_tagged_x(value, file, line, 0);
+ setbitn(id, mac->mac_allocated);
+ }
+ mac->mac_table[id] = newvalue;
+ if (freeit != NULL)
+ sm_free(freeit);
+ }
+ else
+ {
+ if (value == NULL || vclass == A_PERM)
+ newvalue = value;
+ else
+ newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
+ mac->mac_table[id] = newvalue;
+ if (vclass == A_HEAP)
+ sm_free(value);
}
- e->e_macro[m] = v;
#if _FFR_RESET_MACRO_GLOBALS
- switch (m)
+ switch (id)
{
case 'j':
- MyHostName = v;
+ PSTRSET(MyHostName, value);
break;
}
#endif /* _FFR_RESET_MACRO_GLOBALS */
}
- /*
+
+/*
+** MACSET -- set a named macro to a value (low level)
+**
+** No fancy storage management; the caller takes full responsibility.
+** Often used with macget; see also macdefine.
+**
+** Parameters:
+** mac -- Macro table.
+** i -- Macro name, specified as an integer offset.
+** value -- Macro value: either NULL, or a string.
+*/
+
+void
+macset(mac, i, value)
+ MACROS_T *mac;
+ int i;
+ char *value;
+{
+ if (i < 0 || i > MAXMACROID)
+ return;
+
+ if (tTd(35, 9))
+ {
+ sm_dprintf("macset(%s as ", macname(i));
+ xputs(value);
+ sm_dprintf(")\n");
+ }
+ mac->mac_table[i] = value;
+}
+
+/*
** MACVALUE -- return uninterpreted value of a macro.
**
+** Does fancy path searching.
+** The low level counterpart is macget.
+**
** Parameters:
** n -- the name of the macro.
+** e -- envelope in which to start looking for the macro.
**
** Returns:
** The value of n.
@@ -289,9 +406,16 @@ macvalue(n, e)
register ENVELOPE *e;
{
n = bitidx(n);
+ if (e != NULL && e->e_mci != NULL)
+ {
+ register char *p = e->e_mci->mci_macro.mac_table[n];
+
+ if (p != NULL)
+ return p;
+ }
while (e != NULL)
{
- register char *p = e->e_macro[n];
+ register char *p = e->e_macro.mac_table[n];
if (p != NULL)
return p;
@@ -299,9 +423,9 @@ macvalue(n, e)
break;
e = e->e_parent;
}
- return NULL;
+ return GlobalMacros.mac_table[n];
}
- /*
+/*
** MACNAME -- return the name of a macro given its internal id
**
** Parameter:
@@ -333,8 +457,8 @@ macname(n)
mbuf[1] = '\0';
return mbuf;
}
- /*
-** MACID -- return id of macro identified by its name
+/*
+** MACID_PARSE -- return id of macro identified by its name
**
** Parameters:
** p -- pointer to name string -- either a single
@@ -343,15 +467,16 @@ macname(n)
** after the name.
**
** Returns:
-** The internal id code for this macro. This will
-** fit into a single byte.
+** 0 -- An error was detected.
+** 1..255 -- The internal id code for this macro.
**
** Side Effects:
** If this is a new macro name, a new id is allocated.
+** On error, syserr is called.
*/
int
-macid(p, ep)
+macid_parse(p, ep)
register char *p;
char **ep;
{
@@ -361,9 +486,9 @@ macid(p, ep)
if (tTd(35, 14))
{
- dprintf("macid(");
+ sm_dprintf("macid(");
xputs(p);
- dprintf(") => ");
+ sm_dprintf(") => ");
}
if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
@@ -372,7 +497,7 @@ macid(p, ep)
if (ep != NULL)
*ep = p;
if (tTd(35, 14))
- dprintf("NULL\n");
+ sm_dprintf("NULL\n");
return 0;
}
if (*p != '{')
@@ -381,7 +506,7 @@ macid(p, ep)
if (ep != NULL)
*ep = p + 1;
if (tTd(35, 14))
- dprintf("%c\n", bitidx(*p));
+ sm_dprintf("%c\n", bitidx(*p));
return bitidx(*p);
}
bp = mbuf;
@@ -401,7 +526,7 @@ macid(p, ep)
else if (*p != '}')
{
syserr("Macro/class name ({%s}) too long (%d chars max)",
- mbuf, sizeof mbuf - 1);
+ mbuf, (int) (sizeof mbuf - 1));
}
else if (mbuf[1] == '\0')
{
@@ -420,7 +545,8 @@ macid(p, ep)
{
if (NextMacroId > MAXMACROID)
{
- syserr("Macro/class {%s}: too many long names", mbuf);
+ syserr("Macro/class {%s}: too many long names",
+ mbuf);
s->s_macro = -1;
}
else
@@ -437,14 +563,14 @@ macid(p, ep)
{
syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
if (tTd(35, 14))
- dprintf("NULL\n");
+ sm_dprintf("NULL\n");
return 0;
}
if (tTd(35, 14))
- dprintf("0x%x\n", mid);
+ sm_dprintf("0x%x\n", mid);
return mid;
}
- /*
+/*
** WORDINCLASS -- tell if a word is in a specific class
**
** Parameters:
@@ -452,8 +578,8 @@ macid(p, ep)
** cl -- the class name.
**
** Returns:
-** TRUE if str can be found in cl.
-** FALSE otherwise.
+** true if str can be found in cl.
+** false otherwise.
*/
bool
diff --git a/contrib/sendmail/src/mailq.1 b/contrib/sendmail/src/mailq.1
index ab13b55..fd83b03 100644
--- a/contrib/sendmail/src/mailq.1
+++ b/contrib/sendmail/src/mailq.1
@@ -9,9 +9,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: mailq.1,v 8.14.28.3 2000/12/14 23:08:15 gshapiro Exp $
+.\" $Id: mailq.1,v 8.18 2000/12/23 19:37:48 ca Exp $
.\"
-.TH MAILQ 1 "$Date: 2000/12/14 23:08:15 $"
+.TH MAILQ 1 "$Date: 2000/12/23 19:37:48 $"
.SH NAME
mailq
\- print the mail queue
@@ -58,6 +58,8 @@ indicating the ``controlling user'' information;
this shows who will own any programs that are executed
on behalf of this message
and the name of the alias this command expanded from, if any.
+Moreover, status messages for each recipient are printed
+if available.
.PP
The
.B mailq
diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c
index c09daa5..3d3f3cf 100644
--- a/contrib/sendmail/src/main.c
+++ b/contrib/sendmail/src/main.c
@@ -11,8 +11,13 @@
*
*/
+#define _DEFINE
+#include <sendmail.h>
+#include <sm/xtrap.h>
+#include <sm/signal.h>
+
#ifndef lint
-static char copyright[] =
+SM_UNUSED(static char copyright[]) =
"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\
@@ -20,28 +25,32 @@ static char copyright[] =
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
-#ifndef lint
-static char id[] = "@(#)$Id: main.c,v 8.485.4.65 2001/07/20 00:53:00 gshapiro Exp $";
-#endif /* ! lint */
-
-#define _DEFINE
-
-#include <sendmail.h>
+SM_RCSID("@(#)$Id: main.c,v 8.868 2001/12/29 04:54:38 ca Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
#endif /* NETINET || NETINET6 */
-static SIGFUNC_DECL intindebug __P((int));
-static SIGFUNC_DECL quiesce __P((int));
-#ifdef SIGUSR1
-static SIGFUNC_DECL sigusr1 __P((int));
-# endif /* SIGUSR1 */
-static SIGFUNC_DECL term_daemon __P((int));
+/* for getcfname() */
+#include <sendmail/pathnames.h>
+
+static SM_DEBUG_T
+DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
+ "@(#)$Debug: no_persistent_restart - don't restart, log only $");
+
static void dump_class __P((STAB *, int));
static void obsolete __P((char **));
static void testmodeline __P((char *, ENVELOPE *));
+static char *getextenv __P((const char *));
+static void sm_printoptions __P((char **));
+static SIGFUNC_DECL intindebug __P((int));
+static SIGFUNC_DECL sighup __P((int));
+static SIGFUNC_DECL sigpipe __P((int));
+static SIGFUNC_DECL sigterm __P((int));
+#ifdef SIGUSR1
+static SIGFUNC_DECL sigusr1 __P((int));
+#endif /* SIGUSR1 */
/*
** SENDMAIL -- Post mail to a set of destinations.
@@ -59,7 +68,7 @@ static void testmodeline __P((char *, ENVELOPE *));
**
** See the associated documentation for details.
**
-** Author:
+** Authors:
** Eric Allman, UCB/INGRES (until 10/81).
** Britton-Lee, Inc., purveyors of fine
** database computers (11/81 - 10/88).
@@ -71,31 +80,30 @@ static void testmodeline __P((char *, ENVELOPE *));
** The support of the my employers is gratefully acknowledged.
** Few of them (Britton-Lee in particular) have had
** anything to gain from my involvement in this project.
+**
+** Gregory Neil Shapiro,
+** Worcester Polytechnic Institute (until 3/98).
+** Sendmail, Inc. (3/98 - present).
+**
+** Claus Assmann,
+** Sendmail, Inc. (12/98 - present).
*/
-
-int NextMailer; /* "free" index into Mailer struct */
char *FullName; /* sender's full name */
ENVELOPE BlankEnvelope; /* a "blank" envelope */
static ENVELOPE MainEnvelope; /* the envelope around the basic letter */
ADDRESS NullAddress = /* a null address */
{ "", "", NULL, "" };
char *CommandLineArgs; /* command line args for pid file */
-bool Warn_Q_option = FALSE; /* warn about Q option use */
+bool Warn_Q_option = false; /* warn about Q option use */
static int MissingFds = 0; /* bit map of fds missing on startup */
+char *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */
#ifdef NGROUPS_MAX
GIDSET_T InitialGidSet[NGROUPS_MAX];
#endif /* NGROUPS_MAX */
-#if DAEMON && !SMTP
-ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR
-#endif /* DAEMON && !SMTP */
-#if SMTP && !QUEUE
-ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR
-#endif /* SMTP && !QUEUE */
-
-#define MAXCONFIGLEVEL 9 /* highest config version level known */
+#define MAXCONFIGLEVEL 10 /* highest config version level known */
#if SASL
static sasl_callback_t srvcallbacks[] =
@@ -104,10 +112,37 @@ static sasl_callback_t srvcallbacks[] =
{ SASL_CB_PROXY_POLICY, &proxy_policy, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
-
#endif /* SASL */
-int SubmitMode;
+unsigned int SubmitMode;
+int SyslogPrefixLen; /* estimated length of syslog prefix */
+#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */
+#ifndef SL_FUDGE
+# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */
+#endif /* ! SL_FUDGE */
+#define SLDLL 8 /* est. length of default syslog label */
+
+
+/* Some options are dangerous to allow users to use in non-submit mode */
+#define CHECK_AGAINST_OPMODE(cmd) \
+{ \
+ if (extraprivs && \
+ OpMode != MD_DELIVER && OpMode != MD_SMTP && \
+ OpMode != MD_VERIFY && OpMode != MD_TEST) \
+ { \
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
+ "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
+ (cmd)); \
+ break; \
+ } \
+ if (extraprivs && queuerun) \
+ { \
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
+ "WARNING: Ignoring submission mode -%c option with -q\n", \
+ (cmd)); \
+ break; \
+ } \
+}
int
main(argc, argv, envp)
@@ -123,32 +158,60 @@ main(argc, argv, envp)
register int i;
int j;
int dp;
- bool safecf = TRUE;
+ int fill_errno;
+ int qgrp = NOQGRP; /* queue group to process */
+ bool safecf = true;
BITMAP256 *p_flags = NULL; /* daemon flags */
- bool warn_C_flag = FALSE;
- bool auth = TRUE; /* whether to set e_auth_param */
+ bool warn_C_flag = false;
+ bool auth = true; /* whether to set e_auth_param */
char warn_f_flag = '\0';
- bool run_in_foreground = FALSE; /* -bD mode */
- static bool reenter = FALSE;
+ bool run_in_foreground = false; /* -bD mode */
+ bool queuerun = false, debug = false;
struct passwd *pw;
struct hostent *hp;
char *nullserver = NULL;
char *authinfo = NULL;
char *sysloglabel = NULL; /* label for syslog */
- bool forged;
+ char *conffile = NULL; /* name of .cf file */
+ char *queuegroup = NULL; /* queue group to process */
+#if _FFR_QUARANTINE
+ char *quarantining = NULL; /* quarantine queue items? */
+#endif /* _FFR_QUARANTINE */
+ bool extraprivs;
+ bool forged, negate;
+ bool queuepersistent = false; /* queue runner process runs forever */
+ bool foregroundqueue = false; /* queue run in foreground */
+ bool save_val; /* to save some bool var. */
+ int cftype; /* which cf file to use? */
+ static time_t starttime = 0; /* when was process started */
struct stat traf_st; /* for TrafficLog FIFO check */
+ char buf[MAXLINE];
char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
static char rnamebuf[MAXNAME]; /* holds RealUserName */
char *emptyenviron[1];
-# if STARTTLS
+#if STARTTLS
bool tls_ok;
-# endif /* STARTTLS */
+#endif /* STARTTLS */
QUEUE_CHAR *new;
+ ENVELOPE *e;
extern int DtableSize;
extern int optind;
extern int opterr;
extern char *optarg;
extern char **environ;
+#if SASL
+ extern void sm_sasl_init __P((void));
+#endif /* SASL */
+
+#if USE_ENVIRON
+ envp = environ;
+#endif /* USE_ENVIRON */
+
+ /* turn off profiling */
+ SM_PROF(0);
+
+ /* install default exception handler */
+ sm_exc_newthread(fatal_error);
/*
** Check to see if we reentered.
@@ -156,27 +219,27 @@ main(argc, argv, envp)
** were NULL when invoked.
*/
- if (reenter)
+ if (starttime != 0)
{
syserr("main: reentered!");
abort();
}
- reenter = TRUE;
+ starttime = curtime();
/* avoid null pointer dereferences */
TermEscape.te_rv_on = TermEscape.te_rv_off = "";
- /*
- ** Seed the random number generator.
- ** Used for queue file names, picking a queue directory, and
- ** MX randomization.
- */
+ RealUid = getuid();
+ RealGid = getgid();
- seed_random();
+ /* Check if sendmail is running with extra privs */
+ extraprivs = (RealUid != 0 &&
+ (geteuid() != getuid() || getegid() != getgid()));
- /* do machine-dependent initializations */
- init_md(argc, argv);
+ CurrentPid = getpid();
+ /* get whatever .cf file is right for the opmode */
+ cftype = SM_GET_RIGHT_CF;
/* in 4.4BSD, the table can be huge; impose a reasonable limit */
DtableSize = getdtsize();
@@ -188,39 +251,51 @@ main(argc, argv, envp)
** But also be sure that 0, 1, & 2 are open.
*/
+ /* reset errno and fill_errno; the latter is used way down below */
+ errno = fill_errno = 0;
fill_fd(STDIN_FILENO, NULL);
+ if (errno != 0)
+ fill_errno = errno;
fill_fd(STDOUT_FILENO, NULL);
+ if (errno != 0)
+ fill_errno = errno;
fill_fd(STDERR_FILENO, NULL);
+ if (errno != 0)
+ fill_errno = errno;
i = DtableSize;
while (--i > 0)
{
- if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
+ if (i != STDIN_FILENO && i != STDOUT_FILENO &&
+ i != STDERR_FILENO)
(void) close(i);
}
errno = 0;
#if LOG
+# ifndef SM_LOG_STR
+# define SM_LOG_STR "sendmail"
+# endif /* ! SM_LOG_STR */
# ifdef LOG_MAIL
- openlog("sendmail", LOG_PID, LOG_MAIL);
+ openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
# else /* LOG_MAIL */
- openlog("sendmail", LOG_PID);
+ openlog(SM_LOG_STR, LOG_PID);
# endif /* LOG_MAIL */
#endif /* LOG */
- if (MissingFds != 0)
- {
- char mbuf[MAXLINE];
+ /*
+ ** Seed the random number generator.
+ ** Used for queue file names, picking a queue directory, and
+ ** MX randomization.
+ */
- mbuf[0] = '\0';
- if (bitset(1 << STDIN_FILENO, MissingFds))
- (void) strlcat(mbuf, ", stdin", sizeof mbuf);
- if (bitset(1 << STDOUT_FILENO, MissingFds))
- (void) strlcat(mbuf, ", stdout", sizeof mbuf);
- if (bitset(1 << STDERR_FILENO, MissingFds))
- (void) strlcat(mbuf, ", stderr", sizeof mbuf);
- syserr("File descriptors missing on startup: %s", &mbuf[2]);
- }
+ seed_random();
+
+ /* do machine-dependent initializations */
+ init_md(argc, argv);
+
+
+ SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;
/* reset status from syserr() calls for missing file descriptors */
Errors = 0;
@@ -231,30 +306,32 @@ main(argc, argv, envp)
checkfd012("after openlog");
#endif /* XDEBUG */
- tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+ tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1");
#ifdef NGROUPS_MAX
/* save initial group set for future checks */
i = getgroups(NGROUPS_MAX, InitialGidSet);
- if (i == 0)
+ if (i <= 0)
+ {
InitialGidSet[0] = (GID_T) -1;
+ i = 0;
+ }
while (i < NGROUPS_MAX)
InitialGidSet[i++] = InitialGidSet[0];
#endif /* NGROUPS_MAX */
/* drop group id privileges (RunAsUser not yet set) */
- dp = drop_privileges(FALSE);
+ dp = drop_privileges(false);
setstat(dp);
-# ifdef SIGUSR1
+#ifdef SIGUSR1
/* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
- if (getuid() == 0 ||
- (getuid() == geteuid() && getgid() == getegid()))
+ if (extraprivs)
{
/* arrange to dump state on user-1 signal */
- (void) setsignal(SIGUSR1, sigusr1);
+ (void) sm_signal(SIGUSR1, sigusr1);
}
-# endif /* SIGUSR1 */
+#endif /* SIGUSR1 */
/* initialize for setproctitle */
initsetproctitle(argc, argv, envp);
@@ -267,49 +344,121 @@ main(argc, argv, envp)
*/
-#if defined(__osf__) || defined(_AIX3)
-# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x"
-#endif /* defined(__osf__) || defined(_AIX3) */
-#if defined(sony_news)
-# define OPTIONS "B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
-#endif /* defined(sony_news) */
-#ifndef OPTIONS
-# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
-#endif /* ! OPTIONS */
+ /* find initial opMode */
+ OpMode = MD_DELIVER;
+ av = argv;
+ p = strrchr(*av, '/');
+ if (p++ == NULL)
+ p = *av;
+ if (strcmp(p, "newaliases") == 0)
+ OpMode = MD_INITALIAS;
+ else if (strcmp(p, "mailq") == 0)
+ OpMode = MD_PRINT;
+ else if (strcmp(p, "smtpd") == 0)
+ OpMode = MD_DAEMON;
+ else if (strcmp(p, "hoststat") == 0)
+ OpMode = MD_HOSTSTAT;
+ else if (strcmp(p, "purgestat") == 0)
+ OpMode = MD_PURGESTAT;
+
+#if _FFR_QUARANTINE
+# if defined(__osf__) || defined(_AIX3)
+# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:xQ:"
+# endif /* defined(__osf__) || defined(_AIX3) */
+# if defined(sony_news)
+# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"
+# endif /* defined(sony_news) */
+# ifndef OPTIONS
+# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:"
+# endif /* ! OPTIONS */
+#else /* _FFR_QUARANTINE */
+# if defined(__osf__) || defined(_AIX3)
+# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:x"
+# endif /* defined(__osf__) || defined(_AIX3) */
+# if defined(sony_news)
+# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:"
+# endif /* defined(sony_news) */
+# ifndef OPTIONS
+# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:"
+# endif /* ! OPTIONS */
+#endif /* _FFR_QUARANTINE */
+
opterr = 0;
while ((j = getopt(argc, argv, OPTIONS)) != -1)
{
switch (j)
{
- case 'd':
- /* hack attack -- see if should use ANSI mode */
- if (strcmp(optarg, "ANSI") == 0)
+ case 'b': /* operations mode */
+ switch (j = *optarg)
{
- TermEscape.te_rv_on = "\033[7m";
- TermEscape.te_rv_off = "\033[0m";
+ case MD_DAEMON:
+ case MD_FGDAEMON:
+ case MD_SMTP:
+ case MD_INITALIAS:
+ case MD_DELIVER:
+ case MD_VERIFY:
+ case MD_TEST:
+ case MD_PRINT:
+ case MD_PRINTNQE:
+ case MD_HOSTSTAT:
+ case MD_PURGESTAT:
+ case MD_ARPAFTP:
+ OpMode = j;
break;
+
+ case MD_FREEZE:
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Frozen configurations unsupported\n");
+ return EX_USAGE;
+
+ default:
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Invalid operation mode %c\n",
+ j);
+ return EX_USAGE;
}
+ break;
+
+ case 'd':
+ debug = true;
tTflag(optarg);
- setbuf(stdout, (char *) NULL);
+ (void) sm_io_setvbuf(smioout, SM_TIME_DEFAULT,
+ (char *) NULL, SM_IO_NBF,
+ SM_IO_BUFSIZ);
break;
case 'G': /* relay (gateway) submission */
- SubmitMode |= SUBMIT_MTA;
+ SubmitMode = SUBMIT_MTA;
break;
case 'L':
- j = min(strlen(optarg), 24) + 1;
+ j = SM_MIN(strlen(optarg), 24) + 1;
sysloglabel = xalloc(j);
- (void) strlcpy(sysloglabel, optarg, j);
+ (void) sm_strlcpy(sysloglabel, optarg, j);
+ SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +
+ SL_FUDGE + j;
break;
- case 'U': /* initial (user) submission */
- SubmitMode |= SUBMIT_MSA;
+#if _FFR_QUARANTINE
+ case 'Q':
+#endif /* _FFR_QUARANTINE */
+ case 'q':
+ /* just check if it is there */
+ queuerun = true;
break;
}
}
opterr = 1;
+ /* Don't leak queue information via debug flags */
+ if (extraprivs && queuerun && debug)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "WARNING: Can not use -d with -q. Disabling debugging.\n");
+ sm_debug_setfile(NULL);
+ (void) memset(tTdvect, '\0', sizeof tTdvect);
+ }
+
#if LOG
if (sysloglabel != NULL)
{
@@ -342,56 +491,66 @@ main(argc, argv, envp)
*/
setdefaults(&BlankEnvelope);
+ initmacros(&BlankEnvelope);
- RealUid = getuid();
- RealGid = getgid();
+ /* reset macro */
+ set_op_mode(OpMode);
pw = sm_getpwuid(RealUid);
if (pw != NULL)
- (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
+ (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
else
- (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
- (int) RealUid);
+ (void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
+ (int) RealUid);
RealUserName = rnamebuf;
if (tTd(0, 101))
{
- dprintf("Version %s\n", Version);
- finis(FALSE, EX_OK);
+ sm_dprintf("Version %s\n", Version);
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
}
/*
- ** if running non-setuid binary as non-root, pretend
+ ** if running non-set-user-ID binary as non-root, pretend
** we are the RunAsUid
*/
if (RealUid != 0 && geteuid() == RealUid)
{
if (tTd(47, 1))
- dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n",
- (int)RealUid);
+ sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",
+ (int) RealUid);
RunAsUid = RealUid;
}
else if (geteuid() != 0)
RunAsUid = geteuid();
- if (RealUid != 0 && getegid() == RealGid)
+ EffGid = getegid();
+ if (RealUid != 0 && EffGid == RealGid)
RunAsGid = RealGid;
if (tTd(47, 5))
{
- dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
- (int)geteuid(), (int)getuid(),
- (int)getegid(), (int)getgid());
- dprintf("main: RunAsUser = %d:%d\n",
- (int)RunAsUid, (int)RunAsGid);
+ sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
+ (int) geteuid(), (int) getuid(),
+ (int) getegid(), (int) getgid());
+ sm_dprintf("main: RunAsUser = %d:%d\n",
+ (int) RunAsUid, (int) RunAsGid);
}
/* save command line arguments */
j = 0;
for (av = argv; *av != NULL; )
j += strlen(*av++) + 1;
+ if (j < 0 || j > SM_ARG_MAX)
+ {
+ syserr("!Arguments too long");
+
+ /* NOTREACHED */
+ return EX_USAGE;
+ }
SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
CommandLineArgs = xalloc(j);
p = CommandLineArgs;
@@ -402,7 +561,7 @@ main(argc, argv, envp)
SaveArgv[i++] = newstr(*av);
if (av != argv)
*p++ = ' ';
- (void) strlcpy(p, *av++, j);
+ (void) sm_strlcpy(p, *av++, j);
h = strlen(p);
p += h;
j -= h + 1;
@@ -411,60 +570,48 @@ main(argc, argv, envp)
if (tTd(0, 1))
{
- int ll;
extern char *CompileOptions[];
- dprintf("Version %s\n Compiled with:", Version);
- av = CompileOptions;
- ll = 7;
- while (*av != NULL)
- {
- if (ll + strlen(*av) > 63)
- {
- dprintf("\n");
- ll = 0;
- }
- if (ll == 0)
- dprintf("\t\t");
- else
- dprintf(" ");
- dprintf("%s", *av);
- ll += strlen(*av++) + 1;
- }
- dprintf("\n");
+ sm_dprintf("Version %s\n Compiled with:", Version);
+ sm_printoptions(CompileOptions);
}
if (tTd(0, 10))
{
- int ll;
extern char *OsCompileOptions[];
- dprintf(" OS Defines:");
- av = OsCompileOptions;
- ll = 7;
- while (*av != NULL)
- {
- if (ll + strlen(*av) > 63)
- {
- dprintf("\n");
- ll = 0;
- }
- if (ll == 0)
- dprintf("\t\t");
- else
- dprintf(" ");
- dprintf("%s", *av);
- ll += strlen(*av++) + 1;
- }
- dprintf("\n");
+ sm_dprintf(" OS Defines:");
+ sm_printoptions(OsCompileOptions);
#ifdef _PATH_UNIX
- dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
+ sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
#endif /* _PATH_UNIX */
- dprintf(" Def Conf file:\t%s\n", getcfname());
- dprintf(" Def Pid file:\t%s\n", PidFile);
+
+ sm_dprintf(" Conf file:\t%s (default for MSP)\n",
+ getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
+ conffile));
+ sm_dprintf(" Conf file:\t%s (default for MTA)\n",
+ getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,
+ conffile));
+ sm_dprintf(" Pid file:\t%s (default)\n", PidFile);
+ }
+
+ if (tTd(0, 12))
+ {
+ extern char *SmCompileOptions[];
+
+ sm_dprintf(" libsm Defines:");
+ sm_printoptions(SmCompileOptions);
+ }
+
+ if (tTd(0, 13))
+ {
+ extern char *FFRCompileOptions[];
+
+ sm_dprintf(" FFR Defines:");
+ sm_printoptions(FFRCompileOptions);
}
- InChannel = stdin;
- OutChannel = stdout;
+ InChannel = smioin;
+ OutChannel = smioout;
/* clear sendmail's environment */
ExternalEnviron = environ;
@@ -475,23 +622,26 @@ main(argc, argv, envp)
** restore any original TZ setting until TimeZoneSpec has been
** determined - or early log messages may get bogus time stamps
*/
+
if ((p = getextenv("TZ")) != NULL)
{
char *tz;
int tzlen;
+ /* XXX check for reasonable length? */
tzlen = strlen(p) + 4;
tz = xalloc(tzlen);
- (void) snprintf(tz, tzlen, "TZ=%s", p);
+ (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);
+
+ /* XXX check return code? */
(void) putenv(tz);
}
/* prime the child environment */
setuserenv("AGENT", "sendmail");
- (void) setsignal(SIGPIPE, SIG_IGN);
+ (void) sm_signal(SIGPIPE, SIG_IGN);
OldUmask = umask(022);
- OpMode = MD_DELIVER;
FullName = getextenv("NAME");
/*
@@ -501,20 +651,13 @@ main(argc, argv, envp)
#if NAMED_BIND
if (!bitset(RES_INIT, _res.options))
(void) res_init();
-
- /*
- ** hack to avoid crashes when debugging for the resolver is
- ** turned on and sfio is used
- */
if (tTd(8, 8))
-# if !SFIO || SFIO_STDIO_COMPAT
_res.options |= RES_DEBUG;
-# else /* !SFIO || SFIO_STDIO_COMPAT */
- dprintf("RES_DEBUG not available due to SFIO\n");
-# endif /* !SFIO || SFIO_STDIO_COMPAT */
else
_res.options &= ~RES_DEBUG;
# ifdef RES_NOALIASES
+ if (bitset(RES_NOALIASES, _res.options))
+ ResNoAliases = true;
_res.options |= RES_NOALIASES;
# endif /* RES_NOALIASES */
TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
@@ -529,22 +672,21 @@ main(argc, argv, envp)
from = NULL;
/* initialize some macros, etc. */
- initmacros(CurEnv);
- init_vendor_macros(CurEnv);
+ init_vendor_macros(&BlankEnvelope);
/* version */
- define('v', Version, CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);
/* hostname */
hp = myhostname(jbuf, sizeof jbuf);
if (jbuf[0] != '\0')
{
- struct utsname utsname;
+ struct utsname utsname;
if (tTd(0, 4))
- dprintf("canonical name: %s\n", jbuf);
- define('w', newstr(jbuf), CurEnv); /* must be new string */
- define('j', newstr(jbuf), CurEnv);
+ sm_dprintf("Canonical name: %s\n", jbuf);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);
setclass('w', jbuf);
p = strchr(jbuf, '.');
@@ -552,13 +694,14 @@ main(argc, argv, envp)
{
if (p[1] != '\0')
{
- define('m', newstr(&p[1]), CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm',
+ &p[1]);
}
while (p != NULL && strchr(&p[1], '.') != NULL)
{
*p = '\0';
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", jbuf);
+ sm_dprintf("\ta.k.a.: %s\n", jbuf);
setclass('w', jbuf);
*p++ = '.';
p = strchr(p, '.');
@@ -570,15 +713,14 @@ main(argc, argv, envp)
else
{
if (tTd(0, 22))
- dprintf("uname failed (%s)\n",
- errstring(errno));
+ sm_dprintf("uname failed (%s)\n",
+ sm_errstring(errno));
makelower(jbuf);
p = jbuf;
}
if (tTd(0, 4))
- dprintf(" UUCP nodename: %s\n", p);
- p = newstr(p);
- define('k', p, CurEnv);
+ sm_dprintf(" UUCP nodename: %s\n", p);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);
setclass('k', p);
setclass('w', p);
}
@@ -587,11 +729,11 @@ main(argc, argv, envp)
for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
{
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", *av);
+ sm_dprintf("\ta.k.a.: %s\n", *av);
setclass('w', *av);
}
#if NETINET || NETINET6
- for (i = 0; hp->h_addr_list[i] != NULL; i++)
+ for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)
{
# if NETINET6
char *addr;
@@ -612,8 +754,8 @@ main(argc, argv, envp)
break;
memmove(&ia, hp->h_addr_list[i], INADDRSZ);
- (void) snprintf(ipbuf, sizeof ipbuf,
- "[%.100s]", inet_ntoa(ia));
+ (void) sm_snprintf(ipbuf, sizeof ipbuf,
+ "[%.100s]", inet_ntoa(ia));
break;
# endif /* NETINET */
@@ -625,8 +767,8 @@ main(argc, argv, envp)
memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
addr = anynet_ntop(&ia6, buf6, sizeof buf6);
if (addr != NULL)
- (void) snprintf(ipbuf, sizeof ipbuf,
- "[%.100s]", addr);
+ (void) sm_snprintf(ipbuf, sizeof ipbuf,
+ "[%.100s]", addr);
break;
# endif /* NETINET6 */
}
@@ -634,128 +776,97 @@ main(argc, argv, envp)
break;
if (tTd(0, 4))
- dprintf("\ta.k.a.: %s\n", ipbuf);
+ sm_dprintf("\ta.k.a.: %s\n", ipbuf);
setclass('w', ipbuf);
}
#endif /* NETINET || NETINET6 */
-#if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
freehostent(hp);
hp = NULL;
-#endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
}
/* current time */
- define('b', arpadate((char *) NULL), CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));
+
/* current load average */
- CurrentLA = sm_getla(CurEnv);
+ sm_getla();
QueueLimitRecipient = (QUEUE_CHAR *) NULL;
QueueLimitSender = (QUEUE_CHAR *) NULL;
QueueLimitId = (QUEUE_CHAR *) NULL;
+#if _FFR_QUARANTINE
+ QueueLimitQuarantine = (QUEUE_CHAR *) NULL;
+#endif /* _FFR_QUARANTINE */
/*
** Crack argv.
*/
- av = argv;
- p = strrchr(*av, '/');
- if (p++ == NULL)
- p = *av;
- if (strcmp(p, "newaliases") == 0)
- OpMode = MD_INITALIAS;
- else if (strcmp(p, "mailq") == 0)
- OpMode = MD_PRINT;
- else if (strcmp(p, "smtpd") == 0)
- OpMode = MD_DAEMON;
- else if (strcmp(p, "hoststat") == 0)
- OpMode = MD_HOSTSTAT;
- else if (strcmp(p, "purgestat") == 0)
- OpMode = MD_PURGESTAT;
-
optind = 1;
while ((j = getopt(argc, argv, OPTIONS)) != -1)
{
switch (j)
{
case 'b': /* operations mode */
- switch (j = *optarg)
- {
- case MD_DAEMON:
- case MD_FGDAEMON:
-#if !DAEMON
- usrerr("Daemon mode not implemented");
- ExitStat = EX_USAGE;
- break;
-#endif /* !DAEMON */
- case MD_SMTP:
-#if !SMTP
- usrerr("I don't speak SMTP");
- ExitStat = EX_USAGE;
- break;
-#endif /* !SMTP */
-
- case MD_INITALIAS:
- case MD_DELIVER:
- case MD_VERIFY:
- case MD_TEST:
- case MD_PRINT:
- case MD_HOSTSTAT:
- case MD_PURGESTAT:
- case MD_ARPAFTP:
- OpMode = j;
- break;
-
- case MD_FREEZE:
- usrerr("Frozen configurations unsupported");
- ExitStat = EX_USAGE;
- break;
+ /* already done */
+ break;
- default:
- usrerr("Invalid operation mode %c", j);
- ExitStat = EX_USAGE;
- break;
- }
+ case 'A': /* use Alternate sendmail/submit.cf */
+ cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF
+ : SM_GET_SENDMAIL_CF;
break;
case 'B': /* body type */
- CurEnv->e_bodytype = newstr(optarg);
+ CHECK_AGAINST_OPMODE(j);
+ BlankEnvelope.e_bodytype = newstr(optarg);
break;
case 'C': /* select configuration file (already done) */
if (RealUid != 0)
- warn_C_flag = TRUE;
- ConfFile = newstr(optarg);
- dp = drop_privileges(TRUE);
+ warn_C_flag = true;
+ conffile = newstr(optarg);
+ dp = drop_privileges(true);
setstat(dp);
- safecf = FALSE;
+ safecf = false;
break;
- case 'd': /* debugging -- already done */
+ case 'd': /* debugging */
+ /* already done */
break;
case 'f': /* from address */
case 'r': /* obsolete -f flag */
+ CHECK_AGAINST_OPMODE(j);
if (from != NULL)
{
usrerr("More than one \"from\" person");
ExitStat = EX_USAGE;
break;
}
- from = newstr(denlstring(optarg, TRUE, TRUE));
+ from = newstr(denlstring(optarg, true, true));
if (strcmp(RealUserName, from) != 0)
warn_f_flag = j;
break;
case 'F': /* set full name */
+ CHECK_AGAINST_OPMODE(j);
FullName = newstr(optarg);
break;
case 'G': /* relay (gateway) submission */
/* already set */
+ CHECK_AGAINST_OPMODE(j);
break;
case 'h': /* hop count */
- CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10);
+ CHECK_AGAINST_OPMODE(j);
+ BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,
+ 10);
+ (void) sm_snprintf(buf, sizeof buf, "%d",
+ BlankEnvelope.e_hopcount);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);
+
if (*ep)
{
usrerr("Bad hop count (%s)", optarg);
@@ -768,25 +879,27 @@ main(argc, argv, envp)
break;
case 'n': /* don't alias */
- NoAlias = TRUE;
+ CHECK_AGAINST_OPMODE(j);
+ NoAlias = true;
break;
case 'N': /* delivery status notifications */
+ CHECK_AGAINST_OPMODE(j);
DefaultNotify |= QHASNOTIFY;
- define(macid("{dsn_notify}", NULL),
- newstr(optarg), CurEnv);
- if (strcasecmp(optarg, "never") == 0)
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{dsn_notify}"), optarg);
+ if (sm_strcasecmp(optarg, "never") == 0)
break;
for (p = optarg; p != NULL; optarg = p)
{
p = strchr(p, ',');
if (p != NULL)
*p++ = '\0';
- if (strcasecmp(optarg, "success") == 0)
+ if (sm_strcasecmp(optarg, "success") == 0)
DefaultNotify |= QPINGONSUCCESS;
- else if (strcasecmp(optarg, "failure") == 0)
+ else if (sm_strcasecmp(optarg, "failure") == 0)
DefaultNotify |= QPINGONFAILURE;
- else if (strcasecmp(optarg, "delay") == 0)
+ else if (sm_strcasecmp(optarg, "delay") == 0)
DefaultNotify |= QPINGONDELAY;
else
{
@@ -797,40 +910,64 @@ main(argc, argv, envp)
break;
case 'o': /* set option */
- setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
+ setoption(*optarg, optarg + 1, false, true,
+ &BlankEnvelope);
break;
case 'O': /* set option (long form) */
- setoption(' ', optarg, FALSE, TRUE, CurEnv);
+ setoption(' ', optarg, false, true, &BlankEnvelope);
break;
case 'p': /* set protocol */
+ CHECK_AGAINST_OPMODE(j);
p = strchr(optarg, ':');
if (p != NULL)
{
*p++ = '\0';
if (*p != '\0')
{
- ep = xalloc(strlen(p) + 1);
+ ep = sm_malloc_x(strlen(p) + 1);
cleanstrcpy(ep, p, MAXNAME);
- define('s', ep, CurEnv);
+ macdefine(&BlankEnvelope.e_macro,
+ A_HEAP, 's', ep);
}
}
if (*optarg != '\0')
{
- ep = xalloc(strlen(optarg) + 1);
+ ep = sm_malloc_x(strlen(optarg) + 1);
cleanstrcpy(ep, optarg, MAXNAME);
- define('r', ep, CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_HEAP,
+ 'r', ep);
}
break;
+#if _FFR_QUARANTINE
+ case 'Q': /* change quarantining on queued items */
+ /* sanity check */
+ if (OpMode != MD_DELIVER &&
+ OpMode != MD_QUEUERUN)
+ {
+ usrerr("Can not use -Q with -b%c", OpMode);
+ ExitStat = EX_USAGE;
+ break;
+ }
+
+ if (OpMode == MD_DELIVER)
+ set_op_mode(MD_QUEUERUN);
+
+ FullName = NULL;
+
+ quarantining = newstr(optarg);
+ break;
+#endif /* _FFR_QUARANTINE */
+
case 'q': /* run queue files at intervals */
-#if QUEUE
/* sanity check */
if (OpMode != MD_DELIVER &&
OpMode != MD_DAEMON &&
OpMode != MD_FGDAEMON &&
OpMode != MD_PRINT &&
+ OpMode != MD_PRINTNQE &&
OpMode != MD_QUEUERUN)
{
usrerr("Can not use -q with -b%c", OpMode);
@@ -840,33 +977,89 @@ main(argc, argv, envp)
/* don't override -bd, -bD or -bp */
if (OpMode == MD_DELIVER)
- OpMode = MD_QUEUERUN;
+ set_op_mode(MD_QUEUERUN);
FullName = NULL;
+ negate = optarg[0] == '!';
+ if (negate)
+ {
+ /* negate meaning of pattern match */
+ optarg++; /* skip '!' for next switch */
+ }
switch (optarg[0])
{
- case 'I':
+ case 'G': /* Limit by queue group name */
+ if (negate)
+ {
+ usrerr("Can not use -q!G");
+ ExitStat = EX_USAGE;
+ break;
+ }
+ if (queuegroup != NULL)
+ {
+ usrerr("Can not use multiple -qG options");
+ ExitStat = EX_USAGE;
+ break;
+ }
+ queuegroup = newstr(&optarg[1]);
+ break;
+
+ case 'I': /* Limit by ID */
new = (QUEUE_CHAR *) xalloc(sizeof *new);
new->queue_match = newstr(&optarg[1]);
+ new->queue_negate = negate;
new->queue_next = QueueLimitId;
QueueLimitId = new;
break;
- case 'R':
+ case 'R': /* Limit by recipient */
new = (QUEUE_CHAR *) xalloc(sizeof *new);
new->queue_match = newstr(&optarg[1]);
+ new->queue_negate = negate;
new->queue_next = QueueLimitRecipient;
QueueLimitRecipient = new;
break;
- case 'S':
+ case 'S': /* Limit by sender */
new = (QUEUE_CHAR *) xalloc(sizeof *new);
new->queue_match = newstr(&optarg[1]);
+ new->queue_negate = negate;
new->queue_next = QueueLimitSender;
QueueLimitSender = new;
break;
+ case 'f': /* foreground queue run */
+ foregroundqueue = true;
+ break;
+
+#if _FFR_QUARANTINE
+ case 'Q': /* Limit by quarantine message */
+ if (optarg[1] != '\0')
+ {
+ new = (QUEUE_CHAR *) xalloc(sizeof *new);
+ new->queue_match = newstr(&optarg[1]);
+ new->queue_negate = negate;
+ new->queue_next = QueueLimitQuarantine;
+ QueueLimitQuarantine = new;
+ }
+ QueueMode = QM_QUARANTINE;
+ break;
+
+ case 'L': /* act on lost items */
+ QueueMode = QM_LOST;
+ break;
+#endif /* _FFR_QUARANTINE */
+
+ case 'p': /* Persistent queue */
+ queuepersistent = true;
+ if (QueueIntvl == 0)
+ QueueIntvl = 1;
+ if (optarg[1] == '\0')
+ break;
+ ++optarg;
+ /* FALLTHROUGH */
+
default:
i = Errors;
QueueIntvl = convtime(optarg, 'm');
@@ -876,40 +1069,35 @@ main(argc, argv, envp)
ExitStat = EX_USAGE;
break;
}
-#else /* QUEUE */
- usrerr("I don't know about queues");
- ExitStat = EX_USAGE;
-#endif /* QUEUE */
break;
case 'R': /* DSN RET: what to return */
- if (bitset(EF_RET_PARAM, CurEnv->e_flags))
+ CHECK_AGAINST_OPMODE(j);
+ if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))
{
usrerr("Duplicate -R flag");
ExitStat = EX_USAGE;
break;
}
- CurEnv->e_flags |= EF_RET_PARAM;
- if (strcasecmp(optarg, "hdrs") == 0)
- CurEnv->e_flags |= EF_NO_BODY_RETN;
- else if (strcasecmp(optarg, "full") != 0)
+ BlankEnvelope.e_flags |= EF_RET_PARAM;
+ if (sm_strcasecmp(optarg, "hdrs") == 0)
+ BlankEnvelope.e_flags |= EF_NO_BODY_RETN;
+ else if (sm_strcasecmp(optarg, "full") != 0)
{
usrerr("Invalid -R value");
ExitStat = EX_USAGE;
}
- define(macid("{dsn_ret}", NULL),
- newstr(optarg), CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{dsn_ret}"), optarg);
break;
case 't': /* read recipients from message */
- GrabTo = TRUE;
- break;
-
- case 'U': /* initial (user) submission */
- /* already set */
+ CHECK_AGAINST_OPMODE(j);
+ GrabTo = true;
break;
case 'V': /* DSN ENVID: set "original" envelope id */
+ CHECK_AGAINST_OPMODE(j);
if (!xtextok(optarg))
{
usrerr("Invalid syntax in -V flag");
@@ -917,31 +1105,34 @@ main(argc, argv, envp)
}
else
{
- CurEnv->e_envid = newstr(optarg);
- define(macid("{dsn_envid}", NULL),
- newstr(optarg), CurEnv);
+ BlankEnvelope.e_envid = newstr(optarg);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{dsn_envid}"), optarg);
}
break;
case 'X': /* traffic log file */
- dp = drop_privileges(TRUE);
+ dp = drop_privileges(true);
setstat(dp);
if (stat(optarg, &traf_st) == 0 &&
S_ISFIFO(traf_st.st_mode))
- TrafficLogFile = fopen(optarg, "w");
+ TrafficLogFile = sm_io_open(SmFtStdio,
+ SM_TIME_DEFAULT,
+ optarg,
+ SM_IO_WRONLY, NULL);
else
- TrafficLogFile = fopen(optarg, "a");
+ TrafficLogFile = sm_io_open(SmFtStdio,
+ SM_TIME_DEFAULT,
+ optarg,
+ SM_IO_APPEND, NULL);
if (TrafficLogFile == NULL)
{
syserr("cannot open %s", optarg);
ExitStat = EX_CANTCREAT;
break;
}
-#if HASSETVBUF
- (void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
-#else /* HASSETVBUF */
- (void) setlinebuf(TrafficLogFile);
-#endif /* HASSETVBUF */
+ (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,
+ NULL, SM_IO_LBF, 0);
break;
/* compatibility flags */
@@ -950,21 +1141,21 @@ main(argc, argv, envp)
case 'm': /* send to me too */
case 'T': /* set timeout interval */
case 'v': /* give blow-by-blow description */
- setoption(j, "T", FALSE, TRUE, CurEnv);
+ setoption(j, "T", false, true, &BlankEnvelope);
break;
case 'e': /* error message disposition */
case 'M': /* define macro */
- setoption(j, optarg, FALSE, TRUE, CurEnv);
+ setoption(j, optarg, false, true, &BlankEnvelope);
break;
case 's': /* save From lines in headers */
- setoption('f', "T", FALSE, TRUE, CurEnv);
+ setoption('f', "T", false, true, &BlankEnvelope);
break;
#ifdef DBM
case 'I': /* initialize alias DBM file */
- OpMode = MD_INITALIAS;
+ set_op_mode(MD_INITALIAS);
break;
#endif /* DBM */
@@ -980,39 +1171,30 @@ main(argc, argv, envp)
#endif /* defined(sony_news) */
default:
- finis(TRUE, EX_USAGE);
+ finis(true, true, EX_USAGE);
+ /* NOTREACHED */
break;
}
}
- av += optind;
- if (bitset(SUBMIT_MTA, SubmitMode) &&
- bitset(SUBMIT_MSA, SubmitMode))
+ /* if we've had errors so far, exit now */
+ if ((ExitStat != EX_OK && OpMode != MD_TEST) ||
+ ExitStat == EX_OSERR)
{
- /* sanity check */
- errno = 0; /* reset to avoid bogus error messages */
- syserr("Cannot use both -G and -U together");
+ finis(false, true, ExitStat);
+ /* NOTREACHED */
}
- else if (bitset(SUBMIT_MTA, SubmitMode))
- define(macid("{daemon_flags}", NULL), "CC f", CurEnv);
- else if (bitset(SUBMIT_MSA, SubmitMode))
- {
- define(macid("{daemon_flags}", NULL), "c u", CurEnv);
- /* check for wrong OpMode */
- if (OpMode != MD_DELIVER && OpMode != MD_SMTP)
- {
- errno = 0; /* reset to avoid bogus error msgs */
- syserr("Cannot use -U and -b%c", OpMode);
- }
+ if (bitset(SUBMIT_MTA, SubmitMode))
+ {
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_flags}"), "CC f");
}
- else
+ else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)
{
-#if _FFR_DEFAULT_SUBMIT_TO_MSA
- define(macid("{daemon_flags}", NULL), "c u", CurEnv);
-#else /* _FFR_DEFAULT_SUBMIT_TO_MSA */
- /* EMPTY */
-#endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */
+ SubmitMode = SUBMIT_MSA;
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_flags}"), "c u");
}
/*
@@ -1021,27 +1203,39 @@ main(argc, argv, envp)
** Extract special fields for local use.
*/
- /* set up ${opMode} for use in config file */
- {
- char mbuf[2];
-
- mbuf[0] = OpMode;
- mbuf[1] = '\0';
- define(MID_OPMODE, newstr(mbuf), CurEnv);
- }
-
#if XDEBUG
checkfd012("before readcf");
#endif /* XDEBUG */
- vendor_pre_defaults(CurEnv);
+ vendor_pre_defaults(&BlankEnvelope);
- readcf(getcfname(), safecf, CurEnv);
- ConfigFileRead = TRUE;
- vendor_post_defaults(CurEnv);
+ readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
+ safecf, &BlankEnvelope);
+#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
+ ConfigFileRead = true;
+#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
+ vendor_post_defaults(&BlankEnvelope);
+
+ /* now we can complain about missing fds */
+ if (MissingFds != 0 && LogLevel > 8)
+ {
+ char mbuf[MAXLINE];
+
+ mbuf[0] = '\0';
+ if (bitset(1 << STDIN_FILENO, MissingFds))
+ (void) sm_strlcat(mbuf, ", stdin", sizeof mbuf);
+ if (bitset(1 << STDOUT_FILENO, MissingFds))
+ (void) sm_strlcat(mbuf, ", stdout", sizeof mbuf);
+ if (bitset(1 << STDERR_FILENO, MissingFds))
+ (void) sm_strlcat(mbuf, ", stderr", sizeof mbuf);
+
+ /* Notice: fill_errno is from high above: fill_fd() */
+ sm_syslog(LOG_WARNING, NOQID,
+ "File descriptors missing on startup: %s; %s",
+ &mbuf[2], sm_errstring(fill_errno));
+ }
/* Remove the ability for a normal user to send signals */
- if (RealUid != 0 &&
- RealUid != geteuid())
+ if (RealUid != 0 && RealUid != geteuid())
{
uid_t new_uid = geteuid();
@@ -1056,17 +1250,17 @@ main(argc, argv, envp)
if (new_uid == 0)
new_uid = DefUid;
if (tTd(47, 5))
- dprintf("Changing real uid to %d\n", (int) new_uid);
+ sm_dprintf("Changing real uid to %d\n", (int) new_uid);
if (setreuid(new_uid, geteuid()) < 0)
{
syserr("main: setreuid(%d, %d) failed",
(int) new_uid, (int) geteuid());
- finis(FALSE, EX_OSERR);
+ finis(false, true, EX_OSERR);
/* NOTREACHED */
}
if (tTd(47, 10))
- dprintf("Now running as e/ruid %d:%d\n",
- (int) geteuid(), (int) getuid());
+ sm_dprintf("Now running as e/ruid %d:%d\n",
+ (int) geteuid(), (int) getuid());
#else /* HASSETREUID */
/*
** Have to change both effective and real so need to
@@ -1074,23 +1268,45 @@ main(argc, argv, envp)
*/
if (tTd(47, 5))
- dprintf("Changing uid to %d\n", (int) new_uid);
+ sm_dprintf("Changing uid to %d\n", (int) new_uid);
if (setuid(new_uid) < 0)
{
syserr("main: setuid(%d) failed", (int) new_uid);
- finis(FALSE, EX_OSERR);
+ finis(false, true, EX_OSERR);
/* NOTREACHED */
}
if (tTd(47, 10))
- dprintf("Now running as e/ruid %d:%d\n",
- (int) geteuid(), (int) getuid());
+ sm_dprintf("Now running as e/ruid %d:%d\n",
+ (int) geteuid(), (int) getuid());
#endif /* HASSETREUID */
}
+#if NAMED_BIND
+ if (FallBackMX != NULL)
+ (void) getfallbackmxrr(FallBackMX);
+#endif /* NAMED_BIND */
+
+ if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n");
+ }
+
+ if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))
+ {
+ usrerr("Mail submission program cannot be used as daemon");
+ finis(false, true, EX_USAGE);
+ }
+
+ if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||
+ OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||
+ OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)
+ makeworkgroups();
+
/* set up the basic signal handlers */
- if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
- (void) setsignal(SIGINT, intsig);
- (void) setsignal(SIGTERM, intsig);
+ if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void) sm_signal(SIGINT, intsig);
+ (void) sm_signal(SIGTERM, intsig);
/* Enforce use of local time (null string overrides this) */
if (TimeZoneSpec == NULL)
@@ -1101,14 +1317,39 @@ main(argc, argv, envp)
setuserenv("TZ", NULL);
tzset();
+ /* initialize mailbox database */
+ i = sm_mbdb_initialize(Mbdb);
+ if (i != EX_OK)
+ {
+ usrerr("Can't initialize mailbox database \"%s\": %s",
+ Mbdb, sm_strexit(i));
+ ExitStat = i;
+ }
+
/* avoid denial-of-service attacks */
resetlimits();
- if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
+ if (OpMode == MD_TEST)
+ {
+ /* can't be done after readcf if RunAs* is used */
+ dp = drop_privileges(true);
+ if (dp != EX_OK)
+ {
+ finis(false, true, dp);
+ /* NOTREACHED */
+ }
+ }
+ else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
{
/* drop privileges -- daemon mode done after socket/bind */
- dp = drop_privileges(FALSE);
+ dp = drop_privileges(false);
setstat(dp);
+ if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))
+ {
+ usrerr("Mail submission program must have RunAsUser set to non root user");
+ finis(false, true, EX_CONFIG);
+ /* NOTREACHED */
+ }
}
#if NAMED_BIND
@@ -1121,33 +1362,41 @@ main(argc, argv, envp)
*/
authinfo = getauthinfo(STDIN_FILENO, &forged);
- define('_', authinfo, CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
/* suppress error printing if errors mailed back or whatever */
- if (CurEnv->e_errormode != EM_PRINT)
- HoldErrs = TRUE;
+ if (BlankEnvelope.e_errormode != EM_PRINT)
+ HoldErrs = true;
/* set up the $=m class now, after .cf has a chance to redefine $m */
- expand("\201m", jbuf, sizeof jbuf, CurEnv);
+ expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope);
if (jbuf[0] != '\0')
setclass('m', jbuf);
/* probe interfaces and locate any additional names */
- if (!DontProbeInterfaces)
+ if (DontProbeInterfaces != DPI_PROBENONE)
load_if_names();
+ if (tTd(0, 10))
+ {
+ /* Now we know which .cf file we use */
+ sm_dprintf(" Conf file:\t%s (selected)\n",
+ getcfname(OpMode, SubmitMode, cftype, conffile));
+ sm_dprintf(" Pid file:\t%s (selected)\n", PidFile);
+ }
+
if (tTd(0, 1))
{
- dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
- dprintf("\n (short domain name) $w = ");
- xputs(macvalue('w', CurEnv));
- dprintf("\n (canonical domain name) $j = ");
- xputs(macvalue('j', CurEnv));
- dprintf("\n (subdomain name) $m = ");
- xputs(macvalue('m', CurEnv));
- dprintf("\n (node name) $k = ");
- xputs(macvalue('k', CurEnv));
- dprintf("\n========================================================\n\n");
+ sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
+ sm_dprintf("\n (short domain name) $w = ");
+ xputs(macvalue('w', &BlankEnvelope));
+ sm_dprintf("\n (canonical domain name) $j = ");
+ xputs(macvalue('j', &BlankEnvelope));
+ sm_dprintf("\n (subdomain name) $m = ");
+ xputs(macvalue('m', &BlankEnvelope));
+ sm_dprintf("\n (node name) $k = ");
+ xputs(macvalue('k', &BlankEnvelope));
+ sm_dprintf("\n========================================================\n\n");
}
/*
@@ -1157,24 +1406,25 @@ main(argc, argv, envp)
/* process authorization warnings from command line */
if (warn_C_flag)
- auth_warning(CurEnv, "Processed by %s with -C %s",
- RealUserName, ConfFile);
+ auth_warning(&BlankEnvelope, "Processed by %s with -C %s",
+ RealUserName, conffile);
if (Warn_Q_option && !wordinclass(RealUserName, 't'))
- auth_warning(CurEnv, "Processed from queue %s", QueueDir);
+ auth_warning(&BlankEnvelope, "Processed from queue %s",
+ QueueDir);
+ if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&
+ RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)
+ sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",
+ (int) RealUid);
/* check body type for legality */
- if (CurEnv->e_bodytype == NULL)
- /* EMPTY */
- /* nothing */ ;
- else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
- SevenBitInput = TRUE;
- else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
- SevenBitInput = FALSE;
- else
+ i = check_bodytype(BlankEnvelope.e_bodytype);
+ if (i == BODYTYPE_ILLEGAL)
{
- usrerr("Illegal body type %s", CurEnv->e_bodytype);
- CurEnv->e_bodytype = NULL;
+ usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
+ BlankEnvelope.e_bodytype = NULL;
}
+ else if (i != BODYTYPE_NONE)
+ SevenBitInput = (i == BODYTYPE_7BIT);
/* tweak default DSN notifications */
if (DefaultNotify == 0)
@@ -1188,50 +1438,156 @@ main(argc, argv, envp)
if (ConfigLevel > MAXCONFIGLEVEL)
{
syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
- ConfigLevel, Version, MAXCONFIGLEVEL);
+ ConfigLevel, Version, MAXCONFIGLEVEL);
}
/* need MCI cache to have persistence */
if (HostStatDir != NULL && MaxMciCache == 0)
{
HostStatDir = NULL;
- printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
}
/* need HostStatusDir in order to have SingleThreadDelivery */
if (SingleThreadDelivery && HostStatDir == NULL)
{
- SingleThreadDelivery = FALSE;
- printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
+ SingleThreadDelivery = false;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
}
/* check for permissions */
- if ((OpMode == MD_DAEMON ||
- OpMode == MD_FGDAEMON ||
- OpMode == MD_PURGESTAT) &&
- RealUid != 0 &&
+ if (RealUid != 0 &&
RealUid != TrustedUid)
{
- if (LogLevel > 1)
- sm_syslog(LOG_ALERT, NOQID,
- "user %d attempted to %s",
- RealUid,
- OpMode != MD_PURGESTAT ? "run daemon"
- : "purge host status");
- usrerr("Permission denied");
- finis(FALSE, EX_USAGE);
- }
- if (OpMode == MD_INITALIAS &&
- RealUid != 0 &&
- RealUid != TrustedUid &&
- !wordinclass(RealUserName, 't'))
- {
- if (LogLevel > 1)
- sm_syslog(LOG_ALERT, NOQID,
- "user %d attempted to rebuild the alias map",
- RealUid);
- usrerr("Permission denied");
- finis(FALSE, EX_USAGE);
+ char *action = NULL;
+
+ switch (OpMode)
+ {
+ case MD_QUEUERUN:
+#if _FFR_QUARANTINE
+ if (quarantining != NULL)
+ action = "quarantine jobs";
+ else
+#endif /* _FFR_QUARANTINE */
+ /* Normal users can do a single queue run */
+ if (QueueIntvl == 0)
+ break;
+
+ /* but not persistent queue runners */
+ if (action == NULL)
+ action = "start a queue runner daemon";
+ /* FALLTHROUGH */
+
+ case MD_PURGESTAT:
+ if (action == NULL)
+ action = "purge host status";
+ /* FALLTHROUGH */
+
+ case MD_DAEMON:
+ case MD_FGDAEMON:
+ if (action == NULL)
+ action = "run daemon";
+
+ if (tTd(65, 1))
+ sm_dprintf("Deny user %d attempt to %s\n",
+ (int) RealUid, action);
+
+ if (LogLevel > 1)
+ sm_syslog(LOG_ALERT, NOQID,
+ "user %d attempted to %s",
+ (int) RealUid, action);
+ HoldErrs = false;
+ usrerr("Permission denied (real uid not trusted)");
+ finis(false, true, EX_USAGE);
+ /* NOTREACHED */
+ break;
+
+ case MD_VERIFY:
+ if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))
+ {
+ /*
+ ** If -bv and RestrictExpand,
+ ** drop privs to prevent normal
+ ** users from reading private
+ ** aliases/forwards/:include:s
+ */
+
+ if (tTd(65, 1))
+ sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",
+ (int) RealUid);
+
+ dp = drop_privileges(true);
+
+ /* Fake address safety */
+ if (tTd(65, 1))
+ sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");
+ setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);
+
+ if (dp != EX_OK)
+ {
+ if (tTd(65, 1))
+ sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",
+ (int) RealUid);
+ CurEnv->e_id = NULL;
+ finis(true, true, dp);
+ /* NOTREACHED */
+ }
+ }
+ break;
+
+ case MD_TEST:
+ case MD_PRINT:
+ case MD_PRINTNQE:
+ case MD_FREEZE:
+ case MD_HOSTSTAT:
+ /* Nothing special to check */
+ break;
+
+ case MD_INITALIAS:
+ if (!wordinclass(RealUserName, 't'))
+ {
+ if (tTd(65, 1))
+ sm_dprintf("Deny user %d attempt to rebuild the alias map\n",
+ (int) RealUid);
+ if (LogLevel > 1)
+ sm_syslog(LOG_ALERT, NOQID,
+ "user %d attempted to rebuild the alias map",
+ (int) RealUid);
+ HoldErrs = false;
+ usrerr("Permission denied (real uid not trusted)");
+ finis(false, true, EX_USAGE);
+ /* NOTREACHED */
+ }
+ if (UseMSP)
+ {
+ HoldErrs = false;
+ usrerr("User %d cannot rebuild aliases in mail submission program",
+ (int) RealUid);
+ finis(false, true, EX_USAGE);
+ /* NOTREACHED */
+ }
+ /* FALLTHROUGH */
+
+ default:
+ if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&
+ Verbose != 0)
+ {
+ /*
+ ** If -v and RestrictExpand, reset
+ ** Verbose to prevent normal users
+ ** from seeing the expansion of
+ ** aliases/forwards/:include:s
+ */
+
+ if (tTd(65, 1))
+ sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",
+ (int) RealUid);
+ Verbose = 0;
+ }
+ break;
+ }
}
if (MeToo)
@@ -1244,48 +1600,49 @@ main(argc, argv, envp)
HostStatDir = NULL;
if (Verbose == 0)
Verbose = 2;
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
+ BlankEnvelope.e_errormode = EM_PRINT;
+ HoldErrs = false;
break;
case MD_VERIFY:
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
-
+ BlankEnvelope.e_errormode = EM_PRINT;
+ HoldErrs = false;
/* arrange to exit cleanly on hangup signal */
- if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
- (void) setsignal(SIGHUP, intsig);
+ if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
+ (void) sm_signal(SIGHUP, intsig);
+ if (geteuid() != 0)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Notice: -bv may give misleading output for non-privileged user\n");
break;
case MD_FGDAEMON:
- run_in_foreground = TRUE;
- OpMode = MD_DAEMON;
+ run_in_foreground = true;
+ set_op_mode(MD_DAEMON);
/* FALLTHROUGH */
case MD_DAEMON:
- vendor_daemon_setup(CurEnv);
+ vendor_daemon_setup(&BlankEnvelope);
/* remove things that don't make sense in daemon mode */
FullName = NULL;
- GrabTo = FALSE;
+ GrabTo = false;
/* arrange to restart on hangup signal */
if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
sm_syslog(LOG_WARNING, NOQID,
"daemon invoked without full pathname; kill -1 won't work");
- (void) setsignal(SIGTERM, term_daemon);
break;
case MD_INITALIAS:
Verbose = 2;
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
+ BlankEnvelope.e_errormode = EM_PRINT;
+ HoldErrs = false;
/* FALLTHROUGH */
default:
/* arrange to exit cleanly on hangup signal */
- if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
- (void) setsignal(SIGHUP, intsig);
+ if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
+ (void) sm_signal(SIGHUP, intsig);
break;
}
@@ -1297,7 +1654,7 @@ main(argc, argv, envp)
/* full names can't have newlines */
if (strchr(FullName, '\n') != NULL)
{
- full = newstr(denlstring(FullName, TRUE, TRUE));
+ full = newstr(denlstring(FullName, true, true));
FullName = full;
}
@@ -1310,9 +1667,9 @@ main(argc, argv, envp)
** the name portion of the address.
*/
- FullName = addquotes(FullName);
+ FullName = addquotes(FullName, NULL);
if (full != NULL)
- sm_free(full);
+ sm_free(full); /* XXX */
}
}
@@ -1320,10 +1677,10 @@ main(argc, argv, envp)
if (Verbose)
{
/* turn off noconnect option */
- setoption('c', "F", TRUE, FALSE, CurEnv);
+ setoption('c', "F", true, false, &BlankEnvelope);
/* turn on interactive delivery */
- setoption('d', "", TRUE, FALSE, CurEnv);
+ setoption('d', "", true, false, &BlankEnvelope);
}
#ifdef VENDOR_CODE
@@ -1343,19 +1700,21 @@ main(argc, argv, envp)
}
if (ConfigLevel < 3)
- UseErrorsTo = TRUE;
+ UseErrorsTo = true;
/* set options that were previous macros */
if (SmtpGreeting == NULL)
{
- if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
+ if (ConfigLevel < 7 &&
+ (p = macvalue('e', &BlankEnvelope)) != NULL)
SmtpGreeting = newstr(p);
else
SmtpGreeting = "\201j Sendmail \201v ready at \201b";
}
if (UnixFromLine == NULL)
{
- if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
+ if (ConfigLevel < 7 &&
+ (p = macvalue('l', &BlankEnvelope)) != NULL)
UnixFromLine = newstr(p);
else
UnixFromLine = "From \201g \201d";
@@ -1363,11 +1722,11 @@ main(argc, argv, envp)
SmtpError[0] = '\0';
/* our name for SMTP codes */
- expand("\201j", jbuf, sizeof jbuf, CurEnv);
+ expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
if (jbuf[0] == '\0')
- MyHostName = newstr("localhost");
+ PSTRSET(MyHostName, "localhost");
else
- MyHostName = jbuf;
+ PSTRSET(MyHostName, jbuf);
if (strchr(MyHostName, '.') == NULL)
message("WARNING: local host name (%s) is not qualified; fix $j in config file",
MyHostName);
@@ -1375,6 +1734,13 @@ main(argc, argv, envp)
/* make certain that this name is part of the $=w class */
setclass('w', MyHostName);
+ /* fill in the structure of the *default* queue */
+ st = stab("mqueue", ST_QUEUE, ST_FIND);
+ if (st == NULL)
+ syserr("No default queue (mqueue) defined");
+ else
+ set_def_queueval(st->s_quegrp, true);
+
/* the indices of built-in mailers */
st = stab("local", ST_MAILER, ST_FIND);
if (st != NULL)
@@ -1454,29 +1820,28 @@ main(argc, argv, envp)
#endif /* USE_B_CLASS */
/* MIME headers which have fields to check for overflow */
- setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
- setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
+ setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");
+ setclass(macid("{checkMIMEFieldHeaders}"), "content-type");
/* MIME headers to check for length overflow */
- setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
+ setclass(macid("{checkMIMETextHeaders}"), "content-description");
/* MIME headers to check for overflow and rebalance */
- setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
- setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
-
- /* Macros to save in the qf file -- don't remove any */
- setclass(macid("{persistentMacros}", NULL), "r");
- setclass(macid("{persistentMacros}", NULL), "s");
- setclass(macid("{persistentMacros}", NULL), "_");
- setclass(macid("{persistentMacros}", NULL), "{if_addr}");
- setclass(macid("{persistentMacros}", NULL), "{daemon_flags}");
- setclass(macid("{persistentMacros}", NULL), "{client_flags}");
+ setclass(macid("{checkMIMEHeaders}"), "content-disposition");
+ setclass(macid("{checkMIMEHeaders}"), "content-id");
+ setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");
+ setclass(macid("{checkMIMEHeaders}"), "content-type");
+ setclass(macid("{checkMIMEHeaders}"), "mime-version");
+
+ /* Macros to save in the queue file -- don't remove any */
+ setclass(macid("{persistentMacros}"), "r");
+ setclass(macid("{persistentMacros}"), "s");
+ setclass(macid("{persistentMacros}"), "_");
+ setclass(macid("{persistentMacros}"), "{if_addr}");
+ setclass(macid("{persistentMacros}"), "{daemon_flags}");
/* operate in queue directory */
- if (QueueDir == NULL)
+ if (QueueDir == NULL || *QueueDir == '\0')
{
if (OpMode != MD_TEST)
{
@@ -1486,29 +1851,22 @@ main(argc, argv, envp)
}
else
{
- /*
- ** If multiple queues wildcarded, use one for
- ** the daemon's home. Note that this preconditions
- ** a wildcarded QueueDir to a real pathname.
- */
-
if (OpMode != MD_TEST)
- multiqueue_cache();
+ setup_queues(OpMode == MD_DAEMON);
}
/* check host status directory for validity */
- if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
+ if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))
{
/* cannot use this value */
- if (tTd(0, 2))
- dprintf("Cannot use HostStatusDirectory = %s: %s\n",
- HostStatDir, errstring(errno));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Cannot use HostStatusDirectory = %s: %s\n",
+ HostStatDir, sm_errstring(errno));
HostStatDir = NULL;
}
-#if QUEUE
- if (OpMode == MD_QUEUERUN && RealUid != 0 &&
- bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
+ if (OpMode == MD_QUEUERUN &&
+ RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
{
struct stat stbuf;
@@ -1518,22 +1876,48 @@ main(argc, argv, envp)
if (stbuf.st_uid != RealUid)
{
/* nope, really a botch */
+ HoldErrs = false;
usrerr("You do not have permission to process the queue");
- finis(FALSE, EX_NOPERM);
+ finis(false, true, EX_NOPERM);
+ /* NOTREACHED */
}
}
-#endif /* QUEUE */
-#if _FFR_MILTER
+#if MILTER
/* sanity checks on milter filters */
if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
- milter_parse_list(InputFilterList, InputFilters, MAXFILTERS);
-#endif /* _FFR_MILTER */
+ {
+ milter_config(InputFilterList, InputFilters, MAXFILTERS);
+# if _FFR_MILTER_PERDAEMON
+ setup_daemon_milters();
+# endif /* _FFR_MILTER_PERDAEMON */
+ }
+#endif /* MILTER */
+ /* Convert queuegroup string to qgrp number */
+ if (queuegroup != NULL)
+ {
+ qgrp = name2qid(queuegroup);
+ if (qgrp == NOQGRP)
+ {
+ HoldErrs = false;
+ usrerr("Queue group %s unknown", queuegroup);
+ finis(false, true, ExitStat);
+ /* NOTREACHED */
+ }
+ }
/* if we've had errors so far, exit now */
if (ExitStat != EX_OK && OpMode != MD_TEST)
- finis(FALSE, ExitStat);
+ {
+ finis(false, true, ExitStat);
+ /* NOTREACHED */
+ }
+
+#if SASL
+ /* sendmail specific SASL initialization */
+ sm_sasl_init();
+#endif /* SASL */
#if XDEBUG
checkfd012("before main() initmaps");
@@ -1547,43 +1931,89 @@ main(argc, argv, envp)
{
case MD_PRINT:
/* print the queue */
-#if QUEUE
- dropenvelope(CurEnv, TRUE);
- (void) setsignal(SIGPIPE, quiesce);
+ HoldErrs = false;
+ dropenvelope(&BlankEnvelope, true, false);
+ (void) sm_signal(SIGPIPE, sigpipe);
+ if (qgrp != NOQGRP)
+ {
+ int j;
+
+ /* Selecting a particular queue group to run */
+ for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
+ {
+ if (StopRequest)
+ stop_sendmail();
+ (void) print_single_queue(qgrp, j);
+ }
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
+ }
printqueue();
- finis(FALSE, EX_OK);
-#else /* QUEUE */
- usrerr("No queue to print");
- finis(FALSE, EX_UNAVAILABLE);
-#endif /* QUEUE */
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
+ break;
+
+ case MD_PRINTNQE:
+ /* print number of entries in queue */
+ dropenvelope(&BlankEnvelope, true, false);
+ (void) sm_signal(SIGPIPE, sigpipe);
+ printnqe(smioout, NULL);
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
break;
+#if _FFR_QUARANTINE
+ case MD_QUEUERUN:
+ /* only handle quarantining here */
+ if (quarantining == NULL)
+ break;
+
+ if (QueueMode != QM_QUARANTINE &&
+ QueueMode != QM_NORMAL)
+ {
+ HoldErrs = false;
+ usrerr("Can not use -Q with -q%c", QueueMode);
+ ExitStat = EX_USAGE;
+ finis(false, true, ExitStat);
+ /* NOTREACHED */
+ }
+ quarantine_queue(quarantining, qgrp);
+ finis(false, true, EX_OK);
+ break;
+#endif /* _FFR_QUARANTINE */
+
case MD_HOSTSTAT:
- (void) setsignal(SIGPIPE, quiesce);
+ (void) sm_signal(SIGPIPE, sigpipe);
(void) mci_traverse_persistent(mci_print_persistent, NULL);
- finis(FALSE, EX_OK);
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
break;
case MD_PURGESTAT:
(void) mci_traverse_persistent(mci_purge_persistent, NULL);
- finis(FALSE, EX_OK);
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
break;
case MD_INITALIAS:
/* initialize maps */
initmaps();
- finis(FALSE, ExitStat);
+ finis(false, true, ExitStat);
+ /* NOTREACHED */
break;
case MD_SMTP:
case MD_DAEMON:
/* reset DSN parameters */
DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
- define(macid("{dsn_notify}", NULL), NULL, CurEnv);
- CurEnv->e_envid = NULL;
- define(macid("{dsn_envid}", NULL), NULL, CurEnv);
- CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
- define(macid("{dsn_ret}", NULL), NULL, CurEnv);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{dsn_notify}"), NULL);
+ BlankEnvelope.e_envid = NULL;
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{dsn_envid}"), NULL);
+ BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{dsn_ret}"), NULL);
/* don't open maps for daemon -- done below in child */
break;
@@ -1605,7 +2035,8 @@ main(argc, argv, envp)
** Switch to the main envelope.
*/
- CurEnv = newenvelope(&MainEnvelope, CurEnv);
+ CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,
+ sm_rpool_new_x(NULL));
MainEnvelope.e_flags = BlankEnvelope.e_flags;
/*
@@ -1614,82 +2045,191 @@ main(argc, argv, envp)
if (OpMode == MD_TEST)
{
- char buf[MAXLINE];
-
-#if _FFR_TESTMODE_DROP_PRIVS
- dp = drop_privileges(TRUE);
- if (dp != EX_OK)
- {
- CurEnv->e_id = NULL;
- finis(TRUE, dp);
- }
-#endif /* _FFR_TESTMODE_DROP_PRIVS */
-
- if (isatty(fileno(stdin)))
+ if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))
Verbose = 2;
if (Verbose)
{
- printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
- printf("Enter <ruleset> <address>\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Enter <ruleset> <address>\n");
}
- if (setjmp(TopFrame) > 0)
- printf("\n");
- (void) setsignal(SIGINT, intindebug);
+ macdefine(&(MainEnvelope.e_macro), A_PERM,
+ macid("{addr_type}"), "e r");
for (;;)
{
- if (Verbose == 2)
- printf("> ");
- (void) fflush(stdout);
- if (fgets(buf, sizeof buf, stdin) == NULL)
- testmodeline("/quit", CurEnv);
- p = strchr(buf, '\n');
- if (p != NULL)
- *p = '\0';
- if (Verbose < 2)
- printf("> %s\n", buf);
- testmodeline(buf, CurEnv);
+ SM_TRY
+ {
+ (void) sm_signal(SIGINT, intindebug);
+ (void) sm_releasesignal(SIGINT);
+ if (Verbose == 2)
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "> ");
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
+ if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,
+ sizeof buf) == NULL)
+ testmodeline("/quit", &MainEnvelope);
+ p = strchr(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ if (Verbose < 2)
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "> %s\n", buf);
+ testmodeline(buf, &MainEnvelope);
+ }
+ SM_EXCEPT(exc, "[!F]*")
+ {
+ /*
+ ** 8.10 just prints \n on interrupt.
+ ** I'm printing the exception here in case
+ ** sendmail is extended to raise additional
+ ** exceptions in this context.
+ */
+
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\n");
+ sm_exc_print(exc, smioout);
+ }
+ SM_END_TRY
}
}
-#if SMTP
-# if STARTTLS
- tls_ok = init_tls_library();
-# endif /* STARTTLS */
-#endif /* SMTP */
+#if STARTTLS
+ tls_ok = true;
+ if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)
+ {
+ /* check whether STARTTLS is turned off for the client */
+ if (chkclientmodifiers(D_NOTLS))
+ tls_ok = false;
+ }
+ else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||
+ OpMode == MD_SMTP)
+ {
+ /* check whether STARTTLS is turned off for the server */
+ if (chkdaemonmodifiers(D_NOTLS))
+ tls_ok = false;
+ }
+ else /* other modes don't need STARTTLS */
+ tls_ok = false;
+
+ if (tls_ok)
+ {
+ /* basic TLS initialization */
+ tls_ok = init_tls_library();
+ }
+
+ if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
+ {
+ /* disable TLS for client */
+ setclttls(false);
+ }
+#endif /* STARTTLS */
-#if QUEUE
/*
** If collecting stuff from the queue, go start doing that.
*/
if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
{
-# if SMTP
-# if STARTTLS
- if (tls_ok
- )
+ pid_t pid = -1;
+
+#if STARTTLS
+ /* init TLS for client, ignore result for now */
+ (void) initclttls(tls_ok);
+#endif /* STARTTLS */
+
+ /*
+ ** The parent process of the caller of runqueue() needs
+ ** to stay around for a possible SIGTERM. The SIGTERM will
+ ** tell this process that all of the queue runners children
+ ** need to be sent SIGTERM as well. At the same time, we
+ ** want to return control to the command line. So we do an
+ ** extra fork().
+ */
+
+ if (Verbose || foregroundqueue || (pid = fork()) <= 0)
{
- /* init TLS for client, ignore result for now */
- (void) initclttls();
+ /*
+ ** If the fork() failed we should still try to do
+ ** the queue run. If it succeeded then the child
+ ** is going to start the run and wait for all
+ ** of the children to finish.
+ */
+
+ if (pid == 0)
+ {
+ /* Reset global flags */
+ RestartRequest = NULL;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+
+ /* disconnect from terminal */
+ disconnect(2, CurEnv);
+ }
+
+ CurrentPid = getpid();
+ if (qgrp != NOQGRP)
+ {
+ /*
+ ** To run a specific queue group mark it to
+ ** be run, select the work group it's in and
+ ** increment the work counter.
+ */
+
+ runqueueevent(qgrp);
+ (void) run_work_group(Queue[qgrp]->qg_wgrp,
+ false, Verbose,
+ queuepersistent, false);
+ }
+ else
+ (void) runqueue(false, Verbose,
+ queuepersistent, true);
+
+ /* set the title to make it easier to find */
+ sm_setproctitle(true, CurEnv, "Queue control");
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ while (CurChildren > 0)
+ {
+ int status;
+ pid_t ret;
+
+ while ((ret = sm_wait(&status)) <= 0)
+ continue;
+
+ /* Only drop when a child gives status */
+ if (WIFSTOPPED(status))
+ continue;
+
+ proc_list_drop(ret, status, NULL);
+ }
}
-# endif /* STARTTLS */
-# endif /* SMTP */
- (void) runqueue(FALSE, Verbose);
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
+ /* NOTREACHED */
}
-#endif /* QUEUE */
# if SASL
if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
{
- /* give a syserr or just disable AUTH ? */
- if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
+ /* check whether AUTH is turned off for the server */
+ if (!chkdaemonmodifiers(D_NOAUTH) &&
+ (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
syserr("!sasl_server_init failed! [%s]",
- sasl_errstring(i, NULL, NULL));
+ sasl_errstring(i, NULL, NULL));
}
# endif /* SASL */
+ if (OpMode == MD_SMTP)
+ {
+ proc_list_add(CurrentPid, "Sendmail SMTP Agent",
+ PROC_DAEMON, 0, -1);
+
+ /* clean up background delivery children */
+ (void) sm_signal(SIGCHLD, reapchild);
+ }
+
/*
** If a daemon, wait for a request.
** getrequests will always return in a child.
@@ -1710,80 +2250,203 @@ main(argc, argv, envp)
if (i < 0)
syserr("daemon: cannot fork");
if (i != 0)
- finis(FALSE, EX_OK);
+ {
+ finis(false, true, EX_OK);
+ /* NOTREACHED */
+ }
+
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ /* Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ CurrentPid = getpid();
+
+ sm_exc_newthread(fatal_error);
/* disconnect from our controlling tty */
- disconnect(2, CurEnv);
+ disconnect(2, &MainEnvelope);
}
dtype[0] = '\0';
if (OpMode == MD_DAEMON)
- (void) strlcat(dtype, "+SMTP", sizeof dtype);
+ {
+ (void) sm_strlcat(dtype, "+SMTP", sizeof dtype);
+ DaemonPid = CurrentPid;
+ }
if (QueueIntvl != 0)
{
- (void) strlcat(dtype, "+queueing@", sizeof dtype);
- (void) strlcat(dtype, pintvl(QueueIntvl, TRUE),
- sizeof dtype);
+ (void) sm_strlcat2(dtype,
+ queuepersistent
+ ? "+persistent-queueing@"
+ : "+queueing@",
+ pintvl(QueueIntvl, true),
+ sizeof dtype);
}
if (tTd(0, 1))
- (void) strlcat(dtype, "+debugging", sizeof dtype);
+ (void) sm_strlcat(dtype, "+debugging", sizeof dtype);
sm_syslog(LOG_INFO, NOQID,
"starting daemon (%s): %s", Version, dtype + 1);
-#ifdef XLA
+#if XLA
xla_create_file();
#endif /* XLA */
/* save daemon type in a macro for possible PidFile use */
- define(macid("{daemon_info}", NULL),
- newstr(dtype + 1), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{daemon_info}"), dtype + 1);
/* save queue interval in a macro for possible PidFile use */
- define(macid("{queue_interval}", NULL),
- newstr(pintvl(QueueIntvl, TRUE)), CurEnv);
+ macdefine(&MainEnvelope.e_macro, A_TEMP,
+ macid("{queue_interval}"), pintvl(QueueIntvl, true));
+
+ /* workaround: can't seem to release the signal in the parent */
+ (void) sm_signal(SIGHUP, sighup);
+ (void) sm_releasesignal(SIGHUP);
+ (void) sm_signal(SIGTERM, sigterm);
-#if QUEUE
if (QueueIntvl != 0)
{
- (void) runqueue(TRUE, FALSE);
+ (void) runqueue(true, false, queuepersistent, true);
+
+ /*
+ ** If queuepersistent but not in daemon mode then
+ ** we're going to do the queue runner monitoring here.
+ ** If in daemon mode then the monitoring will happen
+ ** elsewhere.
+ */
+
+ if (OpMode != MD_DAEMON && queuepersistent)
+ {
+ /* set the title to make it easier to find */
+ sm_setproctitle(true, CurEnv, "Queue control");
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ while (CurChildren > 0)
+ {
+ int status;
+ pid_t ret;
+ int group;
+
+ if (ShutdownRequest != NULL)
+ shutdown_daemon();
+ else if (RestartRequest != NULL)
+ restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
+
+ while ((ret = sm_wait(&status)) <= 0)
+ continue;
+
+ if (WIFSTOPPED(status))
+ continue;
+
+ /* Probe only on a child status */
+ proc_list_drop(ret, status, &group);
+
+ if (WIFSIGNALED(status))
+ {
+ if (WCOREDUMP(status))
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "persistent queue runner=%d core dumped, signal=%d",
+ group, WTERMSIG(status));
+
+ /* don't restart this one */
+ mark_work_group_restart(group, -1);
+ continue;
+ }
+
+ sm_syslog(LOG_ERR, NOQID,
+ "persistent queue runner=%d died, signal=%d",
+ group, WTERMSIG(status));
+ }
+
+ /*
+ ** When debugging active, don't
+ ** restart the persistent queues.
+ ** But do log this as info.
+ */
+
+ if (sm_debug_active(&DebugNoPRestart,
+ 1))
+ {
+ sm_syslog(LOG_DEBUG, NOQID,
+ "persistent queue runner=%d, exited",
+ group);
+ mark_work_group_restart(group, -1);
+ }
+ }
+ finis(true, true, ExitStat);
+ /* NOTREACHED */
+ }
+
if (OpMode != MD_DAEMON)
{
- /* write the pid to file */
- log_sendmail_pid(CurEnv);
- (void) setsignal(SIGTERM, term_daemon);
+ char qtype[200];
+
+ /*
+ ** Write the pid to file
+ ** XXX Overwrites sendmail.pid
+ */
+
+ log_sendmail_pid(&MainEnvelope);
+
+ /* set the title to make it easier to find */
+ qtype[0] = '\0';
+ (void) sm_strlcpyn(qtype, sizeof qtype, 4,
+ "Queue runner@",
+ pintvl(QueueIntvl, true),
+ " for ",
+ QueueDir);
+ sm_setproctitle(true, CurEnv, qtype);
for (;;)
{
(void) pause();
if (ShutdownRequest != NULL)
shutdown_daemon();
- else if (DoQueueRun)
- (void) runqueue(TRUE, FALSE);
+ else if (RestartRequest != NULL)
+ restart_daemon();
+ else if (RestartWorkGroup)
+ restart_marked_work_groups();
+
+ if (doqueuerun())
+ (void) runqueue(true, false,
+ false, false);
}
}
}
-#endif /* QUEUE */
- dropenvelope(CurEnv, TRUE);
+ dropenvelope(&MainEnvelope, true, false);
-#if DAEMON
-# if STARTTLS
+#if STARTTLS
/* init TLS for server, ignore result for now */
- (void) initsrvtls();
-# endif /* STARTTLS */
- p_flags = getrequests(CurEnv);
+ (void) initsrvtls(tls_ok);
+#endif /* STARTTLS */
+#if PROFILING
+ nextreq:
+#endif /* PROFILING */
+ p_flags = getrequests(&MainEnvelope);
/* drop privileges */
- (void) drop_privileges(FALSE);
-
- /* at this point we are in a child: reset state */
- (void) newenvelope(CurEnv, CurEnv);
+ (void) drop_privileges(false);
/*
** Get authentication data
+ ** Set _ macro in BlankEnvelope before calling newenvelope().
*/
- authinfo = getauthinfo(fileno(InChannel), &forged);
- define('_', authinfo, &BlankEnvelope);
-#endif /* DAEMON */
+ authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
+ NULL), &forged);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
+
+ /* at this point we are in a child: reset state */
+ sm_rpool_free(MainEnvelope.e_rpool);
+ (void) newenvelope(&MainEnvelope, &MainEnvelope,
+ sm_rpool_new_x(NULL));
}
if (LogLevel > 9)
@@ -1792,7 +2455,6 @@ main(argc, argv, envp)
sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo);
}
-#if SMTP
/*
** If running SMTP protocol, start collecting and executing
** commands. This will never return.
@@ -1810,91 +2472,98 @@ main(argc, argv, envp)
{
char ipbuf[103];
- (void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
- anynet_ntoa(&RealHostAddr));
- define(macid("{client_name}", NULL),
- newstr(ipbuf), &BlankEnvelope);
- define(macid("{client_resolve}", NULL),
- "FORGED", &BlankEnvelope);
+ (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
+ anynet_ntoa(&RealHostAddr));
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{client_name}"), ipbuf);
}
else
- define(macid("{client_name}", NULL), RealHostName,
- &BlankEnvelope);
- define(macid("{client_addr}", NULL),
- newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
- (void)sm_getla(&BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{client_name}"), RealHostName);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{client_addr}"), anynet_ntoa(&RealHostAddr));
+ sm_getla();
- switch(RealHostAddr.sa.sa_family)
+ switch (RealHostAddr.sa.sa_family)
{
-# if NETINET
+#if NETINET
case AF_INET:
- (void) snprintf(pbuf, sizeof pbuf, "%d",
- RealHostAddr.sin.sin_port);
+ (void) sm_snprintf(pbuf, sizeof pbuf, "%d",
+ RealHostAddr.sin.sin_port);
break;
-# endif /* NETINET */
-# if NETINET6
+#endif /* NETINET */
+#if NETINET6
case AF_INET6:
- (void) snprintf(pbuf, sizeof pbuf, "%d",
- RealHostAddr.sin6.sin6_port);
+ (void) sm_snprintf(pbuf, sizeof pbuf, "%d",
+ RealHostAddr.sin6.sin6_port);
break;
-# endif /* NETINET6 */
+#endif /* NETINET6 */
default:
- (void) snprintf(pbuf, sizeof pbuf, "0");
+ (void) sm_snprintf(pbuf, sizeof pbuf, "0");
break;
}
- define(macid("{client_port}", NULL),
- newstr(pbuf), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{client_port}"), pbuf);
if (OpMode == MD_DAEMON)
{
/* validate the connection */
- HoldErrs = TRUE;
+ HoldErrs = true;
nullserver = validate_connection(&RealHostAddr,
- RealHostName, CurEnv);
- HoldErrs = FALSE;
+ RealHostName,
+ &MainEnvelope);
+ HoldErrs = false;
}
else if (p_flags == NULL)
{
p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
clrbitmap(p_flags);
}
-# if STARTTLS
+#if STARTTLS
if (OpMode == MD_SMTP)
- (void) initsrvtls();
-# endif /* STARTTLS */
-
-
- smtp(nullserver, *p_flags, CurEnv);
+ (void) initsrvtls(tls_ok);
+#endif /* STARTTLS */
+
+ /* turn off profiling */
+ SM_PROF(1);
+ smtp(nullserver, *p_flags, &MainEnvelope);
+#if PROFILING
+ /* turn off profiling */
+ SM_PROF(0);
+ if (OpMode == MD_DAEMON)
+ goto nextreq;
+#endif /* PROFILING */
}
-#endif /* SMTP */
- clearenvelope(CurEnv, FALSE);
+ sm_rpool_free(MainEnvelope.e_rpool);
+ clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));
if (OpMode == MD_VERIFY)
{
- set_delivery_mode(SM_VERIFY, CurEnv);
+ set_delivery_mode(SM_VERIFY, &MainEnvelope);
PostMasterCopy = NULL;
}
else
{
/* interactive -- all errors are global */
- CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
+ MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
}
/*
** Do basic system initialization and set the sender
*/
- initsys(CurEnv);
- define(macid("{ntries}", NULL), "0", CurEnv);
- setsender(from, CurEnv, NULL, '\0', FALSE);
+ initsys(&MainEnvelope);
+ macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");
+ macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");
+ setsender(from, &MainEnvelope, NULL, '\0', false);
if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
- (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) ||
- strcmp(CurEnv->e_from.q_user, RealUserName) != 0))
+ (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||
+ strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))
{
- auth_warning(CurEnv, "%s set sender to %s using -%c",
- RealUserName, from, warn_f_flag);
+ auth_warning(&MainEnvelope, "%s set sender to %s using -%c",
+ RealUserName, from, warn_f_flag);
#if SASL
- auth = FALSE;
+ auth = false;
#endif /* SASL */
}
if (auth)
@@ -1902,46 +2571,54 @@ main(argc, argv, envp)
char *fv;
/* set the initial sender for AUTH= to $f@$j */
- fv = macvalue('f', CurEnv);
+ fv = macvalue('f', &MainEnvelope);
if (fv == NULL || *fv == '\0')
- CurEnv->e_auth_param = NULL;
+ MainEnvelope.e_auth_param = NULL;
else
{
if (strchr(fv, '@') == NULL)
{
- i = strlen(fv) + strlen(macvalue('j', CurEnv))
- + 2;
- p = xalloc(i);
- (void) snprintf(p, i, "%s@%s", fv,
- macvalue('j', CurEnv));
+ i = strlen(fv) + strlen(macvalue('j',
+ &MainEnvelope)) + 2;
+ p = sm_malloc_x(i);
+ (void) sm_strlcpyn(p, i, 3, fv, "@",
+ macvalue('j',
+ &MainEnvelope));
}
else
- p = newstr(fv);
- CurEnv->e_auth_param = newstr(xtextify(p, "="));
+ p = sm_strdup_x(fv);
+ MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,
+ xtextify(p, "="));
+ sm_free(p); /* XXX */
}
}
- if (macvalue('s', CurEnv) == NULL)
- define('s', RealHostName, CurEnv);
+ if (macvalue('s', &MainEnvelope) == NULL)
+ macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);
+ av = argv + optind;
if (*av == NULL && !GrabTo)
{
- CurEnv->e_to = NULL;
- CurEnv->e_flags |= EF_GLOBALERRS;
- HoldErrs = FALSE;
- SuperSafe = FALSE;
+ MainEnvelope.e_to = NULL;
+ MainEnvelope.e_flags |= EF_GLOBALERRS;
+ HoldErrs = false;
+ SuperSafe = SAFE_NO;
usrerr("Recipient names must be specified");
/* collect body for UUCP return */
if (OpMode != MD_VERIFY)
- collect(InChannel, FALSE, NULL, CurEnv);
- finis(TRUE, EX_USAGE);
+ collect(InChannel, false, NULL, &MainEnvelope);
+ finis(true, true, EX_USAGE);
+ /* NOTREACHED */
}
/*
** Scan argv and deliver the message to everyone.
*/
- sendtoargv(av, CurEnv);
+ save_val = LogUsrErrs;
+ LogUsrErrs = true;
+ sendtoargv(av, &MainEnvelope);
+ LogUsrErrs = save_val;
/* if we have had errors sofar, arrange a meaningful exit stat */
if (Errors > 0 && ExitStat == EX_OK)
@@ -1957,7 +2634,7 @@ main(argc, argv, envp)
{
ADDRESS *q;
- for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
+ for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)
q->q_state = QS_REMOVED;
}
#endif /* _FFR_FIX_DASHT */
@@ -1966,122 +2643,120 @@ main(argc, argv, envp)
** Read the input mail.
*/
- CurEnv->e_to = NULL;
+ MainEnvelope.e_to = NULL;
if (OpMode != MD_VERIFY || GrabTo)
{
- int savederrors = Errors;
- long savedflags = CurEnv->e_flags & EF_FATALERRS;
+ int savederrors;
+ unsigned long savedflags;
- CurEnv->e_flags |= EF_GLOBALERRS;
- CurEnv->e_flags &= ~EF_FATALERRS;
+ /*
+ ** workaround for compiler warning on Irix:
+ ** do not initialize variable in the definition, but
+ ** later on:
+ ** warning(1548): transfer of control bypasses
+ ** initialization of:
+ ** variable "savederrors" (declared at line 2570)
+ ** variable "savedflags" (declared at line 2571)
+ ** goto giveup;
+ */
+
+ savederrors = Errors;
+ savedflags = MainEnvelope.e_flags & EF_FATALERRS;
+ MainEnvelope.e_flags |= EF_GLOBALERRS;
+ MainEnvelope.e_flags &= ~EF_FATALERRS;
Errors = 0;
buffer_errors();
- collect(InChannel, FALSE, NULL, CurEnv);
+ collect(InChannel, false, NULL, &MainEnvelope);
/* header checks failed */
if (Errors > 0)
{
- /* Log who the mail would have gone to */
- if (LogLevel > 8 && CurEnv->e_message != NULL &&
- !GrabTo)
+ giveup:
+ if (!GrabTo)
{
- ADDRESS *a;
-
- for (a = CurEnv->e_sendqueue;
- a != NULL;
- a = a->q_next)
- {
- if (!QS_IS_UNDELIVERED(a->q_state))
- continue;
-
- CurEnv->e_to = a->q_paddr;
- logdelivery(NULL, NULL, NULL,
- CurEnv->e_message,
- NULL, (time_t) 0, CurEnv);
- }
- CurEnv->e_to = NULL;
+ /* Log who the mail would have gone to */
+ logundelrcpts(&MainEnvelope,
+ MainEnvelope.e_message,
+ 8, false);
}
- flush_errors(TRUE);
- finis(TRUE, ExitStat);
+ flush_errors(true);
+ finis(true, true, ExitStat);
/* NOTREACHED */
return -1;
}
/* bail out if message too large */
- if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
+ if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))
{
- finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR);
+ finis(true, true, ExitStat != EX_OK ? ExitStat
+ : EX_DATAERR);
/* NOTREACHED */
return -1;
}
Errors = savederrors;
- CurEnv->e_flags |= savedflags;
+ MainEnvelope.e_flags |= savedflags;
}
errno = 0;
if (tTd(1, 1))
- dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
+ sm_dprintf("From person = \"%s\"\n",
+ MainEnvelope.e_from.q_paddr);
+
+#if _FFR_QUARANTINE
+ /* Check if quarantining stats should be updated */
+ if (MainEnvelope.e_quarmsg != NULL)
+ markstats(&MainEnvelope, NULL, STATS_QUARANTINE);
+#endif /* _FFR_QUARANTINE */
/*
** Actually send everything.
** If verifying, just ack.
*/
- CurEnv->e_from.q_state = QS_SENDER;
- if (tTd(1, 5))
+ if (Errors == 0)
{
- dprintf("main: QS_SENDER ");
- printaddr(&CurEnv->e_from, FALSE);
+ if (!split_by_recipient(&MainEnvelope) &&
+ bitset(EF_FATALERRS, MainEnvelope.e_flags))
+ goto giveup;
}
- CurEnv->e_to = NULL;
- CurrentLA = sm_getla(CurEnv);
- GrabTo = FALSE;
+
+ /* make sure we deliver at least the first envelope */
+ i = FastSplit > 0 ? 0 : -1;
+ for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)
+ {
+ ENVELOPE *next;
+
+ e->e_from.q_state = QS_SENDER;
+ if (tTd(1, 5))
+ {
+ sm_dprintf("main[%d]: QS_SENDER ", i);
+ printaddr(&e->e_from, false);
+ }
+ e->e_to = NULL;
+ sm_getla();
+ GrabTo = false;
#if NAMED_BIND
- _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
- _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
+ _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
+ _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
#endif /* NAMED_BIND */
- sendall(CurEnv, SM_DEFAULT);
+ next = e->e_sibling;
+ e->e_sibling = NULL;
+
+ /* after FastSplit envelopes: queue up */
+ sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);
+ e->e_sibling = next;
+ }
/*
** All done.
** Don't send return error message if in VERIFY mode.
*/
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
/* NOTREACHED */
return ExitStat;
}
- /*
-** QUIESCE -- signal handler for SIGPIPE
-**
-** Parameters:
-** sig -- incoming signal.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Sets StopRequest which should cause the mailq/hoststatus
-** display to stop.
-**
-** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
-** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
-** DOING.
-*/
-
-/* ARGSUSED */
-static SIGFUNC_DECL
-quiesce(sig)
- int sig;
-{
- int save_errno = errno;
-
- FIX_SYSV_SIGNAL(sig, quiesce);
- StopRequest = TRUE;
- errno = save_errno;
- return SIGFUNC_RETURN;
-}
- /*
+/*
** STOP_SENDMAIL -- Stop the running program
**
** Parameters:
@@ -2102,46 +2777,12 @@ stop_sendmail()
(void) setuid(RealUid);
exit(EX_OK);
}
-
- /*
-** INTINDEBUG -- signal handler for SIGINT in -bt mode
-**
-** Parameters:
-** sig -- incoming signal.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** longjmps back to test mode loop.
-**
-** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
-** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
-** DOING.
-**
-** XXX: More work is needed for this signal handler.
-*/
-
-/* ARGSUSED */
-static SIGFUNC_DECL
-intindebug(sig)
- int sig;
-{
- int save_errno = errno;
-
- FIX_SYSV_SIGNAL(sig, intindebug);
- errno = save_errno;
- CHECK_CRITICAL(sig);
-
- errno = save_errno;
- longjmp(TopFrame, 1);
- return SIGFUNC_RETURN;
-}
- /*
+/*
** FINIS -- Clean up and exit.
**
** Parameters:
** drop -- whether or not to drop CurEnv envelope
+** cleanup -- call exit() or _exit()?
** exitstat -- exit status to use for exit() call
**
** Returns:
@@ -2152,75 +2793,144 @@ intindebug(sig)
*/
void
-finis(drop, exitstat)
+finis(drop, cleanup, exitstat)
bool drop;
+ bool cleanup;
volatile int exitstat;
{
/* Still want to process new timeouts added below */
- clear_events();
- (void) releasesignal(SIGALRM);
+ sm_clear_events();
+ (void) sm_releasesignal(SIGALRM);
if (tTd(2, 1))
{
- dprintf("\n====finis: stat %d e_id=%s e_flags=",
- exitstat,
- CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
+ sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
+ exitstat,
+ CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
printenvflags(CurEnv);
}
if (tTd(2, 9))
- printopenfds(FALSE);
+ printopenfds(false);
- /* if we fail in finis(), just exit */
- if (setjmp(TopFrame) != 0)
- {
- /* failed -- just give it up */
- goto forceexit;
- }
+ SM_TRY
+ /*
+ ** Clean up. This might raise E:mta.quickabort
+ */
- /* clean up temp files */
- CurEnv->e_to = NULL;
- if (drop)
- {
- if (CurEnv->e_id != NULL)
- dropenvelope(CurEnv, TRUE);
- else
- poststats(StatFile);
- }
+ /* clean up temp files */
+ CurEnv->e_to = NULL;
+ if (drop)
+ {
+ if (CurEnv->e_id != NULL)
+ {
+ dropenvelope(CurEnv, true, false);
+ sm_rpool_free(CurEnv->e_rpool);
+ CurEnv->e_rpool = NULL;
+ }
+ else
+ poststats(StatFile);
+ }
- /* flush any cached connections */
- mci_flush(TRUE, NULL);
+ /* flush any cached connections */
+ mci_flush(true, NULL);
- /* close maps belonging to this pid */
- closemaps();
+ /* close maps belonging to this pid */
+ closemaps(false);
#if USERDB
- /* close UserDatabase */
- _udbx_close();
+ /* close UserDatabase */
+ _udbx_close();
#endif /* USERDB */
-#ifdef XLA
- /* clean up extended load average stuff */
- xla_all_end();
+#if SASL
+ stop_sasl_client();
+#endif /* SASL */
+
+#if XLA
+ /* clean up extended load average stuff */
+ xla_all_end();
#endif /* XLA */
- /* and exit */
- forceexit:
- if (LogLevel > 78)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "finis, pid=%d",
- (int) getpid());
- if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
- exitstat = EX_OK;
+ SM_FINALLY
+ /*
+ ** And exit.
+ */
+
+ if (LogLevel > 78)
+ sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",
+ (int) CurrentPid);
+ if (exitstat == EX_TEMPFAIL ||
+ CurEnv->e_errormode == EM_BERKNET)
+ exitstat = EX_OK;
+
+ /* XXX clean up queues and related data structures */
+ cleanup_queues();
+#if SM_CONF_SHM
+ cleanup_shm(DaemonPid == getpid());
+#endif /* SM_CONF_SHM */
+
+ /* reset uid for process accounting */
+ endpwent();
+ sm_mbdb_terminate();
+ (void) setuid(RealUid);
+#if SM_HEAP_CHECK
+ /* dump the heap, if we are checking for memory leaks */
+ if (sm_debug_active(&SmHeapCheck, 2))
+ sm_heap_report(smioout,
+ sm_debug_level(&SmHeapCheck) - 1);
+#endif /* SM_HEAP_CHECK */
+ if (sm_debug_active(&SmXtrapReport, 1))
+ sm_dprintf("xtrap count = %d\n", SmXtrapCount);
+ if (cleanup)
+ exit(exitstat);
+ else
+ _exit(exitstat);
+ SM_END_TRY
+}
+/*
+** INTINDEBUG -- signal handler for SIGINT in -bt mode
+**
+** Parameters:
+** sig -- incoming signal.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** longjmps back to test mode loop.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
- sync_queue_time();
+/* Type of an exception generated on SIGINT during address test mode. */
+static const SM_EXC_TYPE_T EtypeInterrupt =
+{
+ SmExcTypeMagic,
+ "S:mta.interrupt",
+ "",
+ sm_etype_printf,
+ "interrupt",
+};
- /* reset uid for process accounting */
- endpwent();
- (void) setuid(RealUid);
- exit(exitstat);
+/* ARGSUSED */
+static SIGFUNC_DECL
+intindebug(sig)
+ int sig;
+{
+ int save_errno = errno;
+
+ FIX_SYSV_SIGNAL(sig, intindebug);
+ errno = save_errno;
+ CHECK_CRITICAL(sig);
+ errno = save_errno;
+ sm_exc_raisenew_x(&EtypeInterrupt);
+ errno = save_errno;
+ return SIGFUNC_RETURN;
}
- /*
-** TERM_DEAMON -- SIGTERM handler for the daemon
+/*
+** SIGTERM -- SIGTERM handler for the daemon
**
** Parameters:
** sig -- signal number.
@@ -2239,53 +2949,77 @@ finis(drop, exitstat)
/* ARGSUSED */
static SIGFUNC_DECL
-term_daemon(sig)
+sigterm(sig)
int sig;
{
int save_errno = errno;
- FIX_SYSV_SIGNAL(sig, term_daemon);
+ FIX_SYSV_SIGNAL(sig, sigterm);
ShutdownRequest = "signal";
errno = save_errno;
return SIGFUNC_RETURN;
}
- /*
-** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
+/*
+** SIGHUP -- handle a SIGHUP signal
**
** Parameters:
-** none.
+** sig -- incoming signal.
**
** Returns:
** none.
**
** Side Effects:
-** closes control socket, exits.
+** Sets RestartRequest which should cause the daemon
+** to restart.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
*/
-void
-shutdown_daemon()
+/* ARGSUSED */
+static SIGFUNC_DECL
+sighup(sig)
+ int sig;
{
- char *reason;
-
- allsignals(TRUE);
-
- reason = ShutdownRequest;
- ShutdownRequest = NULL;
- PendingSignal = 0;
+ int save_errno = errno;
- if (LogLevel > 79)
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)",
- reason == NULL ? "implicit call" : reason);
+ FIX_SYSV_SIGNAL(sig, sighup);
+ RestartRequest = "signal";
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+/*
+** SIGPIPE -- signal handler for SIGPIPE
+**
+** Parameters:
+** sig -- incoming signal.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets StopRequest which should cause the mailq/hoststatus
+** display to stop.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
- FileName = NULL;
- closecontrolsocket(TRUE);
-#ifdef XLA
- xla_all_end();
-#endif /* XLA */
+/* ARGSUSED */
+static SIGFUNC_DECL
+sigpipe(sig)
+ int sig;
+{
+ int save_errno = errno;
- finis(FALSE, EX_OK);
+ FIX_SYSV_SIGNAL(sig, sigpipe);
+ StopRequest = true;
+ errno = save_errno;
+ return SIGFUNC_RETURN;
}
- /*
+/*
** INTSIG -- clean up on interrupt
**
** This just arranges to exit. It pessimizes in that it
@@ -2312,13 +3046,14 @@ SIGFUNC_DECL
intsig(sig)
int sig;
{
- bool drop = FALSE;
+ bool drop = false;
int save_errno = errno;
FIX_SYSV_SIGNAL(sig, intsig);
errno = save_errno;
CHECK_CRITICAL(sig);
- allsignals(TRUE);
+ sm_allsignals(true);
+
if (sig != 0 && LogLevel > 79)
sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
FileName = NULL;
@@ -2344,91 +3079,17 @@ intsig(sig)
for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
q->q_state = QS_DONTSEND;
- /* and don't try to deliver the partial message either */
- if (InChild)
- ExitStat = EX_QUIT;
-
- drop = TRUE;
+ drop = true;
}
else if (OpMode != MD_TEST)
- unlockqueue(CurEnv);
-
- finis(drop, EX_OK);
-}
- /*
-** INITMACROS -- initialize the macro system
-**
-** This just involves defining some macros that are actually
-** used internally as metasymbols to be themselves.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** initializes several macros to be themselves.
-*/
-
-struct metamac MetaMacros[] =
-{
- /* LHS pattern matching characters */
- { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
- { '=', MATCHCLASS }, { '~', MATCHNCLASS },
-
- /* these are RHS metasymbols */
- { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
- { '>', CALLSUBR },
-
- /* the conditional operations */
- { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
-
- /* the hostname lookup characters */
- { '[', HOSTBEGIN }, { ']', HOSTEND },
- { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
-
- /* miscellaneous control characters */
- { '&', MACRODEXPAND },
-
- { '\0', '\0' }
-};
-
-#define MACBINDING(name, mid) \
- stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
- MacroName[mid] = name;
-
-void
-initmacros(e)
- register ENVELOPE *e;
-{
- register struct metamac *m;
- register int c;
- char buf[5];
- extern char *MacroName[MAXMACROID + 1];
-
- for (m = MetaMacros; m->metaname != '\0'; m++)
- {
- buf[0] = m->metaval;
- buf[1] = '\0';
- define(m->metaname, newstr(buf), e);
- }
- buf[0] = MATCHREPL;
- buf[2] = '\0';
- for (c = '0'; c <= '9'; c++)
{
- buf[1] = c;
- define(c, newstr(buf), e);
+ unlockqueue(CurEnv);
}
- /* set defaults for some macros sendmail will use later */
- define('n', "MAILER-DAEMON", e);
-
- /* set up external names for some internal macros */
- MACBINDING("opMode", MID_OPMODE);
- /*XXX should probably add equivalents for all short macros here XXX*/
+ finis(drop, false, EX_OK);
+ /* NOTREACHED */
}
- /*
+/*
** DISCONNECT -- remove our connection with any foreground process
**
** Parameters:
@@ -2456,11 +3117,12 @@ disconnect(droplev, e)
int fd;
if (tTd(52, 1))
- dprintf("disconnect: In %d Out %d, e=%lx\n",
- fileno(InChannel), fileno(OutChannel), (u_long) e);
+ sm_dprintf("disconnect: In %d Out %d, e=%p\n",
+ sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
+ sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);
if (tTd(52, 100))
{
- dprintf("don't\n");
+ sm_dprintf("don't\n");
return;
}
if (LogLevel > 93)
@@ -2469,40 +3131,64 @@ disconnect(droplev, e)
droplev);
/* be sure we don't get nasty signals */
- (void) setsignal(SIGINT, SIG_IGN);
- (void) setsignal(SIGQUIT, SIG_IGN);
+ (void) sm_signal(SIGINT, SIG_IGN);
+ (void) sm_signal(SIGQUIT, SIG_IGN);
/* we can't communicate with our caller, so.... */
- HoldErrs = TRUE;
+ HoldErrs = true;
CurEnv->e_errormode = EM_MAIL;
Verbose = 0;
- DisConnected = TRUE;
+ DisConnected = true;
/* all input from /dev/null */
- if (InChannel != stdin)
+ if (InChannel != smioin)
{
- (void) fclose(InChannel);
- InChannel = stdin;
+ (void) sm_io_close(InChannel, SM_TIME_DEFAULT);
+ InChannel = smioin;
}
- if (freopen("/dev/null", "r", stdin) == NULL)
+ if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
+ SM_IO_RDONLY, NULL, smioin) == NULL)
sm_syslog(LOG_ERR, e->e_id,
- "disconnect: freopen(\"/dev/null\") failed: %s",
- errstring(errno));
+ "disconnect: sm_io_reopen(\"%s\") failed: %s",
+ SM_PATH_DEVNULL, sm_errstring(errno));
- /* output to the transcript */
- if (OutChannel != stdout)
+ /*
+ ** output to the transcript
+ ** We also compare the fd numbers here since OutChannel
+ ** might be a layer on top of smioout due to encryption
+ ** (see sfsasl.c).
+ */
+
+ if (OutChannel != smioout &&
+ sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=
+ sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))
{
- (void) fclose(OutChannel);
- OutChannel = stdout;
+ (void) sm_io_close(OutChannel, SM_TIME_DEFAULT);
+ OutChannel = smioout;
+
+#if 0
+ /*
+ ** Has smioout been closed? Reopen it.
+ ** This shouldn't happen anymore, the code is here
+ ** just as a reminder.
+ */
+
+ if (smioout->sm_magic == NULL &&
+ sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
+ SM_IO_WRONLY, NULL, smioout) == NULL)
+ sm_syslog(LOG_ERR, e->e_id,
+ "disconnect: sm_io_reopen(\"%s\") failed: %s",
+ SM_PATH_DEVNULL, sm_errstring(errno));
+#endif /* 0 */
}
if (droplev > 0)
{
- fd = open("/dev/null", O_WRONLY, 0666);
+ fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);
if (fd == -1)
sm_syslog(LOG_ERR, e->e_id,
- "disconnect: open(\"/dev/null\") failed: %s",
- errstring(errno));
- (void) fflush(stdout);
+ "disconnect: open(\"%s\") failed: %s",
+ SM_PATH_DEVNULL, sm_errstring(errno));
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
(void) dup2(fd, STDOUT_FILENO);
(void) dup2(fd, STDERR_FILENO);
(void) close(fd);
@@ -2520,9 +3206,8 @@ disconnect(droplev, e)
#endif /* XDEBUG */
if (LogLevel > 71)
- sm_syslog(LOG_DEBUG, e->e_id,
- "in background, pid=%d",
- (int) getpid());
+ sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",
+ (int) CurrentPid);
errno = 0;
}
@@ -2540,6 +3225,18 @@ obsolete(argv)
if (ap[0] != '-' || ap[1] == '-')
return;
+#if _FFR_QUARANTINE
+ /* Don't allow users to use "-Q." or "-Q ." */
+ if ((ap[1] == 'Q' && ap[2] == '.') ||
+ (ap[1] == 'Q' && argv[1] != NULL &&
+ argv[1][0] == '.' && argv[1][1] == '\0'))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Can not use -Q.\n");
+ exit(EX_USAGE);
+ }
+#endif /* _FFR_QUARANTINE */
+
/* skip over options that do have a value */
op = strchr(OPTIONS, ap[1]);
if (op != NULL && *++op == ':' && ap[2] == '\0' &&
@@ -2554,18 +3251,24 @@ obsolete(argv)
}
/* If -C doesn't have an argument, use sendmail.cf. */
-#define __DEFPATH "sendmail.cf"
+#define __DEFPATH "sendmail.cf"
if (ap[1] == 'C' && ap[2] == '\0')
{
*argv = xalloc(sizeof(__DEFPATH) + 2);
- (void) snprintf(argv[0], sizeof(__DEFPATH) + 2, "-C%s",
- __DEFPATH);
+ (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,
+ "-C", __DEFPATH);
}
/* If -q doesn't have an argument, run it once. */
if (ap[1] == 'q' && ap[2] == '\0')
*argv = "-q0";
+#if _FFR_QUARANTINE
+ /* If -Q doesn't have an argument, disable quarantining */
+ if (ap[1] == 'Q' && ap[2] == '\0')
+ *argv = "-Q.";
+#endif /* _FFR_QUARANTINE */
+
/* if -d doesn't have an argument, use 0-99.1 */
if (ap[1] == 'd' && ap[2] == '\0')
*argv = "-d0-99.1";
@@ -2581,7 +3284,7 @@ obsolete(argv)
#endif /* defined(sony_news) */
}
}
- /*
+/*
** AUTH_WARNING -- specify authorization warning
**
** Parameters:
@@ -2604,7 +3307,7 @@ auth_warning(e, msg, va_alist)
#endif /* __STDC__ */
{
char buf[MAXLINE];
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
{
@@ -2616,28 +3319,28 @@ auth_warning(e, msg, va_alist)
struct hostent *hp;
hp = myhostname(hostbuf, sizeof hostbuf);
-#if _FFR_FREEHOSTENT && NETINET6
+#if NETINET6
if (hp != NULL)
{
freehostent(hp);
hp = NULL;
}
-#endif /* _FFR_FREEHOSTENT && NETINET6 */
+#endif /* NETINET6 */
}
- (void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": ");
p = &buf[strlen(buf)];
- VA_START(msg);
- vsnprintf(p, SPACELEFT(buf, p), msg, ap);
- VA_END;
- addheader("X-Authentication-Warning", buf, 0, &e->e_header);
+ SM_VA_START(ap, msg);
+ (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);
+ SM_VA_END(ap);
+ addheader("X-Authentication-Warning", buf, 0, e);
if (LogLevel > 3)
sm_syslog(LOG_INFO, e->e_id,
"Authentication-Warning: %.400s",
buf);
}
}
- /*
+/*
** GETEXTENV -- get from external environment
**
** Parameters:
@@ -2647,7 +3350,7 @@ auth_warning(e, msg, va_alist)
** The value, if any.
*/
-char *
+static char *
getextenv(envar)
const char *envar;
{
@@ -2662,8 +3365,8 @@ getextenv(envar)
}
return NULL;
}
- /*
-** SETUSERENV -- set an environment in the propogated environment
+/*
+** SETUSERENV -- set an environment in the propagated environment
**
** Parameters:
** envar -- the name of the environment variable.
@@ -2692,10 +3395,11 @@ setuserenv(envar, value)
return;
}
+ /* XXX enforce reasonable size? */
i = strlen(envar) + 1;
l = strlen(value) + i + 1;
p = (char *) xalloc(l);
- (void) snprintf(p, l, "%s=%s", envar, value);
+ (void) sm_strlcpyn(p, l, 3, envar, "=", value);
while (*evp != NULL && strncmp(*evp, p, i) != 0)
evp++;
@@ -2713,7 +3417,7 @@ setuserenv(envar, value)
if (putenv(p) < 0)
syserr("setuserenv: putenv(%s) failed", p);
}
- /*
+/*
** DUMPSTATE -- dump state
**
** For debugging.
@@ -2738,12 +3442,12 @@ dumpstate(when)
"*** $j not in $=w ***");
}
sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)\n",
+ sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)",
NextMacroId, MAXMACROID);
sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
- printopenfds(TRUE);
+ printopenfds(true);
sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
- mci_dump_all(TRUE);
+ mci_dump_all(true);
rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
if (rs > 0)
{
@@ -2752,7 +3456,7 @@ dumpstate(when)
char *pv[MAXATOM + 1];
pv[0] = NULL;
- status = rewrite(pv, rs, 0, CurEnv);
+ status = REWRITE(pv, rs, CurEnv);
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"--- ruleset debug_dumpstate returns stat %d, pv: ---",
status);
@@ -2761,8 +3465,9 @@ dumpstate(when)
}
sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
}
+
#ifdef SIGUSR1
- /*
+/*
** SIGUSR1 -- Signal a request to dump state.
**
** Parameters:
@@ -2784,16 +3489,23 @@ sigusr1(sig)
int sig;
{
int save_errno = errno;
+# if SM_HEAP_CHECK
+ extern void dumpstab __P((void));
+# endif /* SM_HEAP_CHECK */
FIX_SYSV_SIGNAL(sig, sigusr1);
errno = save_errno;
CHECK_CRITICAL(sig);
dumpstate("user signal");
+# if SM_HEAP_CHECK
+ dumpstab();
+# endif /* SM_HEAP_CHECK */
errno = save_errno;
return SIGFUNC_RETURN;
}
-# endif /* SIGUSR1 */
- /*
+#endif /* SIGUSR1 */
+
+/*
** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
**
** Parameters:
@@ -2813,9 +3525,12 @@ drop_privileges(to_real_uid)
GIDSET_T emptygidset[1];
if (tTd(47, 1))
- dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
- (int)to_real_uid, (int)RealUid,
- (int)RealGid, (int)RunAsUid, (int)RunAsGid);
+ sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n",
+ (int) to_real_uid,
+ (int) RealUid, (int) RealGid,
+ (int) getuid(), (int) getgid(),
+ (int) geteuid(), (int) getegid(),
+ (int) RunAsUid, (int) RunAsGid);
if (to_real_uid)
{
@@ -2826,33 +3541,131 @@ drop_privileges(to_real_uid)
/* make sure no one can grab open descriptors for secret files */
endpwent();
+ sm_mbdb_terminate();
/* reset group permissions; these can be set later */
emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
+
+ /*
+ ** Notice: on some OS (Linux...) the setgroups() call causes
+ ** a logfile entry if sendmail is not run by root.
+ ** However, it is unclear (no POSIX standard) whether
+ ** setgroups() can only succeed if executed by root.
+ ** So for now we keep it as it is; if you want to change it, use
+ ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1)
+ */
+
if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
{
syserr("drop_privileges: setgroups(1, %d) failed",
- (int)emptygidset[0]);
+ (int) emptygidset[0]);
rval = EX_OSERR;
}
- /* reset primary group and user id */
- if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
+ /* reset primary group id */
+ if (to_real_uid)
{
- syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid);
- rval = EX_OSERR;
+ /*
+ ** Drop gid to real gid.
+ ** On some OS we must reset the effective[/real[/saved]] gid,
+ ** and then use setgid() to finally drop all group privileges.
+ ** Later on we check whether we can get back the
+ ** effective gid.
+ */
+
+#if HASSETEGID
+ if (setegid(RunAsGid) < 0)
+ {
+ syserr("drop_privileges: setegid(%d) failed",
+ (int) RunAsGid);
+ rval = EX_OSERR;
+ }
+#else /* HASSETEGID */
+# if HASSETREGID
+ if (setregid(RunAsGid, RunAsGid) < 0)
+ {
+ syserr("drop_privileges: setregid(%d, %d) failed",
+ (int) RunAsGid, (int) RunAsGid);
+ rval = EX_OSERR;
+ }
+# else /* HASSETREGID */
+# if HASSETRESGID
+ if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0)
+ {
+ syserr("drop_privileges: setresgid(%d, %d, %d) failed",
+ (int) RunAsGid, (int) RunAsGid, (int) RunAsGid);
+ rval = EX_OSERR;
+ }
+# endif /* HASSETRESGID */
+# endif /* HASSETREGID */
+#endif /* HASSETEGID */
+ }
+ if (rval == EX_OK && (to_real_uid || RunAsGid != 0))
+ {
+ if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid))
+ {
+ syserr("drop_privileges: setgid(%d) failed",
+ (int) RunAsGid);
+ rval = EX_OSERR;
+ }
+ errno = 0;
+ if (rval == EX_OK && getegid() != RunAsGid)
+ {
+ syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d",
+ (int) getegid(), (int) RunAsGid);
+ rval = EX_OSERR;
+ }
}
+
+ /* fiddle with uid */
if (to_real_uid || RunAsUid != 0)
{
uid_t euid = geteuid();
- if (setuid(RunAsUid) < 0)
+ /*
+ ** Try to setuid(RunAsUid).
+ ** euid must be RunAsUid,
+ ** ruid must be RunAsUid unless it's the MSP and the euid
+ ** wasn't 0 and we didn't have to drop privileges to the
+ ** real uid.
+ */
+
+ if (setuid(RunAsUid) < 0 ||
+ (getuid() != RunAsUid &&
+ (!UseMSP || euid == 0 || to_real_uid )) ||
+ geteuid() != RunAsUid)
{
- syserr("drop_privileges: setuid(%d) failed",
- (int)RunAsUid);
- rval = EX_OSERR;
+#if HASSETREUID
+ /*
+ ** if ruid != RunAsUid, euid == RunAsUid, then
+ ** try resetting just the real uid, then using
+ ** setuid() to drop the saved-uid as well.
+ */
+
+ if (euid == RunAsUid)
+ {
+ if (setreuid(RunAsUid, -1) < 0)
+ {
+ syserr("drop_privileges: setreuid(%d, -1) failed",
+ (int) RunAsUid);
+ rval = EX_OSERR;
+ }
+ if (setuid(RunAsUid) < 0)
+ {
+ syserr("drop_privileges: second setuid(%d) attempt failed",
+ (int) RunAsUid);
+ rval = EX_OSERR;
+ }
+ }
+ else
+#endif /* HASSETREUID */
+ {
+ syserr("drop_privileges: setuid(%d) failed",
+ (int) RunAsUid);
+ rval = EX_OSERR;
+ }
}
- else if (RunAsUid != 0 && setuid(0) == 0)
+ if (RunAsUid != 0 && setuid(0) == 0)
{
/*
** Believe it or not, the Linux capability model
@@ -2872,23 +3685,37 @@ drop_privileges(to_real_uid)
** making it possible to set it back again later.
*/
- syserr("drop_privileges: Unable to drop non-root set-user-id privileges");
+ syserr("drop_privileges: Unable to drop non-root set-user-ID privileges");
rval = EX_OSERR;
}
}
+
+ if ((to_real_uid || RunAsGid != 0) &&
+ rval == EX_OK && RunAsGid != EffGid &&
+ getuid() != 0 && geteuid() != 0)
+ {
+ errno = 0;
+ if (setgid(EffGid) == 0)
+ {
+ syserr("drop_privileges: setgid(%d) succeeded (when it should not)",
+ (int) EffGid);
+ rval = EX_OSERR;
+ }
+ }
+
if (tTd(47, 5))
{
- dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
- (int)geteuid(), (int)getuid(),
- (int)getegid(), (int)getgid());
- dprintf("drop_privileges: RunAsUser = %d:%d\n",
- (int)RunAsUid, (int)RunAsGid);
+ sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
+ (int) geteuid(), (int) getuid(),
+ (int) getegid(), (int) getgid());
+ sm_dprintf("drop_privileges: RunAsUser = %d:%d\n",
+ (int) RunAsUid, (int) RunAsGid);
if (tTd(47, 10))
- dprintf("drop_privileges: rval = %d\n", rval);
+ sm_dprintf("drop_privileges: rval = %d\n", rval);
}
return rval;
}
- /*
+/*
** FILL_FD -- make sure a file descriptor has been properly allocated
**
** Used to make sure that stdin/out/err are allocated on startup
@@ -2901,6 +3728,9 @@ drop_privileges(to_real_uid)
**
** Returns:
** none
+**
+** Side Effects:
+** possibly changes MissingFds
*/
void
@@ -2918,11 +3748,11 @@ fill_fd(fd, where)
syserr("fill_fd: %s: fd %d not open", where, fd);
else
MissingFds |= 1 << fd;
- i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
+ i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666);
if (i < 0)
{
- syserr("!fill_fd: %s: cannot open /dev/null",
- where == NULL ? "startup" : where);
+ syserr("!fill_fd: %s: cannot open %s",
+ where == NULL ? "startup" : where, SM_PATH_DEVNULL);
}
if (fd != i)
{
@@ -2930,7 +3760,42 @@ fill_fd(fd, where)
(void) close(i);
}
}
- /*
+/*
+** SM_PRINTOPTIONS -- print options
+**
+** Parameters:
+** options -- array of options.
+**
+** Returns:
+** none.
+*/
+
+static void
+sm_printoptions(options)
+ char **options;
+{
+ int ll;
+ char **av;
+
+ av = options;
+ ll = 7;
+ while (*av != NULL)
+ {
+ if (ll + strlen(*av) > 63)
+ {
+ sm_dprintf("\n");
+ ll = 0;
+ }
+ if (ll == 0)
+ sm_dprintf("\t\t");
+ else
+ sm_dprintf(" ");
+ sm_dprintf("%s", *av);
+ ll += strlen(*av++) + 1;
+ }
+ sm_dprintf("\n");
+}
+/*
** TESTMODELINE -- process a test mode input line
**
** Parameters:
@@ -2961,11 +3826,7 @@ testmodeline(line, e)
ADDRESS a;
static int tryflags = RF_COPYNONE;
char exbuf[MAXLINE];
- extern u_char TokTypeNoC[];
-
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
+ extern unsigned char TokTypeNoC[];
/* skip leading spaces */
while (*line == ' ')
@@ -2985,18 +3846,18 @@ testmodeline(line, e)
switch (line[1])
{
case 'D':
- mid = macid(&line[2], &delimptr);
+ mid = macid_parse(&line[2], &delimptr);
if (mid == 0)
return;
translate_dollars(delimptr);
- define(mid, newstr(delimptr), e);
+ macdefine(&e->e_macro, A_TEMP, mid, delimptr);
break;
case 'C':
if (line[2] == '\0') /* not to call syserr() */
return;
- mid = macid(&line[2], &delimptr);
+ mid = macid_parse(&line[2], &delimptr);
if (mid == 0)
return;
translate_dollars(delimptr);
@@ -3021,11 +3882,13 @@ testmodeline(line, e)
break;
case '\0':
- printf("Usage: .[DC]macro value(s)\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: .[DC]macro value(s)\n");
break;
default:
- printf("Unknown \".\" command %s\n", line);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown \".\" command %s\n", line);
break;
}
return;
@@ -3037,7 +3900,8 @@ testmodeline(line, e)
rs = strtorwset(&line[2], NULL, ST_FIND);
if (rs < 0)
{
- printf("Undefined ruleset %s\n", &line[2]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Undefined ruleset %s\n", &line[2]);
return;
}
rw = RewriteRules[rs];
@@ -3045,22 +3909,28 @@ testmodeline(line, e)
return;
do
{
- (void) putchar('R');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
+ 'R');
s = rw->r_lhs;
while (*s != NULL)
{
xputs(*s++);
- (void) putchar(' ');
+ (void) sm_io_putc(smioout,
+ SM_TIME_DEFAULT, ' ');
}
- (void) putchar('\t');
- (void) putchar('\t');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
+ '\t');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
+ '\t');
s = rw->r_rhs;
while (*s != NULL)
{
xputs(*s++);
- (void) putchar(' ');
+ (void) sm_io_putc(smioout,
+ SM_TIME_DEFAULT, ' ');
}
- (void) putchar('\n');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
+ '\n');
} while ((rw = rw->r_next) != NULL);
break;
@@ -3073,11 +3943,13 @@ testmodeline(line, e)
break;
case '\0':
- printf("Usage: =Sruleset or =M\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: =Sruleset or =M\n");
break;
default:
- printf("Unknown \"=\" command %s\n", line);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown \"=\" command %s\n", line);
break;
}
return;
@@ -3090,11 +3962,13 @@ testmodeline(line, e)
break;
case '\0':
- printf("Usage: -d{debug arguments}\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: -d{debug arguments}\n");
break;
default:
- printf("Unknown \"-\" command %s\n", line);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown \"-\" command %s\n", line);
break;
}
return;
@@ -3102,21 +3976,23 @@ testmodeline(line, e)
case '$':
if (line[1] == '=')
{
- mid = macid(&line[2], NULL);
+ mid = macid(&line[2]);
if (mid != 0)
stabapply(dump_class, mid);
return;
}
- mid = macid(&line[1], NULL);
+ mid = macid(&line[1]);
if (mid == 0)
return;
p = macvalue(mid, e);
if (p == NULL)
- printf("Undefined\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Undefined\n");
else
{
xputs(p);
- printf("\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\n");
}
return;
@@ -3134,15 +4010,17 @@ testmodeline(line, e)
p = "";
if (line[1] == '\0')
{
- printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /[canon|map|mx|parse|try|tryflags]\n");
return;
}
- if (strcasecmp(&line[1], "quit") == 0)
+ if (sm_strcasecmp(&line[1], "quit") == 0)
{
CurEnv->e_id = NULL;
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
+ /* NOTREACHED */
}
- if (strcasecmp(&line[1], "mx") == 0)
+ if (sm_strcasecmp(&line[1], "mx") == 0)
{
#if NAMED_BIND
/* look up MX records */
@@ -3152,75 +4030,95 @@ testmodeline(line, e)
if (*p == '\0')
{
- printf("Usage: /mx address\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /mx address\n");
return;
}
- nmx = getmxrr(p, mxhosts, NULL, FALSE, &rcode);
- printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
+ nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true,
+ NULL);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "getmxrr(%s) returns %d value(s):\n",
+ p, nmx);
for (i = 0; i < nmx; i++)
- printf("\t%s\n", mxhosts[i]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\t%s\n", mxhosts[i]);
#else /* NAMED_BIND */
- printf("No MX code compiled in\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "No MX code compiled in\n");
#endif /* NAMED_BIND */
}
- else if (strcasecmp(&line[1], "canon") == 0)
+ else if (sm_strcasecmp(&line[1], "canon") == 0)
{
char host[MAXHOSTNAMELEN];
if (*p == '\0')
{
- printf("Usage: /canon address\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /canon address\n");
return;
}
- else if (strlcpy(host, p, sizeof host) >= sizeof host)
+ else if (sm_strlcpy(host, p, sizeof host) >= sizeof host)
{
- printf("Name too long\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Name too long\n");
return;
}
- (void) getcanonname(host, sizeof host, HasWildcardMX);
- printf("getcanonname(%s) returns %s\n", p, host);
+ (void) getcanonname(host, sizeof host, HasWildcardMX,
+ NULL);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "getcanonname(%s) returns %s\n",
+ p, host);
}
- else if (strcasecmp(&line[1], "map") == 0)
+ else if (sm_strcasecmp(&line[1], "map") == 0)
{
auto int rcode = EX_OK;
char *av[2];
if (*p == '\0')
{
- printf("Usage: /map mapname key\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /map mapname key\n");
return;
}
- for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
+ for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
continue;
if (*q == '\0')
{
- printf("No key specified\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "No key specified\n");
return;
}
*q++ = '\0';
map = stab(p, ST_MAP, ST_FIND);
if (map == NULL)
{
- printf("Map named \"%s\" not found\n", p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Map named \"%s\" not found\n", p);
return;
}
if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
!openmap(&(map->s_map)))
{
- printf("Map named \"%s\" not open\n", p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Map named \"%s\" not open\n", p);
return;
}
- printf("map_lookup: %s (%s) ", p, q);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "map_lookup: %s (%s) ", p, q);
av[0] = q;
av[1] = NULL;
p = (*map->s_map.map_class->map_lookup)
(&map->s_map, q, av, &rcode);
if (p == NULL)
- printf("no match (%d)\n", rcode);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "no match (%d)\n",
+ rcode);
else
- printf("returns %s (%d)\n", p, rcode);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "returns %s (%d)\n", p,
+ rcode);
}
- else if (strcasecmp(&line[1], "try") == 0)
+ else if (sm_strcasecmp(&line[1], "try") == 0)
{
MAILER *m;
STAB *st;
@@ -3234,30 +4132,36 @@ testmodeline(line, e)
}
if (q == NULL || *q == '\0')
{
- printf("Usage: /try mailer address\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /try mailer address\n");
return;
}
st = stab(p, ST_MAILER, ST_FIND);
if (st == NULL)
{
- printf("Unknown mailer %s\n", p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown mailer %s\n", p);
return;
}
m = st->s_mailer;
- printf("Trying %s %s address %s for mailer %s\n",
- bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
- bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
- q, p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Trying %s %s address %s for mailer %s\n",
+ bitset(RF_HEADERADDR, tryflags) ? "header"
+ : "envelope",
+ bitset(RF_SENDERADDR, tryflags) ? "sender"
+ : "recipient", q, p);
p = remotename(q, m, tryflags, &rcode, CurEnv);
- printf("Rcode = %d, addr = %s\n",
- rcode, p == NULL ? "<NULL>" : p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Rcode = %d, addr = %s\n",
+ rcode, p == NULL ? "<NULL>" : p);
e->e_to = NULL;
}
- else if (strcasecmp(&line[1], "tryflags") == 0)
+ else if (sm_strcasecmp(&line[1], "tryflags") == 0)
{
if (*p == '\0')
{
- printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
return;
}
for (; *p != '\0'; p++)
@@ -3285,40 +4189,53 @@ testmodeline(line, e)
break;
}
}
-#if _FFR_ADDR_TYPE
exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
exbuf[1] = ' ';
exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
exbuf[3] = '\0';
- define(macid("{addr_type}", NULL), newstr(exbuf), e);
-#endif /* _FFR_ADDR_TYPE */
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{addr_type}"), exbuf);
}
- else if (strcasecmp(&line[1], "parse") == 0)
+ else if (sm_strcasecmp(&line[1], "parse") == 0)
{
if (*p == '\0')
{
- printf("Usage: /parse address\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Usage: /parse address\n");
return;
}
q = crackaddr(p);
- printf("Cracked address = ");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Cracked address = ");
xputs(q);
- printf("\nParsing %s %s address\n",
- bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
- bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
- if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
- printf("Cannot parse\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\nParsing %s %s address\n",
+ bitset(RF_HEADERADDR, tryflags) ?
+ "header" : "envelope",
+ bitset(RF_SENDERADDR, tryflags) ?
+ "sender" : "recipient");
+ if (parseaddr(p, &a, tryflags, '\0', NULL, e, true)
+ == NULL)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Cannot parse\n");
else if (a.q_host != NULL && a.q_host[0] != '\0')
- printf("mailer %s, host %s, user %s\n",
- a.q_mailer->m_name, a.q_host, a.q_user);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "mailer %s, host %s, user %s\n",
+ a.q_mailer->m_name,
+ a.q_host,
+ a.q_user);
else
- printf("mailer %s, user %s\n",
- a.q_mailer->m_name, a.q_user);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "mailer %s, user %s\n",
+ a.q_mailer->m_name,
+ a.q_user);
e->e_to = NULL;
}
else
{
- printf("Unknown \"/\" command %s\n", line);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown \"/\" command %s\n",
+ line);
}
return;
}
@@ -3330,11 +4247,12 @@ testmodeline(line, e)
p++;
if (*p == '\0')
{
- printf("No address!\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "No address!\n");
return;
}
*p = '\0';
- if (invalidaddr(p + 1, NULL))
+ if (invalidaddr(p + 1, NULL, true))
return;
do
{
@@ -3353,13 +4271,16 @@ testmodeline(line, e)
rs = strtorwset(p, NULL, ST_FIND);
if (rs < 0)
{
- printf("Undefined ruleset %s\n", p);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Undefined ruleset %s\n",
+ p);
break;
}
- status = rewrite(pvp, rs, 0, e);
+ status = REWRITE(pvp, rs, e);
if (status != EX_OK)
- printf("== Ruleset %s (%d) status %d\n",
- p, rs, status);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "== Ruleset %s (%d) status %d\n",
+ p, rs, status);
while (*p != '\0' && *p++ != ',')
continue;
}
@@ -3371,8 +4292,26 @@ dump_class(s, id)
register STAB *s;
int id;
{
- if (s->s_type != ST_CLASS)
+ if (s->s_symtype != ST_CLASS)
return;
if (bitnset(bitidx(id), s->s_class))
- printf("%s\n", s->s_name);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s\n", s->s_name);
}
+
+/*
+** An exception type used to create QuickAbort exceptions.
+** This is my first cut at converting QuickAbort from longjmp to exceptions.
+** These exceptions have a single integer argument, which is the argument
+** to longjmp in the original code (either 1 or 2). I don't know the
+** significance of 1 vs 2: the calls to setjmp don't care.
+*/
+
+const SM_EXC_TYPE_T EtypeQuickAbort =
+{
+ SmExcTypeMagic,
+ "E:mta.quickabort",
+ "i",
+ sm_etype_printf,
+ "quick abort %0",
+};
diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c
index 78f8a02..7205da0 100644
--- a/contrib/sendmail/src/map.c
+++ b/contrib/sendmail/src/map.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1992, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1992, 1993
@@ -11,14 +11,15 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: map.c,v 8.414.4.55 2001/08/15 22:08:58 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: map.c,v 8.618 2002/01/11 22:06:52 gshapiro Exp $")
+
+#if LDAPMAP
+# include <sm/ldap.h>
+#endif /* LDAPMAP */
-#ifdef NDBM
+#if NDBM
# include <ndbm.h>
# ifdef R_FIRST
ERROR README: You are running the Berkeley DB version of ndbm.h. See
@@ -27,21 +28,21 @@ static char id[] = "@(#)$Id: map.c,v 8.414.4.55 2001/08/15 22:08:58 gshapiro Exp
ERROR README: and use -DNEWDB instead.
# endif /* R_FIRST */
#endif /* NDBM */
-#ifdef NEWDB
+#if NEWDB
# include <db.h>
# ifndef DB_VERSION_MAJOR
# define DB_VERSION_MAJOR 1
# endif /* ! DB_VERSION_MAJOR */
#endif /* NEWDB */
-#ifdef NIS
+#if NIS
struct dom_binding; /* forward reference needed on IRIX */
# include <rpcsvc/ypclnt.h>
-# ifdef NDBM
+# if NDBM
# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
# endif /* NDBM */
#endif /* NIS */
-#ifdef NEWDB
+#if NEWDB
# if DB_VERSION_MAJOR < 2
static bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
# endif /* DB_VERSION_MAJOR < 2 */
@@ -53,20 +54,15 @@ static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **));
# endif /* DB_VERSION_MAJOR > 2 */
#endif /* NEWDB */
static bool extract_canonname __P((char *, char *, char *, char[], int));
-#ifdef LDAPMAP
-static void ldapmap_clear __P((LDAPMAP_STRUCT *));
-static STAB *ldapmap_findconn __P((LDAPMAP_STRUCT *));
-static int ldapmap_geterrno __P((LDAP *));
-static void ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
-static bool ldapmap_start __P((MAP *));
-static void ldaptimeout __P((int));
-#endif /* LDAPMAP */
static void map_close __P((STAB *, int));
static void map_init __P((STAB *, int));
-#ifdef NISPLUS
+#ifdef LDAPMAP
+static STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *));
+#endif /* LDAPMAP */
+#if NISPLUS
static bool nisplus_getcanonname __P((char *, int, int *));
#endif /* NISPLUS */
-#ifdef NIS
+#if NIS
static bool nis_getcanonname __P((char *, int, int *));
#endif /* NIS */
#if NETINFO
@@ -74,14 +70,25 @@ static bool ni_getcanonname __P((char *, int, int *));
#endif /* NETINFO */
static bool text_getcanonname __P((char *, int, int *));
+/* default error message for trying to open a map in write mode */
+#ifdef ENOSYS
+# define SM_EMAPCANTWRITE ENOSYS
+#else /* ENOSYS */
+# ifdef EFTYPE
+# define SM_EMAPCANTWRITE EFTYPE
+# else /* EFTYPE */
+# define SM_EMAPCANTWRITE ENXIO
+# endif /* EFTYPE */
+#endif /* ENOSYS */
+
/*
** MAP.C -- implementations for various map classes.
**
** Each map class implements a series of functions:
**
** bool map_parse(MAP *map, char *args)
-** Parse the arguments from the config file. Return TRUE
-** if they were ok, FALSE otherwise. Fill in map with the
+** Parse the arguments from the config file. Return true
+** if they were ok, false otherwise. Fill in map with the
** values.
**
** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
@@ -99,9 +106,9 @@ static bool text_getcanonname __P((char *, int, int *));
**
** bool map_open(MAP *map, int mode)
** Open the map for the indicated mode. Mode should
-** be either O_RDONLY or O_RDWR. Return TRUE if it
-** was opened successfully, FALSE otherwise. If the open
-** failed an the MF_OPTIONAL flag is not set, it should
+** be either O_RDONLY or O_RDWR. Return true if it
+** was opened successfully, false otherwise. If the open
+** failed and the MF_OPTIONAL flag is not set, it should
** also print an error. If the MF_ALIAS bit is set
** and this map class understands the @:@ convention, it
** should call aliaswait() before returning.
@@ -116,17 +123,13 @@ static bool text_getcanonname __P((char *, int, int *));
#define DBMMODE 0644
-#ifndef EX_NOTFOUND
-# define EX_NOTFOUND EX_NOHOST
-#endif /* ! EX_NOTFOUND */
-
#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
# define LOCK_ON_OPEN 1 /* we can open/create a locked file */
#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
- /*
+/*
** MAP_PARSEARGS -- parse config line arguments for database lookup
**
** This is a generic version of the map_parse method.
@@ -136,8 +139,8 @@ static bool text_getcanonname __P((char *, int, int *));
** ap -- a pointer to the args on the config line.
**
** Returns:
-** TRUE -- if everything parsed OK.
-** FALSE -- otherwise.
+** true -- if everything parsed OK.
+** false -- otherwise.
**
** Side Effects:
** null terminates the filename; stores it in map
@@ -151,10 +154,11 @@ map_parseargs(map, ap)
register char *p = ap;
/*
- ** there is no check whether there is really an argument,
- ** but that's not important enough to warrant extra code
+ ** There is no check whether there is really an argument,
+ ** but that's not important enough to warrant extra code.
*/
- map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
+
+ map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
map->map_spacesub = SpaceSub; /* default value */
for (;;)
{
@@ -285,11 +289,11 @@ map_parseargs(map, ap)
{
syserr("No file name for %s map %s",
map->map_class->map_cname, map->map_mname);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
- /*
+/*
** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
**
** It also adds the map_app string. It can be used as a utility
@@ -304,9 +308,6 @@ map_parseargs(map, ap)
** Returns:
** Pointer to rewritten result. This is static data that
** should be copied if it is to be saved!
-**
-** Side Effects:
-** none.
*/
char *
@@ -327,15 +328,15 @@ map_rewrite(map, s, slen, av)
if (tTd(39, 1))
{
- dprintf("map_rewrite(%.*s), av =", (int)slen, s);
+ sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
if (av == NULL)
- dprintf(" (nullv)");
+ sm_dprintf(" (nullv)");
else
{
for (avp = av; *avp != NULL; avp++)
- dprintf("\n\t%s", *avp);
+ sm_dprintf("\n\t%s", *avp);
}
- dprintf("\n");
+ sm_dprintf("\n");
}
/* count expected size of output (can safely overestimate) */
@@ -368,7 +369,7 @@ map_rewrite(map, s, slen, av)
buflen = len;
if (buf != NULL)
sm_free(buf);
- buf = xalloc(buflen);
+ buf = sm_pmalloc_x(buflen);
}
bp = buf;
@@ -388,7 +389,7 @@ map_rewrite(map, s, slen, av)
{
pushc:
if (--len <= 0)
- break;
+ break;
*bp++ = c;
continue;
}
@@ -413,14 +414,14 @@ map_rewrite(map, s, slen, av)
}
}
if (map->map_app != NULL && len > 0)
- (void) strlcpy(bp, map->map_app, len);
+ (void) sm_strlcpy(bp, map->map_app, len);
else
*bp = '\0';
if (tTd(39, 1))
- dprintf("map_rewrite => %s\n", buf);
+ sm_dprintf("map_rewrite => %s\n", buf);
return buf;
}
- /*
+/*
** INITMAPS -- rebuild alias maps
**
** Parameters:
@@ -441,7 +442,7 @@ initmaps()
checkfd012("exiting initmaps");
#endif /* XDEBUG */
}
- /*
+/*
** MAP_INIT -- rebuild a map
**
** Parameters:
@@ -464,7 +465,7 @@ map_init(s, unused)
register MAP *map;
/* has to be a map */
- if (s->s_type != ST_MAP)
+ if (s->s_symtype != ST_MAP)
return;
map = &s->s_map;
@@ -472,7 +473,7 @@ map_init(s, unused)
return;
if (tTd(38, 2))
- dprintf("map_init(%s:%s, %s)\n",
+ sm_dprintf("map_init(%s:%s, %s)\n",
map->map_class->map_cname == NULL ? "NULL" :
map->map_class->map_cname,
map->map_mname == NULL ? "NULL" : map->map_mname,
@@ -482,7 +483,7 @@ map_init(s, unused)
!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
{
if (tTd(38, 3))
- dprintf("\tnot rebuildable\n");
+ sm_dprintf("\tnot rebuildable\n");
return;
}
@@ -494,10 +495,10 @@ map_init(s, unused)
map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
}
- (void) rebuildaliases(map, FALSE);
+ (void) rebuildaliases(map, false);
return;
}
- /*
+/*
** OPENMAP -- open a map
**
** Parameters:
@@ -505,39 +506,38 @@ map_init(s, unused)
**
** Returns:
** whether open succeeded.
-**
*/
bool
openmap(map)
MAP *map;
{
- bool restore = FALSE;
+ bool restore = false;
bool savehold = HoldErrs;
bool savequick = QuickAbort;
int saveerrors = Errors;
if (!bitset(MF_VALID, map->map_mflags))
- return FALSE;
+ return false;
/* better safe than sorry... */
if (bitset(MF_OPEN, map->map_mflags))
- return TRUE;
+ return true;
/* Don't send a map open error out via SMTP */
if ((OnlyOneError || QuickAbort) &&
(OpMode == MD_SMTP || OpMode == MD_DAEMON))
{
- restore = TRUE;
- HoldErrs = TRUE;
- QuickAbort = FALSE;
+ restore = true;
+ HoldErrs = true;
+ QuickAbort = false;
}
errno = 0;
if (map->map_class->map_open(map, O_RDONLY))
{
if (tTd(38, 4))
- dprintf("openmap()\t%s:%s %s: valid\n",
+ sm_dprintf("openmap()\t%s:%s %s: valid\n",
map->map_class->map_cname == NULL ? "NULL" :
map->map_class->map_cname,
map->map_mname == NULL ? "NULL" :
@@ -545,12 +545,12 @@ openmap(map)
map->map_file == NULL ? "NULL" :
map->map_file);
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
}
else
{
if (tTd(38, 4))
- dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
+ sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
map->map_class->map_cname == NULL ? "NULL" :
map->map_class->map_cname,
map->map_mname == NULL ? "NULL" :
@@ -558,15 +558,15 @@ openmap(map)
map->map_file == NULL ? "NULL" :
map->map_file,
errno == 0 ? "" : ": ",
- errno == 0 ? "" : errstring(errno));
+ errno == 0 ? "" : sm_errstring(errno));
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
extern MAPCLASS BogusMapClass;
+ map->map_orgclass = map->map_class;
map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- MapOpenErr = TRUE;
+ map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
+ map->map_pid = CurrentPid;
}
else
{
@@ -584,27 +584,28 @@ openmap(map)
return bitset(MF_OPEN, map->map_mflags);
}
- /*
+/*
** CLOSEMAPS -- close all open maps opened by the current pid.
**
** Parameters:
-** none
+** bogus -- only close bogus maps.
**
** Returns:
** none.
*/
void
-closemaps()
+closemaps(bogus)
+ bool bogus;
{
- stabapply(map_close, 0);
+ stabapply(map_close, bogus);
}
- /*
+/*
** MAP_CLOSE -- close a map opened by the current pid.
**
** Parameters:
-** s -- STAB entry: if map: try to open
-** second parameter is unused (required by stabapply())
+** s -- STAB entry: if map: try to close
+** bogus -- only close bogus maps or MCF_NOTPERSIST maps.
**
** Returns:
** none.
@@ -612,78 +613,100 @@ closemaps()
/* ARGSUSED1 */
static void
-map_close(s, unused)
+map_close(s, bogus)
register STAB *s;
- int unused;
+ int bogus; /* int because of stabapply(), used as bool */
{
MAP *map;
+ extern MAPCLASS BogusMapClass;
- if (s->s_type != ST_MAP)
+ if (s->s_symtype != ST_MAP)
return;
map = &s->s_map;
+ /*
+ ** close the map iff:
+ ** it is valid and open and opened by this process
+ ** and (!bogus or it's a bogus map or it is not persistent)
+ ** negate this: return iff
+ ** it is not valid or it is not open or not opened by this process
+ ** or (bogus and it's not a bogus map and it's not not-persistent)
+ */
+
if (!bitset(MF_VALID, map->map_mflags) ||
!bitset(MF_OPEN, map->map_mflags) ||
bitset(MF_CLOSING, map->map_mflags) ||
- map->map_pid != getpid())
+ map->map_pid != CurrentPid ||
+ (bogus && map->map_class != &BogusMapClass &&
+ !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
return;
+ if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
+ map->map_orgclass != &BogusMapClass)
+ map->map_class = map->map_orgclass;
if (tTd(38, 5))
- dprintf("closemaps: closing %s (%s)\n",
+ sm_dprintf("closemaps: closing %s (%s)\n",
map->map_mname == NULL ? "NULL" : map->map_mname,
map->map_file == NULL ? "NULL" : map->map_file);
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
+ if (!bitset(MF_OPENBOGUS, map->map_mflags))
+ {
+ map->map_mflags |= MF_CLOSING;
+ map->map_class->map_close(map);
+ }
+ map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
}
- /*
+/*
** GETCANONNAME -- look up name using service switch
**
** Parameters:
** host -- the host name to look up.
** hbsize -- the size of the host buffer.
** trymx -- if set, try MX records.
+** pttl -- pointer to return TTL (can be NULL).
**
** Returns:
-** TRUE -- if the host was found.
-** FALSE -- otherwise.
+** true -- if the host was found.
+** false -- otherwise.
*/
bool
-getcanonname(host, hbsize, trymx)
+getcanonname(host, hbsize, trymx, pttl)
char *host;
int hbsize;
bool trymx;
+ int *pttl;
{
int nmaps;
int mapno;
- bool found = FALSE;
- bool got_tempfail = FALSE;
+ bool found = false;
+ bool got_tempfail = false;
auto int status;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
nmaps = switch_map_find("hosts", maptype, mapreturn);
+ if (pttl != 0)
+ *pttl = SM_DEFAULT_TTL;
for (mapno = 0; mapno < nmaps; mapno++)
{
int i;
if (tTd(38, 20))
- dprintf("getcanonname(%s), trying %s\n",
+ sm_dprintf("getcanonname(%s), trying %s\n",
host, maptype[mapno]);
if (strcmp("files", maptype[mapno]) == 0)
{
found = text_getcanonname(host, hbsize, &status);
}
-#ifdef NIS
+#if NIS
else if (strcmp("nis", maptype[mapno]) == 0)
{
found = nis_getcanonname(host, hbsize, &status);
}
#endif /* NIS */
-#ifdef NISPLUS
+#if NISPLUS
else if (strcmp("nisplus", maptype[mapno]) == 0)
{
found = nisplus_getcanonname(host, hbsize, &status);
@@ -692,7 +715,7 @@ getcanonname(host, hbsize, trymx)
#if NAMED_BIND
else if (strcmp("dns", maptype[mapno]) == 0)
{
- found = dns_getcanonname(host, hbsize, trymx, &status);
+ found = dns_getcanonname(host, hbsize, trymx, &status, pttl);
}
#endif /* NAMED_BIND */
#if NETINFO
@@ -703,7 +726,7 @@ getcanonname(host, hbsize, trymx)
#endif /* NETINFO */
else
{
- found = FALSE;
+ found = false;
status = EX_UNAVAILABLE;
}
@@ -723,7 +746,7 @@ getcanonname(host, hbsize, trymx)
if (status == EX_TEMPFAIL)
{
i = MA_TRYAGAIN;
- got_tempfail = TRUE;
+ got_tempfail = true;
}
else if (status == EX_NOTFOUND)
i = MA_NOTFOUND;
@@ -738,7 +761,7 @@ getcanonname(host, hbsize, trymx)
char *d;
if (tTd(38, 20))
- dprintf("getcanonname(%s), found\n", host);
+ sm_dprintf("getcanonname(%s), found\n", host);
/*
** If returned name is still single token, compensate
@@ -753,27 +776,29 @@ getcanonname(host, hbsize, trymx)
hbsize > (int) (strlen(host) + strlen(d) + 1))
{
if (host[strlen(host) - 1] != '.')
- (void) strlcat(host, ".", hbsize);
- (void) strlcat(host, d, hbsize);
+ (void) sm_strlcat2(host, ".", d,
+ hbsize);
+ else
+ (void) sm_strlcat(host, d, hbsize);
}
else
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
if (tTd(38, 20))
- dprintf("getcanonname(%s), failed, status=%d\n", host, status);
+ sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
+ status);
-#if NAMED_BIND
if (got_tempfail)
SM_SET_H_ERRNO(TRY_AGAIN);
else
SM_SET_H_ERRNO(HOST_NOT_FOUND);
-#endif /* NAMED_BIND */
- return FALSE;
+
+ return false;
}
- /*
+/*
** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
**
** Parameters:
@@ -784,8 +809,8 @@ getcanonname(host, hbsize, trymx)
** cbuflen -- the size of cbuf.
**
** Returns:
-** TRUE -- if the line matched the desired name.
-** FALSE -- otherwise.
+** true -- if the line matched the desired name.
+** false -- otherwise.
*/
static bool
@@ -798,11 +823,11 @@ extract_canonname(name, dot, line, cbuf, cbuflen)
{
int i;
char *p;
- bool found = FALSE;
+ bool found = false;
cbuf[0] = '\0';
if (line[0] == '#')
- return FALSE;
+ return false;
for (i = 1; ; i++)
{
@@ -816,16 +841,16 @@ extract_canonname(name, dot, line, cbuf, cbuflen)
if (cbuf[0] == '\0' ||
(strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
{
- snprintf(cbuf, cbuflen, "%s", p);
+ (void) sm_strlcpy(cbuf, p, cbuflen);
}
- if (strcasecmp(name, p) == 0)
- found = TRUE;
+ if (sm_strcasecmp(name, p) == 0)
+ found = true;
else if (dot != NULL)
{
/* try looking for the FQDN as well */
*dot = '.';
- if (strcasecmp(name, p) == 0)
- found = TRUE;
+ if (sm_strcasecmp(name, p) == 0)
+ found = true;
*dot = '\0';
}
}
@@ -839,16 +864,484 @@ extract_canonname(name, dot, line, cbuf, cbuflen)
{
p = &cbuf[i];
*p++ = '.';
- (void) strlcpy(p, domain, cbuflen - i - 1);
+ (void) sm_strlcpy(p, domain, cbuflen - i - 1);
}
}
return found;
}
- /*
+
+/*
+** DNS modules
+*/
+
+#if NAMED_BIND
+# if DNSMAP
+
+# include "sm_resolve.h"
+# if NETINET || NETINET6
+# include <arpa/inet.h>
+# endif /* NETINET || NETINET6 */
+
+/*
+** DNS_MAP_OPEN -- stub to check proper value for dns map type
+*/
+
+bool
+dns_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ if (tTd(38,2))
+ sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
+
+ mode &= O_ACCMODE;
+ if (mode != O_RDONLY)
+ {
+ /* issue a pseudo-error message */
+ errno = SM_EMAPCANTWRITE;
+ return false;
+ }
+ return true;
+}
+
+/*
+** DNS_MAP_PARSEARGS -- parse dns map definition args.
+**
+** Parameters:
+** map -- pointer to MAP
+** args -- pointer to the args on the config line.
+**
+** Returns:
+** true -- if everything parsed OK.
+** false -- otherwise.
+*/
+
+# if _FFR_DNSMAP_MULTILIMIT
+# if !_FFR_DNSMAP_MULTI
+ ERROR README: You must define _FFR_DNSMAP_MULTI to use _FFR_DNSMAP_MULTILIMIT
+# endif /* ! _FFR_DNSMAP_MULTI */
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+
+# if _FFR_DNSMAP_MULTI
+# if _FFR_DNSMAP_MULTILIMIT
+# define map_sizelimit map_lockfd /* overload field */
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+# endif /* _FFR_DNSMAP_MULTI */
+
+struct dns_map
+{
+ int dns_m_type;
+};
+
+bool
+dns_map_parseargs(map,args)
+ MAP *map;
+ char *args;
+{
+ register char *p = args;
+ struct dns_map *map_p;
+
+ map_p = (struct dns_map *) xalloc(sizeof *map_p);
+ map_p->dns_m_type = -1;
+ map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
+
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'N':
+ map->map_mflags |= MF_INCLNULL;
+ map->map_mflags &= ~MF_TRY0NULL;
+ break;
+
+ case 'O':
+ map->map_mflags &= ~MF_TRY1NULL;
+ break;
+
+ case 'o':
+ map->map_mflags |= MF_OPTIONAL;
+ break;
+
+ case 'f':
+ map->map_mflags |= MF_NOFOLDCASE;
+ break;
+
+ case 'm':
+ map->map_mflags |= MF_MATCHONLY;
+ break;
+
+ case 'A':
+ map->map_mflags |= MF_APPEND;
+ break;
+
+ case 'q':
+ map->map_mflags |= MF_KEEPQUOTES;
+ break;
+
+ case 't':
+ map->map_mflags |= MF_NODEFER;
+ break;
+
+ case 'a':
+ map->map_app = ++p;
+ break;
+
+ case 'T':
+ map->map_tapp = ++p;
+ break;
+
+ case 'd':
+ {
+ char *h;
+
+ ++p;
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+ map->map_timeout = convtime(p, 's');
+ if (h != NULL)
+ *h = ' ';
+ }
+ break;
+
+ case 'r':
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ map->map_retry = atoi(p);
+ break;
+
+# if _FFR_DNSMAP_MULTI
+ case 'z':
+ if (*++p != '\\')
+ map->map_coldelim = *p;
+ else
+ {
+ switch (*++p)
+ {
+ case 'n':
+ map->map_coldelim = '\n';
+ break;
+
+ case 't':
+ map->map_coldelim = '\t';
+ break;
+
+ default:
+ map->map_coldelim = '\\';
+ }
+ }
+ break;
+
+# if _FFR_DNSMAP_MULTILIMIT
+ case 'Z':
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ map->map_sizelimit = atoi(p);
+ break;
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+# endif /* _FFR_DNSMAP_MULTI */
+
+ /* Start of dns_map specific args */
+ case 'R': /* search field */
+ {
+ char *h;
+
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+ map_p->dns_m_type = dns_string_to_type(p);
+ if (h != NULL)
+ *h = ' ';
+ if (map_p->dns_m_type < 0)
+ syserr("dns map %s: wrong type %s",
+ map->map_mname, p);
+ }
+ break;
+
+# if _FFR_DNSMAP_BASE
+ case 'B': /* base domain */
+ {
+ char *h;
+
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+
+ /*
+ ** slight abuse of map->map_file; it isn't
+ ** used otherwise in this map type.
+ */
+
+ map->map_file = newstr(p);
+ if (h != NULL)
+ *h = ' ';
+ }
+ break;
+# endif /* _FFR_DNSMAP_BASE */
+
+ }
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
+ if (*p != '\0')
+ *p++ = '\0';
+ }
+ if (map_p->dns_m_type < 0)
+ syserr("dns map %s: missing -R type", map->map_mname);
+ if (map->map_app != NULL)
+ map->map_app = newstr(map->map_app);
+ if (map->map_tapp != NULL)
+ map->map_tapp = newstr(map->map_tapp);
+
+ /*
+ ** Assumption: assert(sizeof int <= sizeof(ARBPTR_T));
+ ** Even if this assumption is wrong, we use only one byte,
+ ** so it doesn't really matter.
+ */
+
+ map->map_db1 = (ARBPTR_T) map_p;
+ return true;
+}
+
+/*
+** DNS_MAP_LOOKUP -- perform dns map lookup.
+**
+** Parameters:
+** map -- pointer to MAP
+** name -- name to lookup
+** av -- arguments to interpolate into buf.
+** statp -- pointer to status (EX_)
+**
+** Returns:
+** result of lookup if succeeded.
+** NULL -- otherwise.
+*/
+
+char *
+dns_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+# if _FFR_DNSMAP_MULTI
+# if _FFR_DNSMAP_MULTILIMIT
+ int resnum = 0;
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+# endif /* _FFR_DNSMAP_MULTI */
+ char *vp = NULL, *result = NULL;
+ size_t vsize;
+ struct dns_map *map_p;
+ RESOURCE_RECORD_T *rr = NULL;
+ DNS_REPLY_T *r = NULL;
+# if NETINET6
+ static char buf6[INET6_ADDRSTRLEN];
+# endif /* NETINET6 */
+
+ if (tTd(38, 20))
+ sm_dprintf("dns_map_lookup(%s, %s)\n",
+ map->map_mname, name);
+
+ map_p = (struct dns_map *)(map->map_db1);
+# if _FFR_DNSMAP_BASE
+ if (map->map_file != NULL && *map->map_file != '\0')
+ {
+ size_t len;
+ char *appdomain;
+
+ len = strlen(map->map_file) + strlen(name) + 2;
+ appdomain = (char *) sm_malloc(len);
+ if (appdomain == NULL)
+ {
+ *statp = EX_UNAVAILABLE;
+ return NULL;
+ }
+ (void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
+ r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
+ map->map_timeout, map->map_retry);
+ sm_free(appdomain);
+ }
+ else
+# endif /* _FFR_DNSMAP_BASE */
+ {
+ r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
+ map->map_timeout, map->map_retry);
+ }
+
+ if (r == NULL)
+ {
+ result = NULL;
+ if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
+ errno == ECONNREFUSED)
+ *statp = EX_TEMPFAIL;
+ else
+ *statp = EX_NOTFOUND;
+ goto cleanup;
+ }
+ *statp = EX_OK;
+ for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
+ {
+ char *type = NULL;
+ char *value = NULL;
+
+ switch (rr->rr_type)
+ {
+ case T_NS:
+ type = "T_NS";
+ value = rr->rr_u.rr_txt;
+ break;
+ case T_CNAME:
+ type = "T_CNAME";
+ value = rr->rr_u.rr_txt;
+ break;
+ case T_AFSDB:
+ type = "T_AFSDB";
+ value = rr->rr_u.rr_mx->mx_r_domain;
+ break;
+ case T_SRV:
+ type = "T_SRV";
+ value = rr->rr_u.rr_srv->srv_r_target;
+ break;
+ case T_PTR:
+ type = "T_PTR";
+ value = rr->rr_u.rr_txt;
+ break;
+ case T_TXT:
+ type = "T_TXT";
+ value = rr->rr_u.rr_txt;
+ break;
+ case T_MX:
+ type = "T_MX";
+ value = rr->rr_u.rr_mx->mx_r_domain;
+ break;
+# if NETINET
+ case T_A:
+ type = "T_A";
+ value = inet_ntoa(*(rr->rr_u.rr_a));
+ break;
+# endif /* NETINET */
+# if NETINET6
+ case T_AAAA:
+ type = "T_AAAA";
+ value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
+ sizeof buf6);
+ break;
+# endif /* NETINET6 */
+ }
+
+ if (map_p->dns_m_type != rr->rr_type)
+ {
+ if (tTd(38, 40))
+ sm_dprintf("\tskipping type %s (%d) value %s\n",
+ type != NULL ? type : "<UNKNOWN>",
+ rr->rr_type,
+ value != NULL ? value : "<NO VALUE>");
+ continue;
+ }
+
+# if NETINET6
+ if (rr->rr_type == T_AAAA && value == NULL)
+ {
+ result = NULL;
+ *statp = EX_DATAERR;
+ if (tTd(38, 40))
+ sm_dprintf("\tbad T_AAAA conversion\n");
+ goto cleanup;
+ }
+# endif /* NETINET6 */
+ if (tTd(38, 40))
+ sm_dprintf("\tfound type %s (%d) value %s\n",
+ type != NULL ? type : "<UNKNOWN>",
+ rr->rr_type,
+ value != NULL ? value : "<NO VALUE>");
+# if _FFR_DNSMAP_MULTI
+ if (value != NULL &&
+ (map->map_coldelim == '\0' ||
+# if _FFR_DNSMAP_MULTILIMIT
+ map->map_sizelimit == 1 ||
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+ bitset(MF_MATCHONLY, map->map_mflags)))
+ {
+ /* Only care about the first match */
+ vp = newstr(value);
+ break;
+ }
+ else if (vp == NULL)
+ {
+ /* First result */
+ vp = newstr(value);
+ }
+ else
+ {
+ /* concatenate the results */
+ int sz;
+ char *new;
+
+ sz = strlen(vp) + strlen(value) + 2;
+ new = xalloc(sz);
+ (void) sm_snprintf(new, sz, "%s%c%s",
+ vp, map->map_coldelim, value);
+ sm_free(vp);
+ vp = new;
+# if _FFR_DNSMAP_MULTILIMIT
+ if (map->map_sizelimit > 0 &&
+ ++resnum >= map->map_sizelimit)
+ break;
+# endif /* _FFR_DNSMAP_MULTILIMIT */
+ }
+# else /* _FFR_DNSMAP_MULTI */
+ vp = value;
+ break;
+# endif /* _FFR_DNSMAP_MULTI */
+ }
+ if (vp == NULL)
+ {
+ result = NULL;
+ *statp = EX_NOTFOUND;
+ if (tTd(38, 40))
+ sm_dprintf("\tno match found\n");
+ goto cleanup;
+ }
+
+# if _FFR_DNSMAP_MULTI
+ /* Cleanly truncate for rulesets */
+ truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
+# endif /* _FFR_DNSMAP_MULTI */
+
+ vsize = strlen(vp);
+
+ if (LogLevel > 9)
+ sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
+ name, vp);
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ result = map_rewrite(map, name, strlen(name), NULL);
+ else
+ result = map_rewrite(map, vp, vsize, av);
+
+ cleanup:
+# if _FFR_DNSMAP_MULTI
+ if (vp != NULL)
+ sm_free(vp);
+# endif /* _FFR_DNSMAP_MULTI */
+ if (r != NULL)
+ dns_free_data(r);
+ return result;
+}
+# endif /* DNSMAP */
+#endif /* NAMED_BIND */
+
+/*
** NDBM modules
*/
-#ifdef NDBM
+#if NDBM
/*
** NDBM_MAP_OPEN -- DBM-style map open
@@ -872,14 +1365,14 @@ ndbm_map_open(map, mode)
struct stat std, stp;
if (tTd(38, 2))
- dprintf("ndbm_map_open(%s, %s, %d)\n",
+ sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
map->map_lockfd = -1;
mode &= O_ACCMODE;
/* do initial file and directory checks */
- snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
- snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
+ (void) sm_strlcpyn(dirfile, sizeof dirfile, 2, map->map_file, ".dir");
+ (void) sm_strlcpyn(pagfile, sizeof pagfile, 2, map->map_file, ".pag");
sff = SFF_ROOTOK|SFF_REGONLY;
if (mode == O_RDWR)
{
@@ -898,31 +1391,11 @@ ndbm_map_open(map, mode)
if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
sff |= SFF_SAFEDIRPATH;
ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &std);
+ sff, smode, &std);
if (ret == 0)
ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
sff, smode, &stp);
-# if !_FFR_REMOVE_AUTOREBUILD
- if (ret == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_NDBM, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
-
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_NDBM;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return ndbm_map_open(map, O_RDONLY);
- }
-# endif /* !_FFR_REMOVE_AUTOREBUILD */
-
if (ret != 0)
{
char *prob = "unsafe";
@@ -931,11 +1404,11 @@ ndbm_map_open(map, mode)
if (ret == ENOENT)
prob = "missing";
if (tTd(38, 2))
- dprintf("\t%s map file: %d\n", prob, ret);
+ sm_dprintf("\t%s map file: %d\n", prob, ret);
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("dbm map \"%s\": %s map file %s",
map->map_mname, prob, map->map_file);
- return FALSE;
+ return false;
}
if (std.st_mode == ST_MODE_NOFILE)
mode |= O_CREAT|O_EXCL;
@@ -986,7 +1459,7 @@ ndbm_map_open(map, mode)
errno = save_errno;
syserr("ndbm_map_open: cannot create database %s",
map->map_file);
- return FALSE;
+ return false;
}
if (ftruncate(dirfd, (off_t) 0) < 0 ||
ftruncate(pagfd, (off_t) 0) < 0)
@@ -997,7 +1470,7 @@ ndbm_map_open(map, mode)
errno = save_errno;
syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
map->map_file);
- return FALSE;
+ return false;
}
/* if new file, get "before" bits for later filechanged check */
@@ -1010,7 +1483,7 @@ ndbm_map_open(map, mode)
errno = save_errno;
syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
map->map_file);
- return FALSE;
+ return false;
}
/* have to save the lock for the duration (bletch) */
@@ -1029,8 +1502,8 @@ ndbm_map_open(map, mode)
{
save_errno = errno;
if (bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".pag", FALSE))
- return TRUE;
+ aliaswait(map, ".pag", false))
+ return true;
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
@@ -1038,7 +1511,7 @@ ndbm_map_open(map, mode)
errno = save_errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("Cannot open DBM database %s", map->map_file);
- return FALSE;
+ return false;
}
dfd = dbm_dirfno(dbm);
pfd = dbm_pagfno(dbm);
@@ -1053,7 +1526,7 @@ ndbm_map_open(map, mode)
errno = 0;
syserr("dbm map \"%s\": cannot support GDBM",
map->map_mname);
- return FALSE;
+ return false;
}
if (filechanged(dirfile, dfd, &std) ||
@@ -1068,7 +1541,7 @@ ndbm_map_open(map, mode)
errno = save_errno;
syserr("ndbm_map_open(%s): file changed after open",
map->map_file);
- return FALSE;
+ return false;
}
map->map_db1 = (ARBPTR_T) dbm;
@@ -1091,8 +1564,8 @@ ndbm_map_open(map, mode)
(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
# endif /* LOCK_ON_OPEN */
if (bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".pag", TRUE))
- return FALSE;
+ !aliaswait(map, ".pag", true))
+ return false;
}
else
{
@@ -1107,14 +1580,20 @@ ndbm_map_open(map, mode)
sm_syslog(LOG_ALERT, NOQID,
"ownership change on %s failed: %s",
- map->map_file, errstring(err));
+ map->map_file, sm_errstring(err));
message("050 ownership change on %s failed: %s",
- map->map_file, errstring(err));
+ map->map_file, sm_errstring(err));
}
+# else /* HASFCHOWN */
+ sm_syslog(LOG_ALERT, NOQID,
+ "no fchown(): cannot change ownership on %s",
+ map->map_file);
+ message("050 no fchown(): cannot change ownership on %s",
+ map->map_file);
# endif /* HASFCHOWN */
}
}
- return TRUE;
+ return true;
}
@@ -1135,7 +1614,7 @@ ndbm_map_lookup(map, name, av, statp)
struct stat stbuf;
if (tTd(38, 20))
- dprintf("ndbm_map_lookup(%s, %s)\n",
+ sm_dprintf("ndbm_map_lookup(%s, %s)\n",
map->map_mname, name);
key.dptr = name;
@@ -1169,7 +1648,7 @@ lockdbm:
if (map->map_class->map_open(map, omode))
{
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
if ((omode && O_ACCMODE) == O_RDWR)
map->map_mflags |= MF_WRITABLE;
goto lockdbm;
@@ -1181,9 +1660,10 @@ lockdbm:
extern MAPCLASS BogusMapClass;
*statp = EX_TEMPFAIL;
+ map->map_orgclass = map->map_class;
map->map_class = &BogusMapClass;
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
syserr("Cannot reopen NDBM database %s",
map->map_file);
}
@@ -1231,7 +1711,7 @@ ndbm_map_store(map, lhs, rhs)
char keybuf[MAXNAME + 1];
if (tTd(38, 12))
- dprintf("ndbm_map_store(%s, %s, %s)\n",
+ sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
map->map_mname, lhs, rhs);
key.dsize = strlen(lhs);
@@ -1268,23 +1748,23 @@ ndbm_map_store(map, lhs, rhs)
datum old;
old.dptr = ndbm_map_lookup(map, key.dptr,
- (char **)NULL, &xstat);
+ (char **) NULL, &xstat);
if (old.dptr != NULL && *(char *) old.dptr != '\0')
{
old.dsize = strlen(old.dptr);
if (data.dsize + old.dsize + 2 > bufsiz)
{
if (buf != NULL)
- sm_free(buf);
+ (void) sm_free(buf);
bufsiz = data.dsize + old.dsize + 2;
- buf = xalloc(bufsiz);
+ buf = sm_pmalloc_x(bufsiz);
}
- snprintf(buf, bufsiz, "%s,%s",
- data.dptr, old.dptr);
+ (void) sm_strlcpyn(buf, bufsiz, 3,
+ data.dptr, ",", old.dptr);
data.dsize = data.dsize + old.dsize + 1;
data.dptr = buf;
if (tTd(38, 9))
- dprintf("ndbm_map_store append=%s\n",
+ sm_dprintf("ndbm_map_store append=%s\n",
data.dptr);
}
}
@@ -1305,7 +1785,7 @@ ndbm_map_close(map)
register MAP *map;
{
if (tTd(38, 9))
- dprintf("ndbm_map_close(%s, %s, %lx)\n",
+ sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
map->map_mname, map->map_file, map->map_mflags);
if (bitset(MF_WRITABLE, map->map_mflags))
@@ -1323,7 +1803,7 @@ ndbm_map_close(map)
map->map_mflags |= MF_NOFOLDCASE;
- (void) snprintf(buf, sizeof buf, "%010ld", curtime());
+ (void) sm_snprintf(buf, sizeof buf, "%010ld", curtime());
ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
(void) gethostname(buf, sizeof buf);
@@ -1349,11 +1829,11 @@ ndbm_map_close(map)
}
#endif /* NDBM */
- /*
+/*
** NEWDB (Hash and BTree) Modules
*/
-#ifdef NEWDB
+#if NEWDB
/*
** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
@@ -1395,7 +1875,7 @@ bt_map_open(map, mode)
# endif /* DB_VERSION_MAJOR > 2 */
if (tTd(38, 2))
- dprintf("bt_map_open(%s, %s, %d)\n",
+ sm_dprintf("bt_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
# if DB_VERSION_MAJOR < 3
@@ -1424,7 +1904,7 @@ hash_map_open(map, mode)
# endif /* DB_VERSION_MAJOR > 2 */
if (tTd(38, 2))
- dprintf("hash_map_open(%s, %s, %d)\n",
+ sm_dprintf("hash_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
# if DB_VERSION_MAJOR < 3
@@ -1467,10 +1947,10 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
char buf[MAXNAME + 1];
/* do initial file and directory checks */
- (void) strlcpy(buf, map->map_file, sizeof buf - 3);
+ (void) sm_strlcpy(buf, map->map_file, sizeof buf - 3);
i = strlen(buf);
if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
- (void) strlcat(buf, ".db", sizeof buf);
+ (void) sm_strlcat(buf, ".db", sizeof buf);
mode &= O_ACCMODE;
omode = mode;
@@ -1494,27 +1974,6 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
sff |= SFF_SAFEDIRPATH;
i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
-# if !_FFR_REMOVE_AUTOREBUILD
- if (i == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_HASH, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
-
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_HASH;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return db_map_open(map, O_RDONLY, mapclassname,
- dbtype, openinfo);
- }
-# endif /* !_FFR_REMOVE_AUTOREBUILD */
-
if (i != 0)
{
char *prob = "unsafe";
@@ -1523,12 +1982,12 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
if (i == ENOENT)
prob = "missing";
if (tTd(38, 2))
- dprintf("\t%s map file: %s\n", prob, errstring(i));
+ sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
errno = i;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("%s map \"%s\": %s map file %s",
mapclassname, map->map_mname, prob, buf);
- return FALSE;
+ return false;
}
if (st.st_mode == ST_MODE_NOFILE)
omode |= O_CREAT|O_EXCL;
@@ -1552,7 +2011,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
{
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("db_map_open: cannot pre-open database %s", buf);
- return FALSE;
+ return false;
}
/* make sure no baddies slipped in just before the open... */
@@ -1562,7 +2021,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
(void) close(fd);
errno = save_errno;
syserr("db_map_open(%s): file changed after pre-open", buf);
- return FALSE;
+ return false;
}
/* if new file, get the "before" bits for later filechanged check */
@@ -1573,7 +2032,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
errno = save_errno;
syserr("db_map_open(%s): cannot fstat pre-opened file",
buf);
- return FALSE;
+ return false;
}
/* actually lock the pre-opened file */
@@ -1662,8 +2121,8 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
if (db == NULL)
{
if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".db", FALSE))
- return TRUE;
+ aliaswait(map, ".db", false))
+ return true;
# if !LOCK_ON_OPEN
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
@@ -1672,7 +2131,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("Cannot open %s database %s",
mapclassname, buf);
- return FALSE;
+ return false;
}
# if DB_VERSION_MAJOR < 2
@@ -1695,7 +2154,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
# endif /* !LOCK_ON_OPEN */
errno = save_errno;
syserr("db_map_open(%s): file changed after open", buf);
- return FALSE;
+ return false;
}
if (mode == O_RDWR)
@@ -1720,10 +2179,16 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
sm_syslog(LOG_ALERT, NOQID,
"ownership change on %s failed: %s",
- buf, errstring(err));
+ buf, sm_errstring(err));
message("050 ownership change on %s failed: %s",
- buf, errstring(err));
+ buf, sm_errstring(err));
}
+# else /* HASFCHOWN */
+ sm_syslog(LOG_ALERT, NOQID,
+ "no fchown(): cannot change ownership on %s",
+ map->map_file);
+ message("050 no fchown(): cannot change ownership on %s",
+ map->map_file);
# endif /* HASFCHOWN */
}
}
@@ -1740,9 +2205,9 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
map->map_mtime = st.st_mtime;
if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".db", TRUE))
- return FALSE;
- return TRUE;
+ !aliaswait(map, ".db", true))
+ return false;
+ return true;
}
@@ -1771,13 +2236,13 @@ db_map_lookup(map, name, av, statp)
memset(&val, '\0', sizeof val);
if (tTd(38, 20))
- dprintf("db_map_lookup(%s, %s)\n",
+ sm_dprintf("db_map_lookup(%s, %s)\n",
map->map_mname, name);
i = strlen(map->map_file);
if (i > MAXNAME)
i = MAXNAME;
- (void) strlcpy(buf, map->map_file, i + 1);
+ (void) sm_strlcpy(buf, map->map_file, i + 1);
if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
buf[i - 3] = '\0';
@@ -1812,7 +2277,7 @@ db_map_lookup(map, name, av, statp)
if (map->map_class->map_open(map, omode))
{
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
if ((omode && O_ACCMODE) == O_RDWR)
map->map_mflags |= MF_WRITABLE;
db = (DB *) map->map_db2;
@@ -1825,9 +2290,10 @@ db_map_lookup(map, name, av, statp)
extern MAPCLASS BogusMapClass;
*statp = EX_TEMPFAIL;
+ map->map_orgclass = map->map_class;
map->map_class = &BogusMapClass;
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
syserr("Cannot reopen DB database %s",
map->map_file);
}
@@ -1924,7 +2390,7 @@ db_map_store(map, lhs, rhs)
memset(&data, '\0', sizeof data);
if (tTd(38, 12))
- dprintf("db_map_store(%s, %s, %s)\n",
+ sm_dprintf("db_map_store(%s, %s, %s)\n",
map->map_mname, lhs, rhs);
key.size = strlen(lhs);
@@ -1980,23 +2446,24 @@ db_map_store(map, lhs, rhs)
memset(&old, '\0', sizeof old);
old.data = db_map_lookup(map, key.data,
- (char **)NULL, &status);
+ (char **) NULL, &status);
if (old.data != NULL)
{
old.size = strlen(old.data);
- if (data.size + old.size + 2 > (size_t)bufsiz)
+ if (data.size + old.size + 2 > (size_t) bufsiz)
{
if (buf != NULL)
sm_free(buf);
bufsiz = data.size + old.size + 2;
- buf = xalloc(bufsiz);
+ buf = sm_pmalloc_x(bufsiz);
}
- snprintf(buf, bufsiz, "%s,%s",
- (char *) data.data, (char *) old.data);
+ (void) sm_strlcpyn(buf, bufsiz, 3,
+ (char *) data.data, ",",
+ (char *) old.data);
data.size = data.size + old.size + 1;
data.data = buf;
if (tTd(38, 9))
- dprintf("db_map_store append=%s\n",
+ sm_dprintf("db_map_store append=%s\n",
(char *) data.data);
}
}
@@ -2022,7 +2489,7 @@ db_map_close(map)
register DB *db = map->map_db2;
if (tTd(38, 9))
- dprintf("db_map_close(%s, %s, %lx)\n",
+ sm_dprintf("db_map_close(%s, %s, %lx)\n",
map->map_mname, map->map_file, map->map_mflags);
if (bitset(MF_WRITABLE, map->map_mflags))
@@ -2054,7 +2521,8 @@ db_map_close(map)
** process, do not close the map but recover
** the file descriptor.
*/
- if (map->map_pid != getpid())
+
+ if (map->map_pid != CurrentPid)
{
int fd = -1;
@@ -2070,11 +2538,11 @@ db_map_close(map)
map->map_mname, map->map_file, map->map_mflags);
}
#endif /* NEWDB */
- /*
+/*
** NIS Modules
*/
-#ifdef NIS
+#if NIS
# ifndef YPERR_BUSY
# define YPERR_BUSY 16
@@ -2095,23 +2563,15 @@ nis_map_open(map, mode)
auto int vsize;
if (tTd(38, 2))
- dprintf("nis_map_open(%s, %s, %d)\n",
+ sm_dprintf("nis_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
/* issue a pseudo-error message */
-# ifdef ENOSYS
- errno = ENOSYS;
-# else /* ENOSYS */
-# ifdef EFTYPE
- errno = EFTYPE;
-# else /* EFTYPE */
- errno = ENXIO;
-# endif /* EFTYPE */
-# endif /* ENOSYS */
- return FALSE;
+ errno = SM_EMAPCANTWRITE;
+ return false;
}
p = strchr(map->map_file, '@');
@@ -2133,7 +2593,7 @@ nis_map_open(map, mode)
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("421 4.3.5 NIS map %s specified, but NIS not running",
map->map_file);
- return FALSE;
+ return false;
}
}
@@ -2142,7 +2602,7 @@ nis_map_open(map, mode)
yperr = yp_match(map->map_domain, map->map_file, "@", 1,
&vp, &vsize);
if (tTd(38, 10))
- dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
+ sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
map->map_domain, map->map_file, yperr_string(yperr));
if (vp != NULL)
sm_free(vp);
@@ -2158,9 +2618,9 @@ nis_map_open(map, mode)
# if 0
if (!bitset(MF_ALIAS, map->map_mflags) ||
- aliaswait(map, NULL, TRUE))
+ aliaswait(map, NULL, true))
# endif /* 0 */
- return TRUE;
+ return true;
}
if (!bitset(MF_OPTIONAL, map->map_mflags))
@@ -2169,7 +2629,7 @@ nis_map_open(map, mode)
map->map_file, map->map_domain, yperr_string(yperr));
}
- return FALSE;
+ return false;
}
@@ -2190,9 +2650,10 @@ nis_map_lookup(map, name, av, statp)
int buflen;
int yperr;
char keybuf[MAXNAME + 1];
+ char *SM_NONVOLATILE result = NULL;
if (tTd(38, 20))
- dprintf("nis_map_lookup(%s, %s)\n",
+ sm_dprintf("nis_map_lookup(%s, %s)\n",
map->map_mname, name);
buflen = strlen(name);
@@ -2213,11 +2674,7 @@ nis_map_lookup(map, name, av, statp)
}
if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
{
- if (vp != NULL)
- {
- sm_free(vp);
- vp = NULL;
- }
+ SM_FREE_CLR(vp);
buflen++;
yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
&vp, &vsize);
@@ -2232,17 +2689,16 @@ nis_map_lookup(map, name, av, statp)
sm_free(vp);
return NULL;
}
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- {
- char *ret;
-
- ret = map_rewrite(map, vp, vsize, av);
+ SM_TRY
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ result = map_rewrite(map, name, strlen(name), NULL);
+ else
+ result = map_rewrite(map, vp, vsize, av);
+ SM_FINALLY
if (vp != NULL)
sm_free(vp);
- return ret;
- }
+ SM_END_TRY
+ return result;
}
@@ -2260,20 +2716,20 @@ nis_getcanonname(name, hbsize, statp)
auto int vsize;
int keylen;
int yperr;
- static bool try0null = TRUE;
- static bool try1null = TRUE;
+ static bool try0null = true;
+ static bool try1null = true;
static char *yp_domain = NULL;
char host_record[MAXLINE];
char cbuf[MAXNAME];
char nbuf[MAXNAME + 1];
if (tTd(38, 20))
- dprintf("nis_getcanonname(%s)\n", name);
+ sm_dprintf("nis_getcanonname(%s)\n", name);
- if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
+ if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
(void) shorten_hostname(nbuf);
keylen = strlen(nbuf);
@@ -2288,20 +2744,16 @@ nis_getcanonname(name, hbsize, statp)
yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
&vp, &vsize);
if (yperr == 0)
- try1null = FALSE;
+ try1null = false;
}
if (yperr == YPERR_KEY && try1null)
{
- if (vp != NULL)
- {
- sm_free(vp);
- vp = NULL;
- }
+ SM_FREE_CLR(vp);
keylen++;
yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
&vp, &vsize);
if (yperr == 0)
- try0null = FALSE;
+ try0null = false;
}
if (yperr != 0)
{
@@ -2313,36 +2765,38 @@ nis_getcanonname(name, hbsize, statp)
*statp = EX_UNAVAILABLE;
if (vp != NULL)
sm_free(vp);
- return FALSE;
+ return false;
}
- (void) strlcpy(host_record, vp, sizeof host_record);
+ (void) sm_strlcpy(host_record, vp, sizeof host_record);
sm_free(vp);
if (tTd(38, 44))
- dprintf("got record `%s'\n", host_record);
+ sm_dprintf("got record `%s'\n", host_record);
+ vp = strpbrk(host_record, "#\n");
+ if (vp != NULL)
+ *vp = '\0';
if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf))
{
/* this should not happen, but.... */
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
- if (hbsize <= strlen(cbuf))
+ if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
- (void) strlcpy(name, cbuf, hbsize);
*statp = EX_OK;
- return TRUE;
+ return true;
}
#endif /* NIS */
- /*
+/*
** NISPLUS Modules
**
** This code donated by Sun Microsystems.
*/
-#ifdef NISPLUS
+#if NISPLUS
# undef NIS /* symbol conflict in nis.h */
# undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */
@@ -2368,14 +2822,14 @@ nisplus_map_open(map, mode)
char qbuf[MAXLINE + NIS_MAXNAMELEN];
if (tTd(38, 2))
- dprintf("nisplus_map_open(%s, %s, %d)\n",
+ sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
errno = EPERM;
- return FALSE;
+ return false;
}
if (*map->map_file == '\0')
@@ -2386,19 +2840,19 @@ nisplus_map_open(map, mode)
/* set default NISPLUS Domain to $m */
map->map_domain = newstr(nisplus_default_domain());
if (tTd(38, 2))
- dprintf("nisplus_map_open(%s): using domain %s\n",
+ sm_dprintf("nisplus_map_open(%s): using domain %s\n",
map->map_file, map->map_domain);
}
if (!PARTIAL_NAME(map->map_file))
{
map->map_domain = newstr("");
- snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
+ (void) sm_strlcpy(qbuf, map->map_file, sizeof qbuf);
}
else
{
/* check to see if this map actually exists */
- snprintf(qbuf, sizeof qbuf, "%s.%s",
- map->map_file, map->map_domain);
+ (void) sm_strlcpyn(qbuf, sizeof qbuf, 3,
+ map->map_file, ".", map->map_domain);
}
retry_cnt = 0;
@@ -2416,7 +2870,7 @@ nisplus_map_open(map, mode)
if (retry_cnt++ > 4)
{
errno = EAGAIN;
- return FALSE;
+ return false;
}
/* try not to overwhelm hosed server */
sleep(2);
@@ -2430,7 +2884,7 @@ nisplus_map_open(map, mode)
nis_sperrno(res->status));
# endif /* 0 */
errno = EAGAIN;
- return FALSE;
+ return false;
}
}
@@ -2438,7 +2892,7 @@ nisplus_map_open(map, mode)
(NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
{
if (tTd(38, 10))
- dprintf("nisplus_map_open: %s is not a table\n", qbuf);
+ sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
# if 0
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("421 4.0.0 %s.%s: %s is not a table",
@@ -2446,7 +2900,7 @@ nisplus_map_open(map, mode)
nis_sperrno(res->status));
# endif /* 0 */
errno = EBADF;
- return FALSE;
+ return false;
}
/* default key column is column 0 */
if (map->map_keycolnm == NULL)
@@ -2455,7 +2909,7 @@ nisplus_map_open(map, mode)
max_col = COL_MAX(res);
/* verify the key column exist */
- for (i = 0; i< max_col; i++)
+ for (i = 0; i < max_col; i++)
{
if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
break;
@@ -2463,17 +2917,17 @@ nisplus_map_open(map, mode)
if (i == max_col)
{
if (tTd(38, 2))
- dprintf("nisplus_map_open(%s): can not find key column %s\n",
+ sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
map->map_file, map->map_keycolnm);
errno = ENOENT;
- return FALSE;
+ return false;
}
/* default value column is the last column */
if (map->map_valcolnm == NULL)
{
map->map_valcolno = max_col - 1;
- return TRUE;
+ return true;
}
for (i = 0; i< max_col; i++)
@@ -2481,15 +2935,15 @@ nisplus_map_open(map, mode)
if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
{
map->map_valcolno = i;
- return TRUE;
+ return true;
}
}
if (tTd(38, 2))
- dprintf("nisplus_map_open(%s): can not find column %s\n",
+ sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
map->map_file, map->map_keycolnm);
errno = ENOENT;
- return FALSE;
+ return false;
}
@@ -2513,7 +2967,7 @@ nisplus_map_lookup(map, name, av, statp)
nis_result *result;
if (tTd(38, 20))
- dprintf("nisplus_map_lookup(%s, %s)\n",
+ sm_dprintf("nisplus_map_lookup(%s, %s)\n",
map->map_mname, name);
if (!bitset(MF_OPEN, map->map_mflags))
@@ -2521,7 +2975,7 @@ nisplus_map_lookup(map, name, av, statp)
if (nisplus_map_open(map, O_RDONLY))
{
map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
+ map->map_pid = CurrentPid;
}
else
{
@@ -2569,15 +3023,15 @@ nisplus_map_lookup(map, name, av, statp)
/* construct the query */
if (PARTIAL_NAME(map->map_file))
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
+ (void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
map->map_keycolnm, search_key, map->map_file,
map->map_domain);
else
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
+ (void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
map->map_keycolnm, search_key, map->map_file);
if (tTd(38, 20))
- dprintf("qbuf=%s\n", qbuf);
+ sm_dprintf("qbuf=%s\n", qbuf);
result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
if (result->status == NIS_SUCCESS)
{
@@ -2593,7 +3047,7 @@ nisplus_map_lookup(map, name, av, statp)
/* ignore second entry */
if (tTd(38, 20))
- dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
+ sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
name, count);
}
@@ -2603,7 +3057,7 @@ nisplus_map_lookup(map, name, av, statp)
p = "";
vsize = strlen(p);
if (tTd(38, 20))
- dprintf("nisplus_map_lookup(%s), found %s\n",
+ sm_dprintf("nisplus_map_lookup(%s), found %s\n",
name, p);
if (bitset(MF_MATCHONLY, map->map_mflags))
str = map_rewrite(map, name, strlen(name), NULL);
@@ -2626,7 +3080,7 @@ nisplus_map_lookup(map, name, av, statp)
}
}
if (tTd(38, 20))
- dprintf("nisplus_map_lookup(%s), failed\n", name);
+ sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
nis_freeresult(result);
return NULL;
}
@@ -2650,39 +3104,39 @@ nisplus_getcanonname(name, hbsize, statp)
char nbuf[MAXNAME + 1];
char qbuf[MAXLINE + NIS_MAXNAMELEN];
- if (strlen(name) >= sizeof nbuf)
+ if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
- (void) strlcpy(nbuf, name, sizeof nbuf);
(void) shorten_hostname(nbuf);
p = strchr(nbuf, '.');
if (p == NULL)
{
/* single token */
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
+ (void) sm_snprintf(qbuf, sizeof qbuf,
+ "[name=%s],hosts.org_dir", nbuf);
}
else if (p[1] != '\0')
{
/* multi token -- take only first token in nbuf */
*p = '\0';
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
- nbuf, &p[1]);
+ (void) sm_snprintf(qbuf, sizeof qbuf,
+ "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
}
else
{
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
if (tTd(38, 20))
- dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
- name, qbuf);
+ sm_dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
+ name, qbuf);
result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
- NULL, NULL);
+ NULL, NULL);
if (result->status == NIS_SUCCESS)
{
@@ -2698,20 +3152,20 @@ nisplus_getcanonname(name, hbsize, statp)
/* ignore second entry */
if (tTd(38, 20))
- dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
- name, count);
+ sm_dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
+ name, count);
}
if (tTd(38, 20))
- dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
- name, (NIS_RES_OBJECT(result))->zo_domain);
+ sm_dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
+ name, (NIS_RES_OBJECT(result))->zo_domain);
vp = ((NIS_RES_OBJECT(result))->EN_col(0));
vsize = strlen(vp);
if (tTd(38, 20))
- dprintf("nisplus_getcanonname(%s), found %s\n",
- name, vp);
+ sm_dprintf("nisplus_getcanonname(%s), found %s\n",
+ name, vp);
if (strchr(vp, '.') != NULL)
{
domain = "";
@@ -2725,15 +3179,16 @@ nisplus_getcanonname(name, hbsize, statp)
if (hbsize > vsize + (int) strlen(domain) + 1)
{
if (domain[0] == '\0')
- (void) strlcpy(name, vp, hbsize);
+ (void) sm_strlcpy(name, vp, hbsize);
else
- snprintf(name, hbsize, "%s.%s", vp, domain);
+ (void) sm_snprintf(name, hbsize,
+ "%s.%s", vp, domain);
*statp = EX_OK;
}
else
*statp = EX_NOHOST;
nis_freeresult(result);
- return TRUE;
+ return true;
}
else
{
@@ -2745,10 +3200,10 @@ nisplus_getcanonname(name, hbsize, statp)
*statp = EX_UNAVAILABLE;
}
if (tTd(38, 20))
- dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
- name, result->status, *statp);
+ sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
+ name, result->status, *statp);
nis_freeresult(result);
- return FALSE;
+ return false;
}
char *
@@ -2761,12 +3216,12 @@ nisplus_default_domain()
return default_domain;
p = nis_local_directory();
- snprintf(default_domain, sizeof default_domain, "%s", p);
+ (void) sm_strlcpy(default_domain, p, sizeof default_domain);
return default_domain;
}
#endif /* NISPLUS */
- /*
+/*
** LDAP Modules
*/
@@ -2776,11 +3231,13 @@ nisplus_default_domain()
#if defined(LDAPMAP) || defined(PH_MAP)
-# ifdef PH_MAP
+# if PH_MAP
# define ph_map_dequote ldapmap_dequote
# endif /* PH_MAP */
-char *
+static char *ldapmap_dequote __P((char *));
+
+static char *
ldapmap_dequote(str)
char *str;
{
@@ -2806,9 +3263,9 @@ ldapmap_dequote(str)
}
#endif /* defined(LDAPMAP) || defined(PH_MAP) */
-#ifdef LDAPMAP
+#if LDAPMAP
-LDAPMAP_STRUCT *LDAPDefaults = NULL;
+static SM_LDAP_STRUCT *LDAPDefaults = NULL;
/*
** LDAPMAP_OPEN -- open LDAP map
@@ -2823,11 +3280,11 @@ ldapmap_open(map, mode)
MAP *map;
int mode;
{
- LDAPMAP_STRUCT *lmap;
+ SM_LDAP_STRUCT *lmap;
STAB *s;
if (tTd(38, 2))
- dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
+ sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
mode &= O_ACCMODE;
@@ -2835,127 +3292,48 @@ ldapmap_open(map, mode)
if (mode != O_RDONLY)
{
/* issue a pseudo-error message */
-# ifdef ENOSYS
- errno = ENOSYS;
-# else /* ENOSYS */
-# ifdef EFTYPE
- errno = EFTYPE;
-# else /* EFTYPE */
- errno = ENXIO;
-# endif /* EFTYPE */
-# endif /* ENOSYS */
- return FALSE;
- }
-
- /* Comma separate if used as an alias file */
- if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
- map->map_coldelim = ',';
+ errno = SM_EMAPCANTWRITE;
+ return false;
+ }
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
+ lmap = (SM_LDAP_STRUCT *) map->map_db1;
s = ldapmap_findconn(lmap);
if (s->s_lmap != NULL)
{
/* Already have a connection open to this LDAP server */
- lmap->ldap_ld = ((LDAPMAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
+ lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
+ lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
/* Add this map as head of linked list */
lmap->ldap_next = s->s_lmap;
s->s_lmap = map;
if (tTd(38, 2))
- dprintf("using cached connection\n");
- return TRUE;
+ sm_dprintf("using cached connection\n");
+ return true;
}
if (tTd(38, 2))
- dprintf("opening new connection\n");
+ sm_dprintf("opening new connection\n");
/* No connection yet, connect */
- if (!ldapmap_start(map))
- return FALSE;
-
- /* Save connection for reuse */
- s->s_lmap = map;
- return TRUE;
-}
-
-/*
-** LDAPMAP_START -- actually connect to an LDAP server
-**
-** Parameters:
-** map -- the map being opened.
-**
-** Returns:
-** TRUE if connection is successful, FALSE otherwise.
-**
-** Side Effects:
-** Populates lmap->ldap_ld.
-*/
-
-static jmp_buf LDAPTimeout;
-
-static bool
-ldapmap_start(map)
- MAP *map;
-{
- register int bind_result;
- int save_errno;
- register EVENT *ev = NULL;
- LDAPMAP_STRUCT *lmap;
- LDAP *ld;
-
- if (tTd(38, 2))
- dprintf("ldapmap_start(%s)\n", map->map_mname);
-
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
-
- if (tTd(38,9))
- dprintf("ldapmap_start(%s, %d)\n",
- lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
- lmap->ldap_port);
-
-# if USE_LDAP_INIT
- ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
- save_errno = errno;
-# else /* USE_LDAP_INIT */
- /*
- ** If using ldap_open(), the actual connection to the server
- ** happens now so we need the timeout here. For ldap_init(),
- ** the connection happens at bind time.
- */
-
- /* set the timeout */
- if (lmap->ldap_timeout.tv_sec != 0)
+ if (!sm_ldap_start(map->map_mname, lmap))
{
- if (setjmp(LDAPTimeout) != 0)
+ if (errno == ETIMEDOUT)
{
if (LogLevel > 1)
sm_syslog(LOG_NOTICE, CurEnv->e_id,
"timeout conning to LDAP server %.100s",
lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
- return FALSE;
}
- ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
- }
-
- ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
- save_errno = errno;
- /* clear the event if it has not sprung */
- if (ev != NULL)
- clrevent(ev);
-# endif /* USE_LDAP_INIT */
-
- errno = save_errno;
- if (ld == NULL)
- {
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
if (bitset(MF_NODEFER, map->map_mflags))
syserr("%s failed to %s in map %s",
# if USE_LDAP_INIT
- "ldap_init",
+ "ldap_init/ldap_bind",
# else /* USE_LDAP_INIT */
"ldap_open",
# endif /* USE_LDAP_INIT */
@@ -2965,7 +3343,7 @@ ldapmap_start(map)
else
syserr("421 4.0.0 %s failed to %s in map %s",
# if USE_LDAP_INIT
- "ldap_init",
+ "ldap_init/ldap_bind",
# else /* USE_LDAP_INIT */
"ldap_open",
# endif /* USE_LDAP_INIT */
@@ -2973,86 +3351,12 @@ ldapmap_start(map)
: lmap->ldap_host,
map->map_mname);
}
- return FALSE;
- }
-
- ldapmap_setopts(ld, lmap);
-
-# if USE_LDAP_INIT
- /*
- ** If using ldap_init(), the actual connection to the server
- ** happens at ldap_bind_s() so we need the timeout here.
- */
-
- /* set the timeout */
- if (lmap->ldap_timeout.tv_sec != 0)
- {
- if (setjmp(LDAPTimeout) != 0)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout conning to LDAP server %.100s",
- lmap->ldap_host == NULL ? "localhost"
- : lmap->ldap_host);
- return FALSE;
- }
- ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
- }
-# endif /* USE_LDAP_INIT */
-
-# ifdef LDAP_AUTH_KRBV4
- if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
- lmap->ldap_secret != NULL)
- {
- /*
- ** Need to put ticket in environment here instead of
- ** during parseargs as there may be different tickets
- ** for different LDAP connections.
- */
-
- (void) putenv(lmap->ldap_secret);
- }
-# endif /* LDAP_AUTH_KRBV4 */
-
- bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
- lmap->ldap_secret, lmap->ldap_method);
-
-# if USE_LDAP_INIT
- /* clear the event if it has not sprung */
- if (ev != NULL)
- clrevent(ev);
-# endif /* USE_LDAP_INIT */
-
- if (bind_result != LDAP_SUCCESS)
- {
- errno = bind_result + E_LDAPBASE;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
- map->map_mname,
- lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
- }
- return FALSE;
+ return false;
}
- /* We need to cast ld into the map structure */
- lmap->ldap_ld = ld;
- return TRUE;
-}
-
-/* ARGSUSED */
-static void
-ldaptimeout(sig_no)
- int sig_no;
-{
- /*
- ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
- ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
- ** DOING.
- */
-
- errno = ETIMEDOUT;
- longjmp(LDAPTimeout, 1);
+ /* Save connection for reuse */
+ s->s_lmap = map;
+ return true;
}
/*
@@ -3063,20 +3367,20 @@ void
ldapmap_close(map)
MAP *map;
{
- LDAPMAP_STRUCT *lmap;
+ SM_LDAP_STRUCT *lmap;
STAB *s;
if (tTd(38, 2))
- dprintf("ldapmap_close(%s)\n", map->map_mname);
+ sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
+ lmap = (SM_LDAP_STRUCT *) map->map_db1;
/* Check if already closed */
if (lmap->ldap_ld == NULL)
return;
/* Close the LDAP connection */
- ldap_unbind(lmap->ldap_ld);
+ sm_ldap_close(lmap);
/* Mark all the maps that share the connection as closed */
s = ldapmap_findconn(lmap);
@@ -3086,11 +3390,10 @@ ldapmap_close(map)
MAP *smap = s->s_lmap;
if (tTd(38, 2) && smap != map)
- dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
- map->map_mname, smap->map_mname);
-
+ sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
+ map->map_mname, smap->map_mname);
smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- lmap = (LDAPMAP_STRUCT *) smap->map_db1;
+ lmap = (SM_LDAP_STRUCT *) smap->map_db1;
lmap->ldap_ld = NULL;
s->s_lmap = lmap->ldap_next;
lmap->ldap_next = NULL;
@@ -3099,11 +3402,11 @@ ldapmap_close(map)
# ifdef SUNET_ID
/*
-** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
+** SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
** This only makes sense at Stanford University.
*/
-char *
+static char *
sunet_id_hash(str)
char *str;
{
@@ -3146,22 +3449,21 @@ ldapmap_lookup(map, name, av, statp)
int entries = 0;
int msgid;
int ret;
+ int save_errno;
int vsize;
- char *fp, *vp;
- char *p, *q;
+ char *vp, *p;
char *result = NULL;
- LDAPMAP_STRUCT *lmap = NULL;
+ SM_LDAP_STRUCT *lmap = NULL;
char keybuf[MAXNAME + 1];
- char filter[LDAPMAP_MAX_FILTER + 1];
if (tTd(38, 20))
- dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
+ sm_dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
/* Get ldap struct pointer from map */
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
- ldapmap_setopts(lmap->ldap_ld, lmap);
+ lmap = (SM_LDAP_STRUCT *) map->map_db1;
+ sm_ldap_setopts(lmap->ldap_ld, lmap);
- (void) strlcpy(keybuf, name, sizeof keybuf);
+ (void) sm_strlcpy(keybuf, name, sizeof keybuf);
if (!bitset(MF_NOFOLDCASE, map->map_mflags))
{
@@ -3172,91 +3474,32 @@ ldapmap_lookup(map, name, av, statp)
# endif /* SUNET_ID */
}
- /* substitute keybuf into filter, perhaps multiple times */
- memset(filter, '\0', sizeof filter);
- fp = filter;
- p = lmap->ldap_filter;
- while ((q = strchr(p, '%')) != NULL)
- {
- if (q[1] == 's')
- {
- snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
- (int) (q - p), p, keybuf);
- fp += strlen(fp);
- p = q + 2;
- }
- else if (q[1] == '0')
- {
- char *k = keybuf;
-
- snprintf(fp, SPACELEFT(filter, fp), "%.*s",
- (int) (q - p), p);
- fp += strlen(fp);
- p = q + 2;
-
- /* Properly escape LDAP special characters */
- while (SPACELEFT(filter, fp) > 0 &&
- *k != '\0')
- {
- if (*k == '*' || *k == '(' ||
- *k == ')' || *k == '\\')
- {
- (void) strlcat(fp,
- (*k == '*' ? "\\2A" :
- (*k == '(' ? "\\28" :
- (*k == ')' ? "\\29" :
- (*k == '\\' ? "\\5C" :
- "\00")))),
- SPACELEFT(filter, fp));
- fp += strlen(fp);
- k++;
- }
- else
- *fp++ = *k++;
- }
- }
- else
- {
- snprintf(fp, SPACELEFT(filter, fp), "%.*s",
- (int) (q - p + 1), p);
- p = q + (q[1] == '%' ? 2 : 1);
- fp += strlen(fp);
- }
- }
- snprintf(fp, SPACELEFT(filter, fp), "%s", p);
- if (tTd(38, 20))
- dprintf("ldap search filter=%s\n", filter);
-
- lmap->ldap_res = NULL;
- msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
- filter,
- (lmap->ldap_attr[0] == NULL ? NULL :
- lmap->ldap_attr),
- lmap->ldap_attrsonly);
+ msgid = sm_ldap_search(lmap, keybuf);
if (msgid == -1)
{
- int save_errno;
-
- errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
+ errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
save_errno = errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
if (bitset(MF_NODEFER, map->map_mflags))
syserr("Error in ldap_search using %s in map %s",
- filter, map->map_mname);
+ keybuf, map->map_mname);
else
syserr("421 4.0.0 Error in ldap_search using %s in map %s",
- filter, map->map_mname);
+ keybuf, map->map_mname);
}
*statp = EX_TEMPFAIL;
-#ifdef LDAP_SERVER_DOWN
- errno = save_errno;
- if (errno == LDAP_SERVER_DOWN + E_LDAPBASE)
+ switch (save_errno - E_LDAPBASE)
{
+#ifdef LDAP_SERVER_DOWN
+ case LDAP_SERVER_DOWN:
+#endif /* LDAP_SERVER_DOWN */
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
/* server disappeared, try reopen on next search */
ldapmap_close(map);
+ break;
}
-#endif /* LDAP_SERVER_DOWN */
errno = save_errno;
return NULL;
}
@@ -3264,9 +3507,58 @@ ldapmap_lookup(map, name, av, statp)
*statp = EX_NOTFOUND;
vp = NULL;
- /* Get results (all if MF_NOREWRITE, otherwise one by one) */
- while ((ret = ldap_result(lmap->ldap_ld, msgid,
- bitset(MF_NOREWRITE, map->map_mflags),
+# if _FFR_LDAP_RECURSION
+ {
+ int flags;
+ SM_RPOOL_T *rpool;
+
+ flags = 0;
+ if (bitset(MF_SINGLEMATCH, map->map_mflags))
+ flags |= SM_LDAP_SINGLEMATCH;
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ flags |= SM_LDAP_MATCHONLY;
+
+ /* Create an rpool for search related memory usage */
+ rpool = sm_rpool_new_x(NULL);
+
+ p = NULL;
+ *statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
+ rpool, &p, NULL);
+ save_errno = errno;
+
+ /* Copy result so rpool can be freed */
+ if (*statp == EX_OK && p != NULL)
+ vp = newstr(p);
+ sm_rpool_free(rpool);
+
+ /* need to restart LDAP connection? */
+ if (*statp == EX_RESTART)
+ {
+ *statp = EX_TEMPFAIL;
+ ldapmap_close(map);
+ }
+
+ errno = save_errno;
+ if (*statp != EX_OK && *statp != EX_NOTFOUND)
+ {
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ {
+ if (bitset(MF_NODEFER, map->map_mflags))
+ syserr("Error getting LDAP results in map %s",
+ map->map_mname);
+ else
+ syserr("421 4.0.0 Error getting LDAP results in map %s",
+ map->map_mname);
+ }
+ errno = save_errno;
+ return NULL;
+ }
+ goto finishlookup;
+ }
+# endif /* _FFR_LDAP_RECURSION */
+
+ /* Get results */
+ while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
(lmap->ldap_timeout.tv_sec == 0 ? NULL :
&(lmap->ldap_timeout)),
&(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
@@ -3287,9 +3579,9 @@ ldapmap_lookup(map, name, av, statp)
}
(void) ldap_abandon(lmap->ldap_ld, msgid);
if (vp != NULL)
- sm_free(vp);
+ sm_free(vp); /* XXX */
if (tTd(38, 25))
- dprintf("ldap search found multiple on a single match query\n");
+ sm_dprintf("ldap search found multiple on a single match query\n");
return NULL;
}
}
@@ -3341,15 +3633,21 @@ ldapmap_lookup(map, name, av, statp)
attr);
if (vals == NULL)
{
- errno = ldapmap_geterrno(lmap->ldap_ld);
- if (errno == LDAP_SUCCESS)
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno == LDAP_SUCCESS)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
continue;
+ }
/* Must be an error */
- errno += E_LDAPBASE;
+ save_errno += E_LDAPBASE;
if (!bitset(MF_OPTIONAL,
map->map_mflags))
{
+ errno = save_errno;
if (bitset(MF_NODEFER,
map->map_mflags))
syserr("Error getting LDAP values in map %s",
@@ -3370,7 +3668,8 @@ ldapmap_lookup(map, name, av, statp)
(void) ldap_abandon(lmap->ldap_ld,
msgid);
if (vp != NULL)
- sm_free(vp);
+ sm_free(vp); /* XXX */
+ errno = save_errno;
return NULL;
}
}
@@ -3393,7 +3692,15 @@ ldapmap_lookup(map, name, av, statp)
*/
if (bitset(MF_MATCHONLY, map->map_mflags))
+ {
+ if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
+ ldap_value_free(vals);
+
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
continue;
+ }
/*
** If we don't want multiple values,
@@ -3420,7 +3727,18 @@ ldapmap_lookup(map, name, av, statp)
continue;
}
- vp = newstr(vals[0]);
+ vsize = strlen(vals[0]) + 1;
+ if (lmap->ldap_attrsep != '\0')
+ vsize += strlen(attr) + 1;
+ vp = xalloc(vsize);
+ if (lmap->ldap_attrsep != '\0')
+ sm_snprintf(vp, vsize,
+ "%s%c%s",
+ attr,
+ lmap->ldap_attrsep,
+ vals[0]);
+ else
+ sm_strlcpy(vp, vals[0], vsize);
ldap_value_free(vals);
# if USING_NETSCAPE_LDAP
ldap_memfree(attr);
@@ -3438,10 +3756,11 @@ ldapmap_lookup(map, name, av, statp)
vsize = strlen(vp) +
strlen(attr) + 2;
tmp = xalloc(vsize);
- snprintf(tmp, vsize, "%s%c%s",
- vp, map->map_coldelim,
- attr);
- sm_free(vp);
+ (void) sm_snprintf(tmp,
+ vsize, "%s%c%s",
+ vp, map->map_coldelim,
+ attr);
+ sm_free(vp); /* XXX */
vp = tmp;
}
# if USING_NETSCAPE_LDAP
@@ -3458,15 +3777,25 @@ ldapmap_lookup(map, name, av, statp)
vsize = 0;
for (i = 0; vals[i] != NULL; i++)
+ {
vsize += strlen(vals[i]) + 1;
+ if (lmap->ldap_attrsep != '\0')
+ vsize += strlen(attr) + 1;
+ }
vp_tmp = xalloc(vsize);
*vp_tmp = '\0';
p = vp_tmp;
for (i = 0; vals[i] != NULL; i++)
{
- p += strlcpy(p, vals[i],
- vsize - (p - vp_tmp));
+ if (lmap->ldap_attrsep != '\0')
+ {
+ p += sm_strlcpy(p, attr,
+ vsize - (p - vp_tmp));
+ *p++ = lmap->ldap_attrsep;
+ }
+ p += sm_strlcpy(p, vals[i],
+ vsize - (p - vp_tmp));
if (p >= vp_tmp + vsize)
syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
if (vals[i + 1] != NULL)
@@ -3484,14 +3813,14 @@ ldapmap_lookup(map, name, av, statp)
}
vsize = strlen(vp) + strlen(vp_tmp) + 2;
tmp = xalloc(vsize);
- snprintf(tmp, vsize, "%s%c%s",
+ (void) sm_snprintf(tmp, vsize, "%s%c%s",
vp, map->map_coldelim, vp_tmp);
- sm_free(vp);
- sm_free(vp_tmp);
+ sm_free(vp); /* XXX */
+ sm_free(vp_tmp); /* XXX */
vp = tmp;
}
- errno = ldapmap_geterrno(lmap->ldap_ld);
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
/*
** We check errno != LDAP_DECODING_ERROR since
@@ -3502,13 +3831,14 @@ ldapmap_lookup(map, name, av, statp)
** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
*/
- if (errno != LDAP_SUCCESS &&
- errno != LDAP_DECODING_ERROR)
+ if (save_errno != LDAP_SUCCESS &&
+ save_errno != LDAP_DECODING_ERROR)
{
/* Must be an error */
- errno += E_LDAPBASE;
+ save_errno += E_LDAPBASE;
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
+ errno = save_errno;
if (bitset(MF_NODEFER, map->map_mflags))
syserr("Error getting LDAP attributes in map %s",
map->map_mname);
@@ -3524,7 +3854,8 @@ ldapmap_lookup(map, name, av, statp)
}
(void) ldap_abandon(lmap->ldap_ld, msgid);
if (vp != NULL)
- sm_free(vp);
+ sm_free(vp); /* XXX */
+ errno = save_errno;
return NULL;
}
@@ -3532,13 +3863,15 @@ ldapmap_lookup(map, name, av, statp)
if (map->map_coldelim == '\0' && vp != NULL)
break;
}
- errno = ldapmap_geterrno(lmap->ldap_ld);
- if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno != LDAP_SUCCESS &&
+ save_errno != LDAP_DECODING_ERROR)
{
/* Must be an error */
- errno += E_LDAPBASE;
+ save_errno += E_LDAPBASE;
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
+ errno = save_errno;
if (bitset(MF_NODEFER, map->map_mflags))
syserr("Error getting LDAP entries in map %s",
map->map_mname);
@@ -3554,52 +3887,26 @@ ldapmap_lookup(map, name, av, statp)
}
(void) ldap_abandon(lmap->ldap_ld, msgid);
if (vp != NULL)
- sm_free(vp);
+ sm_free(vp); /* XXX */
+ errno = save_errno;
return NULL;
}
ldap_msgfree(lmap->ldap_res);
lmap->ldap_res = NULL;
}
- /*
- ** If grabbing all results at once for MF_NOREWRITE and
- ** only want a single match, make sure that's all we have
- */
-
- if (ret == LDAP_RES_SEARCH_RESULT &&
- bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
- {
- entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
- if (entries > 1)
- {
- *statp = EX_NOTFOUND;
- if (lmap->ldap_res != NULL)
- {
- ldap_msgfree(lmap->ldap_res);
- lmap->ldap_res = NULL;
- }
- if (vp != NULL)
- sm_free(vp);
- return NULL;
- }
- *statp = EX_OK;
- }
-
if (ret == 0)
- errno = ETIMEDOUT;
+ save_errno = ETIMEDOUT;
else
- errno = ldapmap_geterrno(lmap->ldap_ld);
- if (errno != LDAP_SUCCESS)
+ save_errno = sm_ldap_geterrno(lmap->ldap_ld);
+ if (save_errno != LDAP_SUCCESS)
{
- int save_errno;
-
- /* Must be an error */
if (ret != 0)
- errno += E_LDAPBASE;
- save_errno = errno;
+ save_errno += E_LDAPBASE;
if (!bitset(MF_OPTIONAL, map->map_mflags))
{
+ errno = save_errno;
if (bitset(MF_NODEFER, map->map_mflags))
syserr("Error getting LDAP results in map %s",
map->map_mname);
@@ -3609,37 +3916,31 @@ ldapmap_lookup(map, name, av, statp)
}
*statp = EX_TEMPFAIL;
if (vp != NULL)
- sm_free(vp);
-#ifdef LDAP_SERVER_DOWN
- errno = save_errno;
- if (errno == LDAP_SERVER_DOWN + E_LDAPBASE)
+ sm_free(vp); /* XXX */
+
+ switch (save_errno - E_LDAPBASE)
{
+#ifdef LDAP_SERVER_DOWN
+ case LDAP_SERVER_DOWN:
+#endif /* LDAP_SERVER_DOWN */
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
/* server disappeared, try reopen on next search */
ldapmap_close(map);
+ break;
}
-#endif /* LDAP_SERVER_DOWN */
errno = save_errno;
return NULL;
}
+# if _FFR_LDAP_RECURSION
+finishlookup:
+# endif /* _FFR_LDAP_RECURSION */
+
/* Did we match anything? */
if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
return NULL;
- /*
- ** If MF_NOREWRITE, we are special map which doesn't
- ** actually return a map value. Instead, we don't free
- ** ldap_res and let the calling function process the LDAP
- ** results. The caller should ldap_msgfree(lmap->ldap_res).
- */
-
- if (bitset(MF_NOREWRITE, map->map_mflags))
- {
- if (vp != NULL)
- sm_free(vp);
- return "";
- }
-
if (*statp == EX_OK)
{
if (LogLevel > 9)
@@ -3654,7 +3955,7 @@ ldapmap_lookup(map, name, av, statp)
result = map_rewrite(map, vp, strlen(vp), av);
}
if (vp != NULL)
- sm_free(vp);
+ sm_free(vp); /* XXX */
}
return result;
}
@@ -3673,126 +3974,39 @@ ldapmap_lookup(map, name, av, statp)
**
** Returns:
** Symbol table entry for the LDAP connection.
-**
*/
static STAB *
ldapmap_findconn(lmap)
- LDAPMAP_STRUCT *lmap;
+ SM_LDAP_STRUCT *lmap;
{
- int len;
char *nbuf;
- STAB *s;
-
- len = (lmap->ldap_host == NULL ? strlen("localhost") :
- strlen(lmap->ldap_host)) + 1 + 8 + 1 +
- (lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
- 1 +
- (lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
- 8 + 1;
- nbuf = xalloc(len);
- snprintf(nbuf, len, "%s%c%d%c%s%c%s%d",
- (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
- CONDELSE,
- lmap->ldap_port,
- CONDELSE,
- (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
- CONDELSE,
- (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret),
- (int) getpid());
- s = stab(nbuf, ST_LMAP, ST_ENTER);
- sm_free(nbuf);
+ STAB *SM_NONVOLATILE s = NULL;
+
+ nbuf = sm_stringf_x("%s%c%d%c%s%c%s%d",
+ (lmap->ldap_host == NULL ? "localhost"
+ : lmap->ldap_host),
+ CONDELSE,
+ lmap->ldap_port,
+ CONDELSE,
+ (lmap->ldap_binddn == NULL ? ""
+ : lmap->ldap_binddn),
+ CONDELSE,
+ (lmap->ldap_secret == NULL ? ""
+ : lmap->ldap_secret),
+ (int) CurrentPid);
+ SM_TRY
+ s = stab(nbuf, ST_LMAP, ST_ENTER);
+ SM_FINALLY
+ sm_free(nbuf);
+ SM_END_TRY
return s;
}
- /*
-** LDAPMAP_SETOPTS -- set LDAP options
-**
-** Parameters:
-** ld -- LDAP session handle
-** lmap -- LDAP map information
-**
-** Returns:
-** None.
-**
-*/
-
-static void
-ldapmap_setopts(ld, lmap)
- LDAP *ld;
- LDAPMAP_STRUCT *lmap;
-{
-# if USE_LDAP_SET_OPTION
- ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
- if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
- ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
- else
- ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
- ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
- ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
-# else /* USE_LDAP_SET_OPTION */
- /* From here on in we can use ldap internal timelimits */
- ld->ld_deref = lmap->ldap_deref;
- ld->ld_options = lmap->ldap_options;
- ld->ld_sizelimit = lmap->ldap_sizelimit;
- ld->ld_timelimit = lmap->ldap_timelimit;
-# endif /* USE_LDAP_SET_OPTION */
-}
- /*
-** LDAPMAP_GETERRNO -- get ldap errno value
-**
-** Parameters:
-** ld -- LDAP session handle
-**
-** Returns:
-** LDAP errno.
-**
-*/
-
-static int
-ldapmap_geterrno(ld)
- LDAP *ld;
-{
- int err = LDAP_SUCCESS;
-
-# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
- (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
-# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
-# ifdef LDAP_OPT_SIZELIMIT
- err = ldap_get_lderrno(ld, NULL, NULL);
-# else /* LDAP_OPT_SIZELIMIT */
- err = ld->ld_errno;
-
- /*
- ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
- ** OpenLDAP 1.X's hack (see above)
- */
-
- ld->ld_errno = LDAP_SUCCESS;
-# endif /* LDAP_OPT_SIZELIMIT */
-# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
- return err;
-}
-
-/*
-** LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
-*/
-
-bool
-ldapx_map_parseargs(map, args)
- MAP *map;
- char *args;
-{
- printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
- printf(" version. Use the \"ldap\" map class instead for map \"%s\".\n",
- map->map_mname);
- return ldapmap_parseargs(map, args);
-}
-
/*
** LDAPMAP_PARSEARGS -- parse ldap map definition args.
*/
-struct lamvalues LDAPAuthMethods[] =
+static struct lamvalues LDAPAuthMethods[] =
{
{ "none", LDAP_AUTH_NONE },
{ "simple", LDAP_AUTH_SIMPLE },
@@ -3802,7 +4016,7 @@ struct lamvalues LDAPAuthMethods[] =
{ NULL, 0 }
};
-struct ladvalues LDAPAliasDereference[] =
+static struct ladvalues LDAPAliasDereference[] =
{
{ "never", LDAP_DEREF_NEVER },
{ "always", LDAP_DEREF_ALWAYS },
@@ -3811,7 +4025,7 @@ struct ladvalues LDAPAliasDereference[] =
{ NULL, 0 }
};
-struct lssvalues LDAPSearchScope[] =
+static struct lssvalues LDAPSearchScope[] =
{
{ "base", LDAP_SCOPE_BASE },
{ "one", LDAP_SCOPE_ONELEVEL },
@@ -3824,25 +4038,26 @@ ldapmap_parseargs(map, args)
MAP *map;
char *args;
{
- bool secretread = TRUE;
+ bool secretread = true;
int i;
register char *p = args;
- LDAPMAP_STRUCT *lmap;
+ SM_LDAP_STRUCT *lmap;
struct lamvalues *lam;
struct ladvalues *lad;
struct lssvalues *lss;
+ char ldapfilt[MAXLINE];
char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
/* Get ldap struct pointer from map */
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
+ lmap = (SM_LDAP_STRUCT *) map->map_db1;
/* Check if setting the initial LDAP defaults */
if (lmap == NULL || lmap != LDAPDefaults)
{
- /* We need to alloc an LDAPMAP_STRUCT struct */
- lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
+ /* We need to alloc an SM_LDAP_STRUCT struct */
+ lmap = (SM_LDAP_STRUCT *) xalloc(sizeof *lmap);
if (LDAPDefaults == NULL)
- ldapmap_clear(lmap);
+ sm_ldap_clear(lmap);
else
STRUCTCOPY(*LDAPDefaults, *lmap);
}
@@ -3850,6 +4065,58 @@ ldapmap_parseargs(map, args)
/* there is no check whether there is really an argument */
map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
map->map_spacesub = SpaceSub; /* default value */
+
+ /* Check if setting up an alias or file class LDAP map */
+ if (bitset(MF_ALIAS, map->map_mflags))
+ {
+ /* Comma separate if used as an alias file */
+ map->map_coldelim = ',';
+ if (*args == '\0')
+ {
+ int n;
+ char *lc;
+ char jbuf[MAXHOSTNAMELEN];
+ char lcbuf[MAXLINE];
+
+ /* Get $j */
+ expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
+ if (jbuf[0] == '\0')
+ {
+ (void) sm_strlcpy(jbuf, "localhost",
+ sizeof jbuf);
+ }
+
+ lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
+ if (lc == NULL)
+ lc = "";
+ else
+ {
+ expand(lc, lcbuf, sizeof lcbuf, CurEnv);
+ lc = lcbuf;
+ }
+
+ n = sm_snprintf(ldapfilt, sizeof ldapfilt,
+ "(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
+ lc, jbuf);
+ if (n >= sizeof ldapfilt)
+ {
+ syserr("%s: Default LDAP string too long",
+ map->map_mname);
+ return false;
+ }
+
+ /* default args for an alias LDAP entry */
+ lmap->ldap_filter = ldapfilt;
+ lmap->ldap_attr[0] = "sendmailMTAAliasValue";
+ lmap->ldap_attr[1] = NULL;
+ }
+ }
+ else if (bitset(MF_FILECLASS, map->map_mflags))
+ {
+ /* Space separate if used as a file class file */
+ map->map_coldelim = ' ';
+ }
+
for (;;)
{
while (isascii(*p) && isspace(*p))
@@ -3929,6 +4196,27 @@ ldapmap_parseargs(map, args)
break;
/* Start of ldapmap specific args */
+ case 'V':
+ if (*++p != '\\')
+ lmap->ldap_attrsep = *p;
+ else
+ {
+ switch (*++p)
+ {
+ case 'n':
+ lmap->ldap_attrsep = '\n';
+ break;
+
+ case 't':
+ lmap->ldap_attrsep = '\t';
+ break;
+
+ default:
+ lmap->ldap_attrsep = '\\';
+ }
+ }
+ break;
+
case 'k': /* search field */
while (isascii(*++p) && isspace(*p))
continue;
@@ -3951,7 +4239,7 @@ ldapmap_parseargs(map, args)
# ifdef LDAP_REFERRALS
lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
# else /* LDAP_REFERRALS */
- syserr("compile with -DLDAP_REFERRALS for referral support\n");
+ syserr("compile with -DLDAP_REFERRALS for referral support");
# endif /* LDAP_REFERRALS */
break;
@@ -3963,14 +4251,14 @@ ldapmap_parseargs(map, args)
while (isascii(*++p) && isspace(*p))
continue;
- if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
+ if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
p += 11;
for (lad = LDAPAliasDereference;
lad != NULL && lad->lad_name != NULL; lad++)
{
- if (strncasecmp(p, lad->lad_name,
- strlen(lad->lad_name)) == 0)
+ if (sm_strncasecmp(p, lad->lad_name,
+ strlen(lad->lad_name)) == 0)
break;
}
if (lad->lad_name != NULL)
@@ -3989,7 +4277,7 @@ ldapmap_parseargs(map, args)
p, map->map_mname);
if (ptr != NULL)
*ptr = ' ';
- return FALSE;
+ return false;
}
}
break;
@@ -3998,14 +4286,14 @@ ldapmap_parseargs(map, args)
while (isascii(*++p) && isspace(*p))
continue;
- if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
+ if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
p += 11;
for (lss = LDAPSearchScope;
lss != NULL && lss->lss_name != NULL; lss++)
{
- if (strncasecmp(p, lss->lss_name,
- strlen(lss->lss_name)) == 0)
+ if (sm_strncasecmp(p, lss->lss_name,
+ strlen(lss->lss_name)) == 0)
break;
}
if (lss->lss_name != NULL)
@@ -4024,7 +4312,7 @@ ldapmap_parseargs(map, args)
p, map->map_mname);
if (ptr != NULL)
*ptr = ' ';
- return FALSE;
+ return false;
}
}
break;
@@ -4070,14 +4358,14 @@ ldapmap_parseargs(map, args)
while (isascii(*++p) && isspace(*p))
continue;
- if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
+ if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
p += 10;
for (lam = LDAPAuthMethods;
lam != NULL && lam->lam_name != NULL; lam++)
{
- if (strncasecmp(p, lam->lam_name,
- strlen(lam->lam_name)) == 0)
+ if (sm_strncasecmp(p, lam->lam_name,
+ strlen(lam->lam_name)) == 0)
break;
}
if (lam->lam_name != NULL)
@@ -4096,7 +4384,7 @@ ldapmap_parseargs(map, args)
p, map->map_mname);
if (ptr != NULL)
*ptr = ' ';
- return FALSE;
+ return false;
}
}
@@ -4111,7 +4399,7 @@ ldapmap_parseargs(map, args)
while (isascii(*++p) && isspace(*p))
continue;
lmap->ldap_secret = p;
- secretread = FALSE;
+ secretread = false;
break;
default:
@@ -4165,7 +4453,7 @@ ldapmap_parseargs(map, args)
LDAPDefaults == lmap ||
LDAPDefaults->ldap_secret != lmap->ldap_secret))
{
- FILE *sfd;
+ SM_FILE_T *sfd;
long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
if (DontLockReadFiles)
@@ -4195,12 +4483,12 @@ ldapmap_parseargs(map, args)
{
syserr("LDAP map: cannot open secret %s",
ldapmap_dequote(lmap->ldap_secret));
- return FALSE;
+ return false;
}
lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
sfd, TimeOuts.to_fileopen,
"ldapmap_parseargs");
- (void) fclose(sfd);
+ (void) sm_io_close(sfd, SM_TIME_DEFAULT);
if (lmap->ldap_secret != NULL &&
strlen(m_tmp) > 0)
{
@@ -4220,16 +4508,18 @@ ldapmap_parseargs(map, args)
** stashed
*/
- snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
- "KRBTKFILE=%s",
- ldapmap_dequote(lmap->ldap_secret));
+ (void) sm_snprintf(m_tmp,
+ MAXPATHLEN + LDAPMAP_MAX_PASSWD,
+ "KRBTKFILE=%s",
+ ldapmap_dequote(lmap->ldap_secret));
lmap->ldap_secret = m_tmp;
break;
# endif /* LDAP_AUTH_KRBV4 */
default: /* Should NEVER get here */
syserr("LDAP map: Illegal value in lmap method");
- return FALSE;
+ return false;
+ /* NOTREACHED */
break;
}
}
@@ -4259,7 +4549,7 @@ ldapmap_parseargs(map, args)
/* If setting defaults, don't process ldap_filter and ldap_attr */
if (lmap == LDAPDefaults)
- return TRUE;
+ return true;
if (lmap->ldap_filter != NULL)
lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
@@ -4268,12 +4558,17 @@ ldapmap_parseargs(map, args)
if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
{
syserr("No filter given in map %s", map->map_mname);
- return FALSE;
+ return false;
}
}
if (lmap->ldap_attr[0] != NULL)
{
+#if _FFR_LDAP_RECURSION
+ bool recurse = false;
+ int final = 0;
+#endif /* _FFR_LDAP_RECURSION */
+
i = 0;
p = ldapmap_dequote(lmap->ldap_attr[0]);
lmap->ldap_attr[0] = NULL;
@@ -4295,58 +4590,88 @@ ldapmap_parseargs(map, args)
{
syserr("Too many return attributes in %s (max %d)",
map->map_mname, LDAPMAP_MAX_ATTR);
- return FALSE;
+ return false;
}
if (*v != '\0')
- lmap->ldap_attr[i++] = newstr(v);
+ {
+#if _FFR_LDAP_RECURSION
+ char *type;
+
+ type = strchr(v, ':');
+ if (type != NULL)
+ *type++ = '\0';
+#endif /* _FFR_LDAP_RECURSION */
+
+ lmap->ldap_attr[i] = newstr(v);
+
+#if _FFR_LDAP_RECURSION
+ if (type != NULL)
+ {
+ if (sm_strcasecmp(type, "normal") == 0)
+ {
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_NORMAL;
+ }
+ else if (sm_strcasecmp(type, "dn") == 0)
+ {
+ recurse = true;
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_DN;
+ }
+ else if (sm_strcasecmp(type, "filter") == 0)
+ {
+ recurse = true;
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_FILTER;
+ }
+ else if (sm_strcasecmp(type, "url") == 0)
+ {
+ recurse = true;
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_URL;
+ }
+ else if (sm_strcasecmp(type, "final") == 0)
+ {
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_FINAL;
+ if (final >= LDAPMAP_MAX_ATTR)
+ {
+ syserr("Too many FINAL attributes in %s (max %d)",
+ map->map_mname, LDAPMAP_MAX_ATTR);
+ return false;
+ }
+ lmap->ldap_attr_final[final++] = lmap->ldap_attr[i];
+ }
+ else
+ {
+ syserr("Unknown attribute type (%s) in %s",
+ type, map->map_mname);
+ return false;
+ }
+ }
+ else
+ lmap->ldap_attr_type[i] = LDAPMAP_ATTR_NORMAL;
+#endif /* _FFR_LDAP_RECURSION */
+ i++;
+ }
}
lmap->ldap_attr[i] = NULL;
+#if _FFR_LDAP_RECURSION
+ lmap->ldap_attr_final[final] = NULL;
+ if (recurse && lmap->ldap_attr_final[0] == NULL)
+ {
+ syserr("LDAP recursion requested in %s but no FINAL attribute given",
+ map->map_mname);
+ return false;
+ }
+ if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
+ {
+ syserr("LDAP recursion requested in %s can not be used with -n",
+ map->map_mname);
+ return false;
+ }
+#endif /* _FFR_LDAP_RECURSION */
}
-
map->map_db1 = (ARBPTR_T) lmap;
- return TRUE;
+ return true;
}
/*
-** LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
-**
-** Parameters:
-** lmap -- pointer to LDAPMAP_STRUCT to clear
-**
-** Returns:
-** None.
-**
-*/
-
-static void
-ldapmap_clear(lmap)
- LDAPMAP_STRUCT *lmap;
-{
- lmap->ldap_host = NULL;
- lmap->ldap_port = LDAP_PORT;
- lmap->ldap_deref = LDAP_DEREF_NEVER;
- lmap->ldap_timelimit = LDAP_NO_LIMIT;
- lmap->ldap_sizelimit = LDAP_NO_LIMIT;
-# ifdef LDAP_REFERRALS
- lmap->ldap_options = LDAP_OPT_REFERRALS;
-# else /* LDAP_REFERRALS */
- lmap->ldap_options = 0;
-# endif /* LDAP_REFERRALS */
- lmap->ldap_binddn = NULL;
- lmap->ldap_secret = NULL;
- lmap->ldap_method = LDAP_AUTH_SIMPLE;
- lmap->ldap_base = NULL;
- lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
- lmap->ldap_attrsonly = LDAPMAP_FALSE;
- lmap->ldap_timeout.tv_sec = 0;
- lmap->ldap_timeout.tv_usec = 0;
- lmap->ldap_ld = NULL;
- lmap->ldap_filter = NULL;
- lmap->ldap_attr[0] = NULL;
- lmap->ldap_res = NULL;
- lmap->ldap_next = NULL;
-}
- /*
** LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
**
** Parameters:
@@ -4354,7 +4679,6 @@ ldapmap_clear(lmap)
**
** Returns:
** None.
-**
*/
void
@@ -4366,8 +4690,8 @@ ldapmap_set_defaults(spec)
/* Allocate and set the default values */
if (LDAPDefaults == NULL)
- LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
- ldapmap_clear(LDAPDefaults);
+ LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
+ sm_ldap_clear(LDAPDefaults);
memset(&map, '\0', sizeof map);
@@ -4391,16 +4715,8 @@ ldapmap_set_defaults(spec)
map.map_tapp != NULL)
{
syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
- if (map.map_app != NULL)
- {
- sm_free(map.map_app);
- map.map_app = NULL;
- }
- if (map.map_tapp != NULL)
- {
- sm_free(map.map_tapp);
- map.map_tapp = NULL;
- }
+ SM_FREE_CLR(map.map_app);
+ SM_FREE_CLR(map.map_tapp);
}
if (LDAPDefaults->ldap_filter != NULL)
@@ -4418,11 +4734,11 @@ ldapmap_set_defaults(spec)
}
}
#endif /* LDAPMAP */
- /*
+/*
** PH map
*/
-#ifdef PH_MAP
+#if PH_MAP
/*
** Support for the CCSO Nameserver (ph/qi).
@@ -4430,8 +4746,11 @@ ldapmap_set_defaults(spec)
** Contributed by Mark D. Roth <roth@uiuc.edu>. Contact him for support.
*/
-# include <qiapi.h>
-# include <qicode.h>
+/* what version of the ph map code we're running */
+static char phmap_id[PH_BUF_SIZE];
+
+/* sendmail version for phmap id string */
+extern const char Version[];
/*
** PH_MAP_PARSEARGS -- parse ph map definition args.
@@ -4442,20 +4761,23 @@ ph_map_parseargs(map, args)
MAP *map;
char *args;
{
- int i;
- register int done;
- PH_MAP_STRUCT *pmap = NULL;
+ register bool done;
register char *p = args;
+ PH_MAP_STRUCT *pmap = NULL;
+
+ /* initialize version string */
+ (void) sm_snprintf(phmap_id, sizeof phmap_id,
+ "sendmail-%s phmap-20010529 libphclient-%s",
+ Version, libphclient_version);
pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
/* defaults */
pmap->ph_servers = NULL;
pmap->ph_field_list = NULL;
- pmap->ph_to_server = NULL;
- pmap->ph_from_server = NULL;
- pmap->ph_sockfd = -1;
+ pmap->ph = NULL;
pmap->ph_timeout = 0;
+ pmap->ph_fastclose = 0;
map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
for (;;)
@@ -4507,13 +4829,11 @@ ph_map_parseargs(map, args)
map->map_tapp = ++p;
break;
-#if _FFR_PHMAP_TIMEOUT
case 'l':
while (isascii(*++p) && isspace(*p))
continue;
pmap->ph_timeout = atoi(p);
break;
-#endif /* _FFR_PHMAP_TIMEOUT */
case 'S':
map->map_spacesub = *++p;
@@ -4529,14 +4849,20 @@ ph_map_parseargs(map, args)
pmap->ph_servers = p;
break;
- case 'v': /* fields to search for */
+ case 'v':
+ sm_syslog(LOG_WARNING, NULL,
+ "ph_map_parseargs: WARNING: -v option will be removed in a future release - please use -k instead");
+ /* intentional fallthrough for backward compatibility */
+ /* FALLTHROUGH */
+
+ case 'k': /* fields to search for */
while (isascii(*++p) && isspace(*p))
continue;
pmap->ph_field_list = p;
break;
default:
- syserr("ph_map_parseargs: unknown option -%c\n", *p);
+ syserr("ph_map_parseargs: unknown option -%c", *p);
}
/* try to account for quoted strings */
@@ -4566,72 +4892,51 @@ ph_map_parseargs(map, args)
if (pmap->ph_field_list != NULL)
pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
- else
- pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
if (pmap->ph_servers != NULL)
pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
else
{
syserr("ph_map_parseargs: -h flag is required");
- return FALSE;
+ return false;
}
map->map_db1 = (ARBPTR_T) pmap;
- return TRUE;
+ return true;
}
-#if _FFR_PHMAP_TIMEOUT
/*
** PH_MAP_CLOSE -- close the connection to the ph server
*/
-static void
-ph_map_safeclose(map)
+void
+ph_map_close(map)
MAP *map;
{
- int save_errno = errno;
PH_MAP_STRUCT *pmap;
pmap = (PH_MAP_STRUCT *)map->map_db1;
+ if (tTd(38, 9))
+ sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d",
+ map->map_mname, pmap->ph_fastclose);
- if (pmap->ph_sockfd != -1)
- {
- (void) close(pmap->ph_sockfd);
- pmap->ph_sockfd = -1;
- }
- if (pmap->ph_from_server != NULL)
- {
- (void) fclose(pmap->ph_from_server);
- pmap->ph_from_server = NULL;
- }
- if (pmap->ph_to_server != NULL)
+
+ if (pmap->ph != NULL)
{
- (void) fclose(pmap->ph_to_server);
- pmap->ph_to_server = NULL;
+ ph_set_sendhook(pmap->ph, NULL);
+ ph_set_recvhook(pmap->ph, NULL);
+ ph_close(pmap->ph, pmap->ph_fastclose);
}
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- errno = save_errno;
-}
-
-void
-ph_map_close(map)
- MAP *map;
-{
- PH_MAP_STRUCT *pmap;
- pmap = (PH_MAP_STRUCT *)map->map_db1;
- (void) fprintf(pmap->ph_to_server, "quit\n");
- (void) fflush(pmap->ph_to_server);
- ph_map_safeclose(map);
+ map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
}
static jmp_buf PHTimeout;
/* ARGSUSED */
static void
-ph_timeout(sig)
- int sig;
+ph_timeout(unused)
+ int unused;
{
/*
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
@@ -4642,25 +4947,30 @@ ph_timeout(sig)
errno = ETIMEDOUT;
longjmp(PHTimeout, 1);
}
-#else /* _FFR_PHMAP_TIMEOUT */
-/*
-** PH_MAP_CLOSE -- close the connection to the ph server
-*/
-void
-ph_map_close(map)
- MAP *map;
+static void
+ph_map_send_debug(text)
+ char *text;
{
- PH_MAP_STRUCT *pmap;
+ if (LogLevel > 9)
+ sm_syslog(LOG_NOTICE, CurEnv->e_id,
+ "ph_map_send_debug: ==> %s", text);
+ if (tTd(38, 20))
+ sm_dprintf("ph_map_send_debug: ==> %s\n", text);
+}
- pmap = (PH_MAP_STRUCT *)map->map_db1;
- CloseQi(pmap->ph_to_server, pmap->ph_from_server);
- pmap->ph_to_server = NULL;
- pmap->ph_from_server = NULL;
+static void
+ph_map_recv_debug(text)
+ char *text;
+{
+ if (LogLevel > 10)
+ sm_syslog(LOG_NOTICE, CurEnv->e_id,
+ "ph_map_recv_debug: <== %s", text);
+ if (tTd(38, 21))
+ sm_dprintf("ph_map_recv_debug: <== %s\n", text);
}
-#endif /* _FFR_PHMAP_TIMEOUT */
- /*
+/*
** PH_MAP_OPEN -- sub for opening PH map
*/
bool
@@ -4668,60 +4978,49 @@ ph_map_open(map, mode)
MAP *map;
int mode;
{
-#if !_FFR_PHMAP_TIMEOUT
- int save_errno = 0;
-#endif /* !_FFR_PHMAP_TIMEOUT */
- int j;
- char *hostlist, *tmp;
- QIR *server_data = NULL;
PH_MAP_STRUCT *pmap;
-#if _FFR_PHMAP_TIMEOUT
- register EVENT *ev = NULL;
-#endif /* _FFR_PHMAP_TIMEOUT */
+ register SM_EVENT *ev = NULL;
+ int save_errno = 0;
+ char *hostlist, *host;
if (tTd(38, 2))
- dprintf("ph_map_open(%s)\n", map->map_mname);
+ sm_dprintf("ph_map_open(%s)\n", map->map_mname);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
/* issue a pseudo-error message */
-# ifdef ENOSYS
- errno = ENOSYS;
-# else /* ENOSYS */
-# ifdef EFTYPE
- errno = EFTYPE;
-# else /* EFTYPE */
- errno = ENXIO;
-# endif /* EFTYPE */
-# endif /* ENOSYS */
- return FALSE;
+ errno = SM_EMAPCANTWRITE;
+ return false;
}
if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
bitset(MF_DEFER, map->map_mflags))
{
if (tTd(9, 1))
- dprintf("ph_map_open(%s) => DEFERRED\n",
- map->map_mname);
+ sm_dprintf("ph_map_open(%s) => DEFERRED\n",
+ map->map_mname);
/*
- ** Unset MF_DEFER here so that map_lookup() returns
- ** a temporary failure using the bogus map and
- ** map->map_tapp instead of the default permanent error.
+ ** Unset MF_DEFER here so that map_lookup() returns
+ ** a temporary failure using the bogus map and
+ ** map->map_tapp instead of the default permanent error.
*/
map->map_mflags &= ~MF_DEFER;
- return FALSE;
+ return false;
}
pmap = (PH_MAP_STRUCT *)map->map_db1;
+ pmap->ph_fastclose = 0; /* refresh field for reopen */
+ /* try each host in the list */
hostlist = newstr(pmap->ph_servers);
- tmp = strtok(hostlist, " ");
- do
+ for (host = strtok(hostlist, " ");
+ host != NULL;
+ host = strtok(NULL, " "))
{
-#if _FFR_PHMAP_TIMEOUT
+ /* set timeout */
if (pmap->ph_timeout != 0)
{
if (setjmp(PHTimeout) != 0)
@@ -4730,67 +5029,33 @@ ph_map_open(map, mode)
if (LogLevel > 1)
sm_syslog(LOG_NOTICE, CurEnv->e_id,
"timeout connecting to PH server %.100s",
- tmp);
-# ifdef ETIMEDOUT
+ host);
errno = ETIMEDOUT;
-# else /* ETIMEDOUT */
- errno = EAGAIN;
-# endif /* ETIMEDOUT */
goto ph_map_open_abort;
}
- ev = setevent(pmap->ph_timeout, ph_timeout, 0);
+ ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
}
- if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
- !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
- &(pmap->ph_from_server)) &&
- fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
- fflush(pmap->ph_to_server) == 0 &&
- (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
- server_data->code == 200)
+
+ /* open connection to server */
+ if (!ph_open(&(pmap->ph), host, PH_ROUNDROBIN|PH_DONTID,
+ ph_map_send_debug, ph_map_recv_debug) &&
+ !ph_id(pmap->ph, phmap_id))
{
if (ev != NULL)
- clrevent(ev);
- FreeQIR(server_data);
-#else /* _FFR_PHMAP_TIMEOUT */
- if (OpenQi(tmp, &(pmap->ph_to_server),
- &(pmap->ph_from_server)) >= 0)
- {
- if (fprintf(pmap->ph_to_server,
- "id sendmail+phmap\n") < 0 ||
- fflush(pmap->ph_to_server) != 0 ||
- (server_data = ReadQi(pmap->ph_from_server,
- &j)) == NULL ||
- server_data->code != 200)
- {
- save_errno = errno;
- CloseQi(pmap->ph_to_server,
- pmap->ph_from_server);
- continue;
- }
- if (server_data != NULL)
- FreeQIR(server_data);
-#endif /* _FFR_PHMAP_TIMEOUT */
- sm_free(hostlist);
- return TRUE;
+ sm_clrevent(ev);
+ sm_free(hostlist); /* XXX */
+ return true;
}
-#if _FFR_PHMAP_TIMEOUT
+
ph_map_open_abort:
- if (ev != NULL)
- clrevent(ev);
- ph_map_safeclose(map);
- if (server_data != NULL)
- {
- FreeQIR(server_data);
- server_data = NULL;
- }
-#else /* _FFR_PHMAP_TIMEOUT */
save_errno = errno;
-#endif /* _FFR_PHMAP_TIMEOUT */
- } while (tmp = strtok(NULL, " "));
+ if (ev != NULL)
+ sm_clrevent(ev);
+ pmap->ph_fastclose = PH_FASTCLOSE;
+ ph_map_close(map);
+ errno = save_errno;
+ }
-#if !_FFR_PHMAP_TIMEOUT
- errno = save_errno;
-#endif /* !_FFR_PHMAP_TIMEOUT */
if (bitset(MF_NODEFER, map->map_mflags))
{
if (errno == 0)
@@ -4802,18 +5067,14 @@ ph_map_open(map, mode)
sm_syslog(LOG_NOTICE, CurEnv->e_id,
"ph_map_open: %s: cannot connect to PH server",
map->map_mname);
- sm_free(hostlist);
- return FALSE;
+ sm_free(hostlist); /* XXX */
+ return false;
}
/*
** PH_MAP_LOOKUP -- look up key from ph server
*/
-#if _FFR_PHMAP_TIMEOUT
-# define MAX_PH_FIELDS 20
-#endif /* _FFR_PHMAP_TIMEOUT */
-
char *
ph_map_lookup(map, key, args, pstat)
MAP *map;
@@ -4821,25 +5082,16 @@ ph_map_lookup(map, key, args, pstat)
char **args;
int *pstat;
{
- int j;
- size_t sz;
- char *tmp, *tmp2;
- char *message = NULL, *field = NULL, *fmtkey;
- QIR *server_data = NULL;
- QIR *qirp;
- char keybuf[MAXKEY + 1], fieldbuf[101];
-#if _FFR_PHMAP_TIMEOUT
- QIR *hold_data[MAX_PH_FIELDS];
- int hold_data_idx = 0;
- register EVENT *ev = NULL;
-#endif /* _FFR_PHMAP_TIMEOUT */
+ int i, save_errno = 0;
+ register SM_EVENT *ev = NULL;
PH_MAP_STRUCT *pmap;
+ char *value = NULL;
pmap = (PH_MAP_STRUCT *)map->map_db1;
*pstat = EX_OK;
-#if _FFR_PHMAP_TIMEOUT
+ /* set timeout */
if (pmap->ph_timeout != 0)
{
if (setjmp(PHTimeout) != 0)
@@ -4849,263 +5101,52 @@ ph_map_lookup(map, key, args, pstat)
sm_syslog(LOG_NOTICE, CurEnv->e_id,
"timeout during PH lookup of %.100s",
key);
-# ifdef ETIMEDOUT
errno = ETIMEDOUT;
-# else /* ETIMEDOUT */
- errno = 0;
-# endif /* ETIMEDOUT */
*pstat = EX_TEMPFAIL;
goto ph_map_lookup_abort;
}
- ev = setevent(pmap->ph_timeout, ph_timeout, 0);
+ ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
}
-#endif /* _FFR_PHMAP_TIMEOUT */
- /* check all relevant fields */
- tmp = pmap->ph_field_list;
- do
- {
-#if _FFR_PHMAP_TIMEOUT
- server_data = NULL;
-#endif /* _FFR_PHMAP_TIMEOUT */
- while (isascii(*tmp) && isspace(*tmp))
- tmp++;
- if (*tmp == '\0')
- break;
- sz = strcspn(tmp, " ") + 1;
- if (sz > sizeof fieldbuf)
- sz = sizeof fieldbuf;
- (void) strlcpy(fieldbuf, tmp, sz);
- field = fieldbuf;
- tmp += sz;
-
- (void) strlcpy(keybuf, key, sizeof keybuf);
- fmtkey = keybuf;
- if (strcmp(field, "alias") == 0)
- {
- /*
- ** for alias lookups, replace any punctuation
- ** characters with '-'
- */
-
- for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
- {
- if (isascii(*tmp2) && ispunct(*tmp2))
- *tmp2 = '-';
- }
- tmp2 = field;
- }
- else if (strcmp(field,"spacedname") == 0)
- {
- /*
- ** for "spaced" name lookups, replace any
- ** punctuation characters with a space
- */
-
- for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
- {
- if (isascii(*tmp2) && ispunct(*tmp2) &&
- *tmp2 != '*')
- *tmp2 = ' ';
- }
- tmp2 = &(field[6]);
- }
- else
- tmp2 = field;
-
- if (LogLevel > 9)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "ph_map_lookup: query %s=\"%s\" return email",
- tmp2, fmtkey);
- if (tTd(38, 20))
- dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
- tmp2, fmtkey);
-
- j = 0;
-
- if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
- tmp2, fmtkey) < 0)
- message = "qi query command failed";
- else if (fflush(pmap->ph_to_server) != 0)
- message = "qi fflush failed";
- else if ((server_data = ReadQi(pmap->ph_from_server,
- &j)) == NULL)
- message = "ReadQi() returned NULL";
-
-#if _FFR_PHMAP_TIMEOUT
- if ((hold_data[hold_data_idx] = server_data) != NULL)
- {
- /* save pointer for later free() */
- hold_data_idx++;
- }
-#endif /* _FFR_PHMAP_TIMEOUT */
-
- if (server_data == NULL ||
- (server_data->code >= 400 &&
- server_data->code < 500))
- {
- /* temporary failure */
- *pstat = EX_TEMPFAIL;
-#if _FFR_PHMAP_TIMEOUT
- break;
-#else /* _FFR_PHMAP_TIMEOUT */
- if (server_data != NULL)
- {
- FreeQIR(server_data);
- server_data = NULL;
- }
- return NULL;
-#endif /* _FFR_PHMAP_TIMEOUT */
- }
-
- /*
- ** if we found a single match, break out.
- ** otherwise, try the next field.
- */
-
- if (j == 1)
- break;
-
- /*
- ** check for a single response which is an error:
- ** ReadQi() doesn't set j on error responses,
- ** but we should stop here instead of moving on if
- ** it happens (e.g., alias found but email field empty)
- */
-
- for (qirp = server_data;
- qirp != NULL && qirp->code < 0;
- qirp++)
- {
- if (tTd(38, 20))
- dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
- qirp->code, qirp->subcode, qirp->field,
- (qirp->message ? qirp->message
- : "[NULL]"));
- if (qirp->code <= -500)
- {
- j = 0;
- goto ph_map_lookup_abort;
- }
- }
-
-#if _FFR_PHMAP_TIMEOUT
- } while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
-#else /* _FFR_PHMAP_TIMEOUT */
- } while (*tmp != '\0');
-#endif /* _FFR_PHMAP_TIMEOUT */
+ /* perform lookup */
+ i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
+ if (i == -1)
+ *pstat = EX_TEMPFAIL;
+ else if (i == PH_NOMATCH || i == PH_DATAERR)
+ *pstat = EX_UNAVAILABLE;
ph_map_lookup_abort:
-#if _FFR_PHMAP_TIMEOUT
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
/*
- ** Return EX_TEMPFAIL if the timer popped
+ ** Close the connection if the timer popped
** or we got a temporary PH error
*/
if (*pstat == EX_TEMPFAIL)
- ph_map_safeclose(map);
-
- /* if we didn't find a single match, bail out */
- if (*pstat == EX_OK && j != 1)
- *pstat = EX_UNAVAILABLE;
+ {
+ save_errno = errno;
+ pmap->ph_fastclose = PH_FASTCLOSE;
+ ph_map_close(map);
+ errno = save_errno;
+ }
if (*pstat == EX_OK)
{
- /*
- ** skip leading whitespace and chop at first address
- */
-
- for (tmp = server_data->message;
- isascii(*tmp) && isspace(*tmp);
- tmp++)
- continue;
-
- for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
- {
- if (isascii(*tmp2) && isspace(*tmp2))
- {
- *tmp2 = '\0';
- break;
- }
- }
-
if (tTd(38,20))
- dprintf("ph_map_lookup: %s => %s\n", key, tmp);
+ sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
if (bitset(MF_MATCHONLY, map->map_mflags))
- message = map_rewrite(map, key, strlen(key), NULL);
+ return map_rewrite(map, key, strlen(key), NULL);
else
- message = map_rewrite(map, tmp, strlen(tmp), args);
+ return map_rewrite(map, value, strlen(value), args);
}
- /*
- ** Deferred free() of returned server_data values
- ** the deferral is to avoid the risk of a free() being
- ** interrupted by the event timer. By now the timeout event
- ** has been cleared and none of the data is still in use.
- */
-
- while (--hold_data_idx >= 0)
- {
- if (hold_data[hold_data_idx] != NULL)
- FreeQIR(hold_data[hold_data_idx]);
- }
-
- if (*pstat == EX_OK)
- return message;
-
return NULL;
-#else /* _FFR_PHMAP_TIMEOUT */
- /* if we didn't find a single match, bail out */
- if (j != 1)
- {
- *pstat = EX_UNAVAILABLE;
- if (server_data != NULL)
- {
- FreeQIR(server_data);
- server_data = NULL;
- }
- return NULL;
- }
-
- /*
- ** skip leading whitespace and chop at first address
- */
-
- for (tmp = server_data->message;
- isascii(*tmp) && isspace(*tmp);
- tmp++)
- continue;
-
- for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
- {
- if (isascii(*tmp2) && isspace(*tmp2))
- {
- *tmp2 = '\0';
- break;
- }
- }
-
- if (tTd(38,20))
- dprintf("ph_map_lookup: %s => %s\n", key, tmp);
-
- if (bitset(MF_MATCHONLY, map->map_mflags))
- message = map_rewrite(map, key, strlen(key), NULL);
- else
- message = map_rewrite(map, tmp, strlen(tmp), args);
- if (server_data != NULL)
- {
- FreeQIR(server_data);
- server_data = NULL;
- }
- return message;
-#endif /* _FFR_PHMAP_TIMEOUT */
}
#endif /* PH_MAP */
- /*
+/*
** syslog map
*/
@@ -5165,56 +5206,56 @@ syslog_map_parseargs(map, args)
map->map_prio = LOG_INFO;
else
{
- if (strncasecmp("LOG_", priority, 4) == 0)
+ if (sm_strncasecmp("LOG_", priority, 4) == 0)
priority += 4;
#ifdef LOG_EMERG
- if (strcasecmp("EMERG", priority) == 0)
+ if (sm_strcasecmp("EMERG", priority) == 0)
map->map_prio = LOG_EMERG;
else
#endif /* LOG_EMERG */
#ifdef LOG_ALERT
- if (strcasecmp("ALERT", priority) == 0)
+ if (sm_strcasecmp("ALERT", priority) == 0)
map->map_prio = LOG_ALERT;
else
#endif /* LOG_ALERT */
#ifdef LOG_CRIT
- if (strcasecmp("CRIT", priority) == 0)
+ if (sm_strcasecmp("CRIT", priority) == 0)
map->map_prio = LOG_CRIT;
else
#endif /* LOG_CRIT */
#ifdef LOG_ERR
- if (strcasecmp("ERR", priority) == 0)
+ if (sm_strcasecmp("ERR", priority) == 0)
map->map_prio = LOG_ERR;
else
#endif /* LOG_ERR */
#ifdef LOG_WARNING
- if (strcasecmp("WARNING", priority) == 0)
+ if (sm_strcasecmp("WARNING", priority) == 0)
map->map_prio = LOG_WARNING;
else
#endif /* LOG_WARNING */
#ifdef LOG_NOTICE
- if (strcasecmp("NOTICE", priority) == 0)
+ if (sm_strcasecmp("NOTICE", priority) == 0)
map->map_prio = LOG_NOTICE;
else
#endif /* LOG_NOTICE */
#ifdef LOG_INFO
- if (strcasecmp("INFO", priority) == 0)
+ if (sm_strcasecmp("INFO", priority) == 0)
map->map_prio = LOG_INFO;
else
#endif /* LOG_INFO */
#ifdef LOG_DEBUG
- if (strcasecmp("DEBUG", priority) == 0)
+ if (sm_strcasecmp("DEBUG", priority) == 0)
map->map_prio = LOG_DEBUG;
else
#endif /* LOG_DEBUG */
{
- syserr("syslog_map_parseargs: Unknown priority %s\n",
+ syserr("syslog_map_parseargs: Unknown priority %s",
priority);
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/*
@@ -5233,7 +5274,7 @@ syslog_map_lookup(map, string, args, statp)
if (ptr != NULL)
{
if (tTd(38, 20))
- dprintf("syslog_map_lookup(%s (priority %d): %s\n",
+ sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
map->map_mname, map->map_prio, ptr);
sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
@@ -5243,11 +5284,11 @@ syslog_map_lookup(map, string, args, statp)
return "";
}
- /*
+/*
** HESIOD Modules
*/
-#ifdef HESIOD
+#if HESIOD
bool
hes_map_open(map, mode)
@@ -5255,32 +5296,24 @@ hes_map_open(map, mode)
int mode;
{
if (tTd(38, 2))
- dprintf("hes_map_open(%s, %s, %d)\n",
+ sm_dprintf("hes_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
if (mode != O_RDONLY)
{
/* issue a pseudo-error message */
-# ifdef ENOSYS
- errno = ENOSYS;
-# else /* ENOSYS */
-# ifdef EFTYPE
- errno = EFTYPE;
-# else /* EFTYPE */
- errno = ENXIO;
-# endif /* EFTYPE */
-# endif /* ENOSYS */
- return FALSE;
+ errno = SM_EMAPCANTWRITE;
+ return false;
}
# ifdef HESIOD_INIT
if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
- return TRUE;
+ return true;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
- errstring(errno));
- return FALSE;
+ sm_errstring(errno));
+ return false;
# else /* HESIOD_INIT */
if (hes_error() == HES_ER_UNINIT)
hes_init();
@@ -5288,13 +5321,13 @@ hes_map_open(map, mode)
{
case HES_ER_OK:
case HES_ER_NOTFOUND:
- return TRUE;
+ return true;
}
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
- return FALSE;
+ return false;
# endif /* HESIOD_INIT */
}
@@ -5308,7 +5341,7 @@ hes_map_lookup(map, name, av, statp)
char **hp;
if (tTd(38, 20))
- dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
+ sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
if (name[0] == '\\')
{
@@ -5323,7 +5356,7 @@ hes_map_lookup(map, name, av, statp)
else
np = xalloc(strlen(name) + 2);
np[0] = '\\';
- (void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
+ (void) sm_strlcpy(&np[1], name, (sizeof nbuf) - 1);
# ifdef HESIOD_INIT
hp = hesiod_resolve(HesiodContext, np, map->map_file);
# else /* HESIOD_INIT */
@@ -5331,7 +5364,7 @@ hes_map_lookup(map, name, av, statp)
# endif /* HESIOD_INIT */
save_errno = errno;
if (np != nbuf)
- sm_free(np);
+ sm_free(np); /* XXX */
errno = save_errno;
}
else
@@ -5351,9 +5384,9 @@ hes_map_lookup(map, name, av, statp)
*statp = EX_NOTFOUND;
break;
case ECONNREFUSED:
- case EMSGSIZE:
*statp = EX_TEMPFAIL;
break;
+ case EMSGSIZE:
case ENOMEM:
default:
*statp = EX_UNAVAILABLE;
@@ -5394,8 +5427,29 @@ hes_map_lookup(map, name, av, statp)
return map_rewrite(map, hp[0], strlen(hp[0]), av);
}
+/*
+** HES_MAP_CLOSE -- free the Hesiod context
+*/
+
+void
+hes_map_close(map)
+ MAP *map;
+{
+ if (tTd(38, 20))
+ sm_dprintf("hes_map_close(%s)\n", map->map_file);
+
+# ifdef HESIOD_INIT
+ /* Free the hesiod context */
+ if (HesiodContext != NULL)
+ {
+ hesiod_end(HesiodContext);
+ HesiodContext = NULL;
+ }
+# endif /* HESIOD_INIT */
+}
+
#endif /* HESIOD */
- /*
+/*
** NeXT NETINFO Modules
*/
@@ -5414,7 +5468,7 @@ ni_map_open(map, mode)
int mode;
{
if (tTd(38, 2))
- dprintf("ni_map_open(%s, %s, %d)\n",
+ sm_dprintf("ni_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
@@ -5424,10 +5478,14 @@ ni_map_open(map, mode)
if (map->map_valcolnm == NULL)
map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
- if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
- map->map_coldelim = ',';
-
- return TRUE;
+ if (map->map_coldelim == '\0')
+ {
+ if (bitset(MF_ALIAS, map->map_mflags))
+ map->map_coldelim = ',';
+ else if (bitset(MF_FILECLASS, map->map_mflags))
+ map->map_coldelim = ' ';
+ }
+ return true;
}
@@ -5446,7 +5504,7 @@ ni_map_lookup(map, name, av, statp)
char *propval;
if (tTd(38, 20))
- dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
+ sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
propval = ni_propval(map->map_file, map->map_keycolnm, name,
map->map_valcolnm, map->map_coldelim);
@@ -5454,11 +5512,14 @@ ni_map_lookup(map, name, av, statp)
if (propval == NULL)
return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- res = map_rewrite(map, name, strlen(name), NULL);
- else
- res = map_rewrite(map, propval, strlen(propval), av);
- sm_free(propval);
+ SM_TRY
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ res = map_rewrite(map, name, strlen(name), NULL);
+ else
+ res = map_rewrite(map, propval, strlen(propval), av);
+ SM_FINALLY
+ sm_free(propval);
+ SM_END_TRY
return res;
}
@@ -5474,12 +5535,12 @@ ni_getcanonname(name, hbsize, statp)
char nbuf[MAXNAME + 1];
if (tTd(38, 20))
- dprintf("ni_getcanonname(%s)\n", name);
+ sm_dprintf("ni_getcanonname(%s)\n", name);
- if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
+ if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
(void) shorten_hostname(nbuf);
@@ -5487,7 +5548,7 @@ ni_getcanonname(name, hbsize, statp)
if (strchr(nbuf, '.'))
{
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
/* Do the search */
@@ -5496,211 +5557,25 @@ ni_getcanonname(name, hbsize, statp)
if (vptr == NULL)
{
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
/* Only want the first machine name */
if ((ptr = strchr(vptr, '\n')) != NULL)
*ptr = '\0';
- if (hbsize >= strlen(vptr))
+ if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
{
- (void) strlcpy(name, vptr, hbsize);
sm_free(vptr);
- *statp = EX_OK;
- return TRUE;
+ *statp = EX_UNAVAILABLE;
+ return true;
}
- *statp = EX_UNAVAILABLE;
sm_free(vptr);
- return FALSE;
-}
-
-
-/*
-** NI_PROPVAL -- NetInfo property value lookup routine
-**
-** Parameters:
-** keydir -- the NetInfo directory name in which to search
-** for the key.
-** keyprop -- the name of the property in which to find the
-** property we are interested. Defaults to "name".
-** keyval -- the value for which we are really searching.
-** valprop -- the property name for the value in which we
-** are interested.
-** sepchar -- if non-nil, this can be multiple-valued, and
-** we should return a string separated by this
-** character.
-**
-** Returns:
-** NULL -- if:
-** 1. the directory is not found
-** 2. the property name is not found
-** 3. the property contains multiple values
-** 4. some error occurred
-** else -- the value of the lookup.
-**
-** Example:
-** To search for an alias value, use:
-** ni_propval("/aliases", "name", aliasname, "members", ',')
-**
-** Notes:
-** Caller should free the return value of ni_proval
-*/
-
-# include <netinfo/ni.h>
-
-# define LOCAL_NETINFO_DOMAIN "."
-# define PARENT_NETINFO_DOMAIN ".."
-# define MAX_NI_LEVELS 256
-
-char *
-ni_propval(keydir, keyprop, keyval, valprop, sepchar)
- char *keydir;
- char *keyprop;
- char *keyval;
- char *valprop;
- int sepchar;
-{
- char *propval = NULL;
- int i;
- int j, alen, l;
- void *ni = NULL;
- void *lastni = NULL;
- ni_status nis;
- ni_id nid;
- ni_namelist ninl;
- register char *p;
- char keybuf[1024];
-
- /*
- ** Create the full key from the two parts.
- **
- ** Note that directory can end with, e.g., "name=" to specify
- ** an alternate search property.
- */
-
- i = strlen(keydir) + strlen(keyval) + 2;
- if (keyprop != NULL)
- i += strlen(keyprop) + 1;
- if (i >= sizeof keybuf)
- return NULL;
- (void) strlcpy(keybuf, keydir, sizeof keybuf);
- (void) strlcat(keybuf, "/", sizeof keybuf);
- if (keyprop != NULL)
- {
- (void) strlcat(keybuf, keyprop, sizeof keybuf);
- (void) strlcat(keybuf, "=", sizeof keybuf);
- }
- (void) strlcat(keybuf, keyval, sizeof keybuf);
-
- if (tTd(38, 21))
- dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
- keydir, keyprop, keyval, valprop, sepchar, keybuf);
- /*
- ** If the passed directory and property name are found
- ** in one of netinfo domains we need to search (starting
- ** from the local domain moving all the way back to the
- ** root domain) set propval to the property's value
- ** and return it.
- */
-
- for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
- {
- if (i == 0)
- {
- nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
- if (tTd(38, 20))
- dprintf("ni_open(LOCAL) = %d\n", nis);
- }
- else
- {
- if (lastni != NULL)
- ni_free(lastni);
- lastni = ni;
- nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
- if (tTd(38, 20))
- dprintf("ni_open(PARENT) = %d\n", nis);
- }
-
- /*
- ** Don't bother if we didn't get a handle on a
- ** proper domain. This is not necessarily an error.
- ** We would get a positive ni_status if, for instance
- ** we never found the directory or property and tried
- ** to open the parent of the root domain!
- */
-
- if (nis != 0)
- break;
-
- /*
- ** Find the path to the server information.
- */
-
- if (ni_pathsearch(ni, &nid, keybuf) != 0)
- continue;
-
- /*
- ** Find associated value information.
- */
-
- if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
- continue;
-
- if (tTd(38, 20))
- dprintf("ni_lookupprop: len=%d\n",
- ninl.ni_namelist_len);
-
- /*
- ** See if we have an acceptable number of values.
- */
-
- if (ninl.ni_namelist_len <= 0)
- continue;
-
- if (sepchar == '\0' && ninl.ni_namelist_len > 1)
- {
- ni_namelist_free(&ninl);
- continue;
- }
-
- /*
- ** Calculate number of bytes needed and build result
- */
-
- alen = 1;
- for (j = 0; j < ninl.ni_namelist_len; j++)
- alen += strlen(ninl.ni_namelist_val[j]) + 1;
- propval = p = xalloc(alen);
- for (j = 0; j < ninl.ni_namelist_len; j++)
- {
- (void) strlcpy(p, ninl.ni_namelist_val[j], alen);
- l = strlen(p);
- p += l;
- *p++ = sepchar;
- alen -= l + 1;
- }
- *--p = '\0';
-
- ni_namelist_free(&ninl);
- }
-
- /*
- ** Clean up.
- */
-
- if (ni != NULL)
- ni_free(ni);
- if (lastni != NULL && ni != lastni)
- ni_free(lastni);
- if (tTd(38, 20))
- dprintf("ni_propval returns: '%s'\n", propval);
-
- return propval;
+ *statp = EX_OK;
+ return false;
}
-
#endif /* NETINFO */
- /*
+/*
** TEXT (unindexed text file) Modules
**
** This code donated by Sun Microsystems.
@@ -5722,28 +5597,28 @@ text_map_open(map, mode)
int i;
if (tTd(38, 2))
- dprintf("text_map_open(%s, %s, %d)\n",
+ sm_dprintf("text_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
errno = EPERM;
- return FALSE;
+ return false;
}
if (*map->map_file == '\0')
{
syserr("text map \"%s\": file name required",
map->map_mname);
- return FALSE;
+ return false;
}
if (map->map_file[0] != '/')
{
syserr("text map \"%s\": file name must be fully qualified",
map->map_mname);
- return FALSE;
+ return false;
}
sff = SFF_ROOTOK|SFF_REGONLY;
@@ -5758,12 +5633,12 @@ text_map_open(map, mode)
/* cannot open this map */
if (tTd(38, 2))
- dprintf("\tunsafe map file: %d\n", i);
+ sm_dprintf("\tunsafe map file: %d\n", i);
errno = save_errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("text map \"%s\": unsafe map file %s",
map->map_mname, map->map_file);
- return FALSE;
+ return false;
}
if (map->map_keycolnm == NULL)
@@ -5775,7 +5650,7 @@ text_map_open(map, mode)
syserr("text map \"%s\", file %s: -k should specify a number, not %s",
map->map_mname, map->map_file,
map->map_keycolnm);
- return FALSE;
+ return false;
}
map->map_keycolno = atoi(map->map_keycolnm);
}
@@ -5789,23 +5664,23 @@ text_map_open(map, mode)
syserr("text map \"%s\", file %s: -v should specify a number, not %s",
map->map_mname, map->map_file,
map->map_valcolnm);
- return FALSE;
+ return false;
}
map->map_valcolno = atoi(map->map_valcolnm);
}
if (tTd(38, 2))
{
- dprintf("text_map_open(%s, %s): delimiter = ",
+ sm_dprintf("text_map_open(%s, %s): delimiter = ",
map->map_mname, map->map_file);
if (map->map_coldelim == '\0')
- dprintf("(white space)\n");
+ sm_dprintf("(white space)\n");
else
- dprintf("%c\n", map->map_coldelim);
+ sm_dprintf("%c\n", map->map_coldelim);
}
map->map_sff = sff;
- return TRUE;
+ return true;
}
@@ -5823,7 +5698,7 @@ text_map_lookup(map, name, av, statp)
char *vp;
auto int vsize;
int buflen;
- FILE *f;
+ SM_FILE_T *f;
char delim;
int key_idx;
bool found_it;
@@ -5832,13 +5707,13 @@ text_map_lookup(map, name, av, statp)
char linebuf[MAXLINE];
char buf[MAXNAME + 1];
- found_it = FALSE;
+ found_it = false;
if (tTd(38, 20))
- dprintf("text_map_lookup(%s, %s)\n", map->map_mname, name);
+ sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname, name);
buflen = strlen(name);
if (buflen > sizeof search_key - 1)
- buflen = sizeof search_key - 1;
+ buflen = sizeof search_key - 1; /* XXX just cut if off? */
memmove(search_key, name, buflen);
search_key[buflen] = '\0';
if (!bitset(MF_NOFOLDCASE, map->map_mflags))
@@ -5853,7 +5728,7 @@ text_map_lookup(map, name, av, statp)
}
key_idx = map->map_keycolno;
delim = map->map_coldelim;
- while (fgets(linebuf, MAXLINE, f) != NULL)
+ while (sm_io_fgets(f, SM_TIME_DEFAULT, linebuf, MAXLINE) != NULL)
{
char *p;
@@ -5864,13 +5739,13 @@ text_map_lookup(map, name, av, statp)
if (p != NULL)
*p = '\0';
p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
- if (p != NULL && strcasecmp(search_key, p) == 0)
+ if (p != NULL && sm_strcasecmp(search_key, p) == 0)
{
- found_it = TRUE;
+ found_it = true;
break;
}
}
- (void) fclose(f);
+ (void) sm_io_close(f, SM_TIME_DEFAULT);
if (!found_it)
{
*statp = EX_NOTFOUND;
@@ -5902,30 +5777,31 @@ text_getcanonname(name, hbsize, statp)
{
bool found;
char *dot;
- FILE *f;
+ SM_FILE_T *f;
char linebuf[MAXLINE];
char cbuf[MAXNAME + 1];
char nbuf[MAXNAME + 1];
if (tTd(38, 20))
- dprintf("text_getcanonname(%s)\n", name);
+ sm_dprintf("text_getcanonname(%s)\n", name);
- if (strlen(name) >= (SIZE_T) sizeof nbuf)
+ if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
- (void) strlcpy(nbuf, name, sizeof nbuf);
dot = shorten_hostname(nbuf);
- f = fopen(HostsFile, "r");
+ f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
+ NULL);
if (f == NULL)
{
*statp = EX_UNAVAILABLE;
- return FALSE;
+ return false;
}
- found = FALSE;
- while (!found && fgets(linebuf, MAXLINE, f) != NULL)
+ found = false;
+ while (!found &&
+ sm_io_fgets(f, SM_TIME_DEFAULT, linebuf, MAXLINE) != NULL)
{
char *p = strpbrk(linebuf, "#\n");
@@ -5935,23 +5811,22 @@ text_getcanonname(name, hbsize, statp)
found = extract_canonname(nbuf, dot, linebuf,
cbuf, sizeof cbuf);
}
- (void) fclose(f);
+ (void) sm_io_close(f, SM_TIME_DEFAULT);
if (!found)
{
*statp = EX_NOHOST;
- return FALSE;
+ return false;
}
- if ((SIZE_T) hbsize >= strlen(cbuf))
+ if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
{
- (void) strlcpy(name, cbuf, hbsize);
- *statp = EX_OK;
- return TRUE;
+ *statp = EX_UNAVAILABLE;
+ return false;
}
- *statp = EX_UNAVAILABLE;
- return FALSE;
+ *statp = EX_OK;
+ return true;
}
- /*
+/*
** STAB (Symbol Table) Modules
*/
@@ -5971,7 +5846,7 @@ stab_map_lookup(map, name, av, pstat)
register STAB *s;
if (tTd(38, 20))
- dprintf("stab_lookup(%s, %s)\n",
+ sm_dprintf("stab_lookup(%s, %s)\n",
map->map_mname, name);
s = stab(name, ST_ALIAS, ST_FIND);
@@ -6012,19 +5887,19 @@ stab_map_open(map, mode)
register MAP *map;
int mode;
{
- FILE *af;
+ SM_FILE_T *af;
long sff;
struct stat st;
if (tTd(38, 2))
- dprintf("stab_map_open(%s, %s, %d)\n",
+ sm_dprintf("stab_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
errno = EPERM;
- return FALSE;
+ return false;
}
sff = SFF_ROOTOK|SFF_REGONLY;
@@ -6034,16 +5909,16 @@ stab_map_open(map, mode)
sff |= SFF_SAFEDIRPATH;
af = safefopen(map->map_file, O_RDONLY, 0444, sff);
if (af == NULL)
- return FALSE;
- readaliases(map, af, FALSE, FALSE);
+ return false;
+ readaliases(map, af, false, false);
- if (fstat(fileno(af), &st) >= 0)
+ if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
map->map_mtime = st.st_mtime;
- (void) fclose(af);
+ (void) sm_io_close(af, SM_TIME_DEFAULT);
- return TRUE;
+ return true;
}
- /*
+/*
** Implicit Modules
**
** Tries several types. For back compatibility of aliases.
@@ -6062,14 +5937,14 @@ impl_map_lookup(map, name, av, pstat)
int *pstat;
{
if (tTd(38, 20))
- dprintf("impl_map_lookup(%s, %s)\n",
+ sm_dprintf("impl_map_lookup(%s, %s)\n",
map->map_mname, name);
-#ifdef NEWDB
+#if NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
return db_map_lookup(map, name, av, pstat);
#endif /* NEWDB */
-#ifdef NDBM
+#if NDBM
if (bitset(MF_IMPL_NDBM, map->map_mflags))
return ndbm_map_lookup(map, name, av, pstat);
#endif /* NDBM */
@@ -6087,13 +5962,13 @@ impl_map_store(map, lhs, rhs)
char *rhs;
{
if (tTd(38, 12))
- dprintf("impl_map_store(%s, %s, %s)\n",
+ sm_dprintf("impl_map_store(%s, %s, %s)\n",
map->map_mname, lhs, rhs);
-#ifdef NEWDB
+#if NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
db_map_store(map, lhs, rhs);
#endif /* NEWDB */
-#ifdef NDBM
+#if NDBM
if (bitset(MF_IMPL_NDBM, map->map_mflags))
ndbm_map_store(map, lhs, rhs);
#endif /* NDBM */
@@ -6110,27 +5985,27 @@ impl_map_open(map, mode)
int mode;
{
if (tTd(38, 2))
- dprintf("impl_map_open(%s, %s, %d)\n",
+ sm_dprintf("impl_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
-#ifdef NEWDB
+#if NEWDB
map->map_mflags |= MF_IMPL_HASH;
if (hash_map_open(map, mode))
{
# ifdef NDBM_YP_COMPAT
if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
# endif /* NDBM_YP_COMPAT */
- return TRUE;
+ return true;
}
else
map->map_mflags &= ~MF_IMPL_HASH;
#endif /* NEWDB */
-#ifdef NDBM
+#if NDBM
map->map_mflags |= MF_IMPL_NDBM;
if (ndbm_map_open(map, mode))
{
- return TRUE;
+ return true;
}
else
map->map_mflags &= ~MF_IMPL_NDBM;
@@ -6149,7 +6024,7 @@ impl_map_open(map, mode)
if (mode == O_RDONLY)
return stab_map_open(map, mode);
else
- return FALSE;
+ return false;
}
@@ -6162,9 +6037,9 @@ impl_map_close(map)
MAP *map;
{
if (tTd(38, 9))
- dprintf("impl_map_close(%s, %s, %lx)\n",
+ sm_dprintf("impl_map_close(%s, %s, %lx)\n",
map->map_mname, map->map_file, map->map_mflags);
-#ifdef NEWDB
+#if NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
{
db_map_close(map);
@@ -6172,7 +6047,7 @@ impl_map_close(map)
}
#endif /* NEWDB */
-#ifdef NDBM
+#if NDBM
if (bitset(MF_IMPL_NDBM, map->map_mflags))
{
ndbm_map_close(map);
@@ -6180,7 +6055,7 @@ impl_map_close(map)
}
#endif /* NDBM */
}
- /*
+/*
** User map class.
**
** Provides access to the system password file.
@@ -6198,48 +6073,40 @@ user_map_open(map, mode)
int mode;
{
if (tTd(38, 2))
- dprintf("user_map_open(%s, %d)\n",
+ sm_dprintf("user_map_open(%s, %d)\n",
map->map_mname, mode);
mode &= O_ACCMODE;
if (mode != O_RDONLY)
{
/* issue a pseudo-error message */
-#ifdef ENOSYS
- errno = ENOSYS;
-#else /* ENOSYS */
-# ifdef EFTYPE
- errno = EFTYPE;
-# else /* EFTYPE */
- errno = ENXIO;
-# endif /* EFTYPE */
-#endif /* ENOSYS */
- return FALSE;
+ errno = SM_EMAPCANTWRITE;
+ return false;
}
if (map->map_valcolnm == NULL)
/* EMPTY */
/* nothing */ ;
- else if (strcasecmp(map->map_valcolnm, "name") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
map->map_valcolno = 1;
- else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
map->map_valcolno = 2;
- else if (strcasecmp(map->map_valcolnm, "uid") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
map->map_valcolno = 3;
- else if (strcasecmp(map->map_valcolnm, "gid") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
map->map_valcolno = 4;
- else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
map->map_valcolno = 5;
- else if (strcasecmp(map->map_valcolnm, "dir") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
map->map_valcolno = 6;
- else if (strcasecmp(map->map_valcolnm, "shell") == 0)
+ else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
map->map_valcolno = 7;
else
{
syserr("User map %s: unknown column name %s",
map->map_mname, map->map_valcolnm);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
@@ -6255,15 +6122,15 @@ user_map_lookup(map, key, av, statp)
char **av;
int *statp;
{
- struct passwd *pw;
auto bool fuzzy;
+ SM_MBDB_T user;
if (tTd(38, 20))
- dprintf("user_map_lookup(%s, %s)\n",
+ sm_dprintf("user_map_lookup(%s, %s)\n",
map->map_mname, key);
- pw = finduser(key, &fuzzy);
- if (pw == NULL)
+ *statp = finduser(key, &fuzzy, &user);
+ if (*statp != EX_OK)
return NULL;
if (bitset(MF_MATCHONLY, map->map_mflags))
return map_rewrite(map, key, strlen(key), NULL);
@@ -6276,39 +6143,41 @@ user_map_lookup(map, key, av, statp)
{
case 0:
case 1:
- rwval = pw->pw_name;
+ rwval = user.mbdb_name;
break;
case 2:
- rwval = pw->pw_passwd;
+ rwval = "x"; /* passwd no longer supported */
break;
case 3:
- snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
+ (void) sm_snprintf(buf, sizeof buf, "%d",
+ (int) user.mbdb_uid);
rwval = buf;
break;
case 4:
- snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
+ (void) sm_snprintf(buf, sizeof buf, "%d",
+ (int) user.mbdb_gid);
rwval = buf;
break;
case 5:
- rwval = pw->pw_gecos;
+ rwval = user.mbdb_fullname;
break;
case 6:
- rwval = pw->pw_dir;
+ rwval = user.mbdb_homedir;
break;
case 7:
- rwval = pw->pw_shell;
+ rwval = user.mbdb_shell;
break;
}
return map_rewrite(map, rwval, strlen(rwval), av);
}
}
- /*
+/*
** Program map type.
**
** This provides access to arbitrary programs. It should be used
@@ -6334,14 +6203,14 @@ prog_map_lookup(map, name, av, statp)
char buf[MAXLINE];
if (tTd(38, 20))
- dprintf("prog_map_lookup(%s, %s) %s\n",
+ sm_dprintf("prog_map_lookup(%s, %s) %s\n",
map->map_mname, name, map->map_file);
i = 0;
argv[i++] = map->map_file;
if (map->map_rebuild != NULL)
{
- snprintf(buf, sizeof buf, "%s", map->map_rebuild);
+ (void) sm_strlcpy(buf, map->map_rebuild, sizeof buf);
for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
{
if (i >= MAXPV - 1)
@@ -6353,21 +6222,21 @@ prog_map_lookup(map, name, av, statp)
argv[i] = NULL;
if (tTd(38, 21))
{
- dprintf("prog_open:");
+ sm_dprintf("prog_open:");
for (i = 0; argv[i] != NULL; i++)
- dprintf(" %s", argv[i]);
- dprintf("\n");
+ sm_dprintf(" %s", argv[i]);
+ sm_dprintf("\n");
}
- (void) blocksignal(SIGCHLD);
+ (void) sm_blocksignal(SIGCHLD);
pid = prog_open(argv, &fd, CurEnv);
if (pid < 0)
{
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, errstring(errno));
+ map->map_mname, sm_errstring(errno));
else if (tTd(38, 9))
- dprintf("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, errstring(errno));
+ sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
+ map->map_mname, sm_errstring(errno));
map->map_mflags &= ~(MF_VALID|MF_OPEN);
*statp = EX_OSFILE;
return NULL;
@@ -6375,15 +6244,15 @@ prog_map_lookup(map, name, av, statp)
i = read(fd, buf, sizeof buf - 1);
if (i < 0)
{
- syserr("prog_map_lookup(%s): read error %s\n",
- map->map_mname, errstring(errno));
+ syserr("prog_map_lookup(%s): read error %s",
+ map->map_mname, sm_errstring(errno));
rval = NULL;
}
else if (i == 0)
{
if (tTd(38, 20))
- dprintf("prog_map_lookup(%s): empty answer\n",
- map->map_mname);
+ sm_dprintf("prog_map_lookup(%s): empty answer\n",
+ map->map_mname);
rval = NULL;
}
else
@@ -6408,13 +6277,13 @@ prog_map_lookup(map, name, av, statp)
(void) close(fd);
status = waitfor(pid);
save_errno = errno;
- (void) releasesignal(SIGCHLD);
+ (void) sm_releasesignal(SIGCHLD);
errno = save_errno;
if (status == -1)
{
- syserr("prog_map_lookup(%s): wait error %s\n",
- map->map_mname, errstring(errno));
+ syserr("prog_map_lookup(%s): wait error %s",
+ map->map_mname, sm_errstring(errno));
*statp = EX_SOFTWARE;
rval = NULL;
}
@@ -6426,13 +6295,13 @@ prog_map_lookup(map, name, av, statp)
else
{
syserr("prog_map_lookup(%s): child died on signal %d",
- map->map_mname, status);
+ map->map_mname, status);
*statp = EX_UNAVAILABLE;
rval = NULL;
}
return rval;
}
- /*
+/*
** Sequenced map type.
**
** Tries each map in order until something matches, much like
@@ -6446,7 +6315,7 @@ prog_map_lookup(map, name, av, statp)
** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
**
** We don't need an explicit open, since all maps are
-** opened during startup, including underlying maps.
+** opened on demand.
*/
/*
@@ -6461,7 +6330,7 @@ seq_map_parse(map, ap)
int maxmap;
if (tTd(38, 2))
- dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
+ sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
maxmap = 0;
while (*ap != '\0')
{
@@ -6490,7 +6359,7 @@ seq_map_parse(map, ap)
syserr("Sequence map %s: unknown member map %s",
map->map_mname, ap);
}
- else if (maxmap == MAXMAPSTACK)
+ else if (maxmap >= MAXMAPSTACK)
{
syserr("Sequence map %s: too many member maps (%d max)",
map->map_mname, MAXMAPSTACK);
@@ -6502,10 +6371,9 @@ seq_map_parse(map, ap)
}
ap = p;
}
- return TRUE;
+ return true;
}
-
/*
** SWITCH_MAP_OPEN -- open a switched map
**
@@ -6527,19 +6395,19 @@ switch_map_open(map, mode)
char *maptype[MAXMAPSTACK];
if (tTd(38, 2))
- dprintf("switch_map_open(%s, %s, %d)\n",
+ sm_dprintf("switch_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
mode &= O_ACCMODE;
nmaps = switch_map_find(map->map_file, maptype, map->map_return);
if (tTd(38, 19))
{
- dprintf("\tswitch_map_find => %d\n", nmaps);
+ sm_dprintf("\tswitch_map_find => %d\n", nmaps);
for (mapno = 0; mapno < nmaps; mapno++)
- dprintf("\t\t%s\n", maptype[mapno]);
+ sm_dprintf("\t\t%s\n", maptype[mapno]);
}
if (nmaps <= 0 || nmaps > MAXMAPSTACK)
- return FALSE;
+ return false;
for (mapno = 0; mapno < nmaps; mapno++)
{
@@ -6548,8 +6416,8 @@ switch_map_open(map, mode)
if (maptype[mapno] == NULL)
continue;
- (void) snprintf(nbuf, sizeof nbuf, "%s.%s",
- map->map_mname, maptype[mapno]);
+ (void) sm_strlcpyn(nbuf, sizeof nbuf, 3,
+ map->map_mname, ".", maptype[mapno]);
s = stab(nbuf, ST_MAP, ST_FIND);
if (s == NULL)
{
@@ -6560,15 +6428,16 @@ switch_map_open(map, mode)
{
map->map_stack[mapno] = &s->s_map;
if (tTd(38, 4))
- dprintf("\tmap_stack[%d] = %s:%s\n",
- mapno, s->s_map.map_class->map_cname,
- nbuf);
+ sm_dprintf("\tmap_stack[%d] = %s:%s\n",
+ mapno,
+ s->s_map.map_class->map_cname,
+ nbuf);
}
}
- return TRUE;
+ return true;
}
-
+#if 0
/*
** SEQ_MAP_CLOSE -- close all underlying maps
*/
@@ -6580,7 +6449,7 @@ seq_map_close(map)
int mapno;
if (tTd(38, 9))
- dprintf("seq_map_close(%s)\n", map->map_mname);
+ sm_dprintf("seq_map_close(%s)\n", map->map_mname);
for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
{
@@ -6593,7 +6462,7 @@ seq_map_close(map)
mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
}
}
-
+#endif /* 0 */
/*
** SEQ_MAP_LOOKUP -- sequenced map lookup
@@ -6608,10 +6477,10 @@ seq_map_lookup(map, key, args, pstat)
{
int mapno;
int mapbit = 0x01;
- bool tempfail = FALSE;
+ bool tempfail = false;
if (tTd(38, 20))
- dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
+ sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
{
@@ -6638,7 +6507,7 @@ seq_map_lookup(map, key, args, pstat)
{
if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
return NULL;
- tempfail = TRUE;
+ tempfail = true;
}
else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
break;
@@ -6650,7 +6519,6 @@ seq_map_lookup(map, key, args, pstat)
return NULL;
}
-
/*
** SEQ_MAP_STORE -- sequenced map store
*/
@@ -6664,7 +6532,7 @@ seq_map_store(map, key, val)
int mapno;
if (tTd(38, 12))
- dprintf("seq_map_store(%s, %s, %s)\n",
+ sm_dprintf("seq_map_store(%s, %s, %s)\n",
map->map_mname, key, val);
for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
@@ -6680,7 +6548,7 @@ seq_map_store(map, key, val)
syserr("seq_map_store(%s, %s, %s): no writable map",
map->map_mname, key, val);
}
- /*
+/*
** NULL stubs
*/
@@ -6690,7 +6558,7 @@ null_map_open(map, mode)
MAP *map;
int mode;
{
- return TRUE;
+ return true;
}
/* ARGSUSED */
@@ -6722,7 +6590,6 @@ null_map_store(map, key, val)
return;
}
-
/*
** BOGUS stubs
*/
@@ -6740,11 +6607,11 @@ bogus_map_lookup(map, key, args, pstat)
MAPCLASS BogusMapClass =
{
- "bogus-map", NULL, 0,
- NULL, bogus_map_lookup, null_map_store,
- null_map_open, null_map_close,
+ "bogus-map", NULL, 0,
+ NULL, bogus_map_lookup, null_map_store,
+ null_map_open, null_map_close,
};
- /*
+/*
** MACRO modules
*/
@@ -6758,37 +6625,35 @@ macro_map_lookup(map, name, av, statp)
int mid;
if (tTd(38, 20))
- dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
+ sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
name == NULL ? "NULL" : name);
if (name == NULL ||
*name == '\0' ||
- (mid = macid(name, NULL)) == '\0')
+ (mid = macid(name)) == 0)
{
*statp = EX_CONFIG;
return NULL;
}
if (av[1] == NULL)
- define(mid, NULL, CurEnv);
+ macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
else
- define(mid, newstr(av[1]), CurEnv);
+ macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
*statp = EX_OK;
return "";
}
- /*
+/*
** REGEX modules
*/
-#ifdef MAP_REGEX
+#if MAP_REGEX
# include <regex.h>
# define DEFAULT_DELIM CONDELSE
-
# define END_OF_FIELDS -1
-
# define ERRBUF_SIZE 80
# define MAX_MATCH 32
@@ -6810,7 +6675,7 @@ parse_fields(s, ibuf, blen, nr_substrings)
{
register char *cp;
int i = 0;
- bool lastone = FALSE;
+ bool lastone = false;
blen--; /* for terminating END_OF_FIELDS */
cp = s;
@@ -6825,7 +6690,7 @@ parse_fields(s, ibuf, blen, nr_substrings)
}
if (*cp == '\0')
{
- lastone = TRUE;
+ lastone = true;
break;
}
}
@@ -6843,7 +6708,7 @@ parse_fields(s, ibuf, blen, nr_substrings)
}
else
{
- syserr("too many fields, %d max\n", blen);
+ syserr("too many fields, %d max", blen);
return -1;
}
s = ++cp;
@@ -6862,16 +6727,14 @@ regex_map_init(map, ap)
register char *p;
char *sub_param = NULL;
int pflags;
- static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
+ static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
if (tTd(38, 2))
- dprintf("regex_map_init: mapname '%s', args '%s'\n",
+ sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
map->map_mname, ap);
pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
-
p = ap;
-
map_p = (struct regex_map *) xnalloc(sizeof *map_p);
map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
@@ -6928,7 +6791,7 @@ regex_map_init(map, ap)
*p++ = '\0';
}
if (tTd(38, 3))
- dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
+ sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
{
@@ -6936,11 +6799,11 @@ regex_map_init(map, ap)
char errbuf[ERRBUF_SIZE];
(void) regerror(regerr, map_p->regex_pattern_buf,
- errbuf, ERRBUF_SIZE);
- syserr("pattern-compile-error: %s\n", errbuf);
- sm_free(map_p->regex_pattern_buf);
- sm_free(map_p);
- return FALSE;
+ errbuf, sizeof errbuf);
+ syserr("pattern-compile-error: %s", errbuf);
+ sm_free(map_p->regex_pattern_buf); /* XXX */
+ sm_free(map_p); /* XXX */
+ return false;
}
if (map->map_app != NULL)
@@ -6959,28 +6822,28 @@ regex_map_init(map, ap)
substrings = map_p->regex_pattern_buf->re_nsub + 1;
if (tTd(38, 3))
- dprintf("regex_map_init: nr of substrings %d\n",
+ sm_dprintf("regex_map_init: nr of substrings %d\n",
substrings);
if (substrings >= MAX_MATCH)
{
- syserr("too many substrings, %d max\n", MAX_MATCH);
- sm_free(map_p->regex_pattern_buf);
- sm_free(map_p);
- return FALSE;
+ syserr("too many substrings, %d max", MAX_MATCH);
+ sm_free(map_p->regex_pattern_buf); /* XXX */
+ sm_free(map_p); /* XXX */
+ return false;
}
if (sub_param != NULL && sub_param[0] != '\0')
{
/* optional parameter -sfields */
if (parse_fields(sub_param, fields,
MAX_MATCH + 1, substrings) == -1)
- return FALSE;
+ return false;
}
else
{
- /* set default fields */
int i;
+ /* set default fields */
for (i = 0; i < substrings; i++)
fields[i] = i;
fields[i] = END_OF_FIELDS;
@@ -6990,15 +6853,14 @@ regex_map_init(map, ap)
{
int *ip;
- dprintf("regex_map_init: subfields");
+ sm_dprintf("regex_map_init: subfields");
for (ip = fields; *ip != END_OF_FIELDS; ip++)
- dprintf(" %d", *ip);
- dprintf("\n");
+ sm_dprintf(" %d", *ip);
+ sm_dprintf("\n");
}
}
- map->map_db1 = (ARBPTR_T)map_p; /* dirty hack */
-
- return TRUE;
+ map->map_db1 = (ARBPTR_T) map_p; /* dirty hack */
+ return true;
}
static char *
@@ -7029,9 +6891,9 @@ regex_map_lookup(map, name, av, statp)
{
char **cpp;
- dprintf("regex_map_lookup: key '%s'\n", name);
+ sm_dprintf("regex_map_lookup: key '%s'\n", name);
for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
- dprintf("regex_map_lookup: arg '%s'\n", *cpp);
+ sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
}
map_p = (struct regex_map *)(map->map_db1);
@@ -7042,7 +6904,7 @@ regex_map_lookup(map, name, av, statp)
{
/* option -n */
if (reg_res == REG_NOMATCH)
- return regex_map_rewrite(map, "", (size_t)0, av);
+ return regex_map_rewrite(map, "", (size_t) 0, av);
else
return NULL;
}
@@ -7054,9 +6916,9 @@ regex_map_lookup(map, name, av, statp)
/* option -s */
static char retbuf[MAXNAME];
int fields[MAX_MATCH + 1];
- bool first = TRUE;
+ bool first = true;
int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
- bool quotemode = FALSE, bslashmode = FALSE;
+ bool quotemode = false, bslashmode = false;
register char *dp, *sp;
char *endp, *ldp;
int *ip;
@@ -7088,8 +6950,7 @@ regex_map_lookup(map, name, av, statp)
}
}
else
- first = FALSE;
-
+ first = false;
if (*ip >= MAX_MATCH ||
pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
@@ -7104,40 +6965,40 @@ regex_map_lookup(map, name, av, statp)
if (bslashmode)
{
*dp++ = *sp;
- bslashmode = FALSE;
+ bslashmode = false;
}
else if (quotemode && *sp != '"' &&
*sp != '\\')
{
*dp++ = *sp;
}
- else switch(*dp++ = *sp)
+ else switch (*dp++ = *sp)
{
- case '\\':
- bslashmode = TRUE;
+ case '\\':
+ bslashmode = true;
break;
- case '(':
+ case '(':
cmntcnt++;
break;
- case ')':
+ case ')':
cmntcnt--;
break;
- case '<':
+ case '<':
anglecnt++;
break;
- case '>':
+ case '>':
anglecnt--;
break;
- case ' ':
+ case ' ':
spacecnt++;
break;
- case '"':
+ case '"':
quotemode = !quotemode;
break;
}
@@ -7160,10 +7021,10 @@ regex_map_lookup(map, name, av, statp)
return regex_map_rewrite(map, "", (size_t)0, av);
}
#endif /* MAP_REGEX */
- /*
+/*
** NSD modules
*/
-#ifdef MAP_NSD
+#if MAP_NSD
# include <ndbm.h>
# define _DATUM_DEFINED
@@ -7171,9 +7032,9 @@ regex_map_lookup(map, name, av, statp)
typedef struct ns_map_list
{
- ns_map_t *map;
- char *mapname;
- struct ns_map_list *next;
+ ns_map_t *map; /* XXX ns_ ? */
+ char *mapname;
+ struct ns_map_list *next;
} ns_map_list_t;
static ns_map_t *
@@ -7216,11 +7077,11 @@ nsd_map_lookup(map, name, av, statp)
char buf[MAXLINE];
if (tTd(38, 20))
- dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
+ sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
buflen = strlen(name);
if (buflen > sizeof keybuf - 1)
- buflen = sizeof keybuf - 1;
+ buflen = sizeof keybuf - 1; /* XXX simply cut off? */
memmove(keybuf, name, buflen);
keybuf[buflen] = '\0';
if (!bitset(MF_NOFOLDCASE, map->map_mflags))
@@ -7230,7 +7091,7 @@ nsd_map_lookup(map, name, av, statp)
if (ns_map == NULL)
{
if (tTd(38, 20))
- dprintf("nsd_map_t_find failed\n");
+ sm_dprintf("nsd_map_t_find failed\n");
*statp = EX_UNAVAILABLE;
return NULL;
}
@@ -7274,19 +7135,19 @@ arith_map_lookup(map, name, av, statp)
{
long r;
long v[2];
- bool res = FALSE;
+ bool res = false;
bool boolres;
static char result[16];
char **cpp;
if (tTd(38, 2))
{
- dprintf("arith_map_lookup: key '%s'\n", name);
+ sm_dprintf("arith_map_lookup: key '%s'\n", name);
for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
- dprintf("arith_map_lookup: arg '%s'\n", *cpp);
+ sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
}
r = 0;
- boolres = FALSE;
+ boolres = false;
cpp = av;
*statp = EX_OK;
@@ -7295,15 +7156,15 @@ arith_map_lookup(map, name, av, statp)
** - no check is made whether they are really numbers
** - just ignores args after the second
*/
+
for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
v[r++] = strtol(*cpp, NULL, 0);
/* operator and (at least) two operands given? */
if (name != NULL && r == 2)
{
- switch(*name)
+ switch (*name)
{
-#if _FFR_ARITH
case '|':
r = v[0] | v[1];
break;
@@ -7317,8 +7178,6 @@ arith_map_lookup(map, name, av, statp)
return NULL;
r = v[0] % v[1];
break;
-#endif /* _FFR_ARITH */
-
case '+':
r = v[0] + v[1];
break;
@@ -7339,12 +7198,12 @@ arith_map_lookup(map, name, av, statp)
case 'l':
res = v[0] < v[1];
- boolres = TRUE;
+ boolres = true;
break;
case '=':
res = v[0] == v[1];
- boolres = TRUE;
+ boolres = true;
break;
default:
@@ -7357,9 +7216,10 @@ arith_map_lookup(map, name, av, statp)
return NULL;
}
if (boolres)
- snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
+ (void) sm_snprintf(result, sizeof result,
+ res ? "TRUE" : "FALSE");
else
- snprintf(result, sizeof result, "%ld", r);
+ (void) sm_snprintf(result, sizeof result, "%ld", r);
return result;
}
*statp = EX_CONFIG;
diff --git a/contrib/sendmail/src/mci.c b/contrib/sendmail/src/mci.c
index 198a18b..ce9422c 100644
--- a/contrib/sendmail/src/mci.c
+++ b/contrib/sendmail/src/mci.c
@@ -11,12 +11,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: mci.c,v 8.133.10.8 2001/05/03 17:24:10 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: mci.c,v 8.202 2001/11/05 22:12:17 ca Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
@@ -29,7 +26,7 @@ static int mci_generate_persistent_path __P((const char *, char *,
static bool mci_load_persistent __P((MCI *));
static void mci_uncache __P((MCI **, bool));
static int mci_lock_host_statfile __P((MCI *));
-static int mci_read_persistent __P((FILE *, MCI *));
+static int mci_read_persistent __P((SM_FILE_T *, MCI *));
/*
** Mail Connection Information (MCI) Caching Module.
@@ -64,7 +61,7 @@ static int mci_read_persistent __P((FILE *, MCI *));
static MCI **MciCache; /* the open connection cache */
- /*
+/*
** MCI_CACHE -- enter a connection structure into the open connection cache
**
** This may cause something else to be flushed.
@@ -103,21 +100,21 @@ mci_cache(mci)
/* otherwise we may have to clear the slot */
if (*mcislot != NULL)
- mci_uncache(mcislot, TRUE);
+ mci_uncache(mcislot, true);
if (tTd(42, 5))
- dprintf("mci_cache: caching %lx (%s) in slot %d\n",
- (u_long) mci, mci->mci_host,
- (int)(mcislot - MciCache));
+ sm_dprintf("mci_cache: caching %p (%s) in slot %d\n",
+ mci, mci->mci_host, (int) (mcislot - MciCache));
if (tTd(91, 100))
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"mci_cache: caching %lx (%.100s) in slot %d",
- (u_long) mci, mci->mci_host, mcislot - MciCache);
+ (unsigned long) mci, mci->mci_host,
+ (int) (mcislot - MciCache));
*mcislot = mci;
mci->mci_flags |= MCIF_CACHED;
}
- /*
+/*
** MCI_SCAN -- scan the cache, flush junk, and return best slot
**
** Parameters:
@@ -145,7 +142,7 @@ mci_scan(savemci)
if (MciCache == NULL)
{
/* first call */
- MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
+ MciCache = (MCI **) sm_pmalloc_x(MaxMciCache * sizeof *MciCache);
memset((char *) MciCache, '\0', MaxMciCache * sizeof *MciCache);
return &MciCache[0];
}
@@ -170,7 +167,7 @@ mci_scan(savemci)
bestmci = &MciCache[i];
/* close it */
- mci_uncache(bestmci, TRUE);
+ mci_uncache(bestmci, true);
continue;
}
if (*bestmci == NULL)
@@ -180,15 +177,15 @@ mci_scan(savemci)
}
return bestmci;
}
- /*
+/*
** MCI_UNCACHE -- remove a connection from a slot.
**
** May close a connection.
**
** Parameters:
** mcislot -- the slot to empty.
-** doquit -- if TRUE, send QUIT protocol on this connection.
-** if FALSE, we are assumed to be in a forked child;
+** doquit -- if true, send QUIT protocol on this connection.
+** if false, we are assumed to be in a forked child;
** all we want to do is close the file(s).
**
** Returns:
@@ -213,17 +210,16 @@ mci_uncache(mcislot, doquit)
mci_unlock_host(mci);
if (tTd(42, 5))
- dprintf("mci_uncache: uncaching %lx (%s) from slot %d (%d)\n",
- (u_long) mci, mci->mci_host,
- (int)(mcislot - MciCache), doquit);
+ sm_dprintf("mci_uncache: uncaching %p (%s) from slot %d (%d)\n",
+ mci, mci->mci_host, (int) (mcislot - MciCache),
+ doquit);
if (tTd(91, 100))
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"mci_uncache: uncaching %lx (%.100s) from slot %d (%d)",
- (u_long) mci, mci->mci_host,
- mcislot - MciCache, doquit);
+ (unsigned long) mci, mci->mci_host,
+ (int) (mcislot - MciCache), doquit);
mci->mci_deliveries = 0;
-#if SMTP
if (doquit)
{
message("Closing connection to %s", mci->mci_host);
@@ -233,30 +229,45 @@ mci_uncache(mcislot, doquit)
/* only uses the envelope to flush the transcript file */
if (mci->mci_state != MCIS_CLOSED)
smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
-# ifdef XLA
+#if XLA
xla_host_end(mci->mci_host);
-# endif /* XLA */
+#endif /* XLA */
}
else
-#endif /* SMTP */
{
if (mci->mci_in != NULL)
- (void) fclose(mci->mci_in);
+ (void) sm_io_close(mci->mci_in, SM_TIME_DEFAULT);
if (mci->mci_out != NULL)
- (void) fclose(mci->mci_out);
+ (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
mci->mci_in = mci->mci_out = NULL;
mci->mci_state = MCIS_CLOSED;
mci->mci_exitstat = EX_OK;
mci->mci_errno = 0;
mci->mci_flags = 0;
+
+ mci->mci_retryrcpt = false;
+ mci->mci_tolist = NULL;
+#if PIPELINING
+ mci->mci_okrcpts = 0;
+#endif /* PIPELINING */
+ }
+
+ SM_FREE_CLR(mci->mci_status);
+ SM_FREE_CLR(mci->mci_rstatus);
+ SM_FREE_CLR(mci->mci_heloname);
+ if (mci->mci_rpool != NULL)
+ {
+ sm_rpool_free(mci->mci_rpool);
+ mci->mci_macro.mac_rpool = NULL;
+ mci->mci_rpool = NULL;
}
}
- /*
+/*
** MCI_FLUSH -- flush the entire cache
**
** Parameters:
-** doquit -- if TRUE, send QUIT protocol.
-** if FALSE, just close the connection.
+** doquit -- if true, send QUIT protocol.
+** if false, just close the connection.
** allbut -- but leave this one open.
**
** Returns:
@@ -279,8 +290,15 @@ mci_flush(doquit, allbut)
mci_uncache(&MciCache[i], doquit);
}
}
- /*
+/*
** MCI_GET -- get information about a particular host
+**
+** Parameters:
+** host -- host to look for.
+** m -- mailer.
+**
+** Returns:
+** mci for this host (might be new).
*/
MCI *
@@ -290,13 +308,10 @@ mci_get(host, m)
{
register MCI *mci;
register STAB *s;
-
-#if DAEMON
extern SOCKADDR CurHostAddr;
/* clear CurHostAddr so we don't get a bogus address with this name */
memset(&CurHostAddr, '\0', sizeof CurHostAddr);
-#endif /* DAEMON */
/* clear out any expired connections */
(void) mci_scan(NULL);
@@ -307,8 +322,21 @@ mci_get(host, m)
s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
mci = &s->s_mci;
+ /* initialize per-message data */
+ mci->mci_retryrcpt = false;
+ mci->mci_tolist = NULL;
+#if PIPELINING
+ mci->mci_okrcpts = 0;
+#endif /* PIPELINING */
+
+ if (mci->mci_rpool == NULL)
+ mci->mci_rpool = sm_rpool_new_x(NULL);
+
+ if (mci->mci_macro.mac_rpool == NULL)
+ mci->mci_macro.mac_rpool = mci->mci_rpool;
+
/*
- ** We don't need to load the peristent data if we have data
+ ** We don't need to load the persistent data if we have data
** already loaded in the cache.
*/
@@ -317,7 +345,7 @@ mci_get(host, m)
!mci_load_persistent(mci))
{
if (tTd(42, 2))
- dprintf("mci_get(%s %s): lock failed\n",
+ sm_dprintf("mci_get(%s %s): lock failed\n",
host, m->m_name);
mci->mci_exitstat = EX_TEMPFAIL;
mci->mci_state = MCIS_CLOSED;
@@ -327,12 +355,11 @@ mci_get(host, m)
if (tTd(42, 2))
{
- dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n",
+ sm_dprintf("mci_get(%s %s): mci_state=%d, _flags=%lx, _exitstat=%d, _errno=%d\n",
host, m->m_name, mci->mci_state, mci->mci_flags,
mci->mci_exitstat, mci->mci_errno);
}
-#if SMTP
if (mci->mci_state == MCIS_OPEN)
{
/* poke the connection to see if it's still alive */
@@ -345,19 +372,17 @@ mci_get(host, m)
mci->mci_exitstat = EX_OK;
mci->mci_state = MCIS_CLOSED;
}
-# if DAEMON
else
{
- /* get peer host address for logging reasons only */
+ /* get peer host address */
/* (this should really be in the mci struct) */
SOCKADDR_LEN_T socklen = sizeof CurHostAddr;
- (void) getpeername(fileno(mci->mci_in),
+ (void) getpeername(sm_io_getinfo(mci->mci_in,
+ SM_IO_WHAT_FD, NULL),
(struct sockaddr *) &CurHostAddr, &socklen);
}
-# endif /* DAEMON */
}
-#endif /* SMTP */
if (mci->mci_state == MCIS_CLOSED)
{
time_t now = curtime();
@@ -373,8 +398,40 @@ mci_get(host, m)
return mci;
}
- /*
+/*
+** MCI_NEW -- allocate new MCI structure
+**
+** Parameters:
+** rpool -- if non-NULL: allocate from that rpool.
+**
+** Returns:
+** mci (new).
+*/
+
+MCI *
+mci_new(rpool)
+ SM_RPOOL_T *rpool;
+{
+ register MCI *mci;
+
+ if (rpool == NULL)
+ mci = (MCI *) sm_malloc_x(sizeof *mci);
+ else
+ mci = (MCI *) sm_rpool_malloc_x(rpool, sizeof *mci);
+ memset((char *) mci, '\0', sizeof *mci);
+ mci->mci_rpool = sm_rpool_new_x(NULL);
+ mci->mci_macro.mac_rpool = mci->mci_rpool;
+ return mci;
+}
+/*
** MCI_MATCH -- check connection cache for a particular host
+**
+** Parameters:
+** host -- host to look for.
+** m -- mailer.
+**
+** Returns:
+** true iff open connection exists.
*/
bool
@@ -386,17 +443,15 @@ mci_match(host, m)
register STAB *s;
if (m->m_mno < 0 || m->m_mno > MAXMAILERS)
- return FALSE;
+ return false;
s = stab(host, ST_MCI + m->m_mno, ST_FIND);
if (s == NULL)
- return FALSE;
+ return false;
mci = &s->s_mci;
- if (mci->mci_state == MCIS_OPEN)
- return TRUE;
- return FALSE;
+ return mci->mci_state == MCIS_OPEN;
}
- /*
+/*
** MCI_SETSTAT -- set status codes in MCI structure.
**
** Parameters:
@@ -420,14 +475,15 @@ mci_setstat(mci, xstat, dstat, rstat)
if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
mci->mci_exitstat = xstat;
- mci->mci_status = dstat;
- if (mci->mci_rstatus != NULL)
- sm_free(mci->mci_rstatus);
+ SM_FREE_CLR(mci->mci_status);
+ if (dstat != NULL)
+ mci->mci_status = sm_strdup_x(dstat);
+
+ SM_FREE_CLR(mci->mci_rstatus);
if (rstat != NULL)
- rstat = newstr(rstat);
- mci->mci_rstatus = rstat;
+ mci->mci_rstatus = sm_strdup_x(rstat);
}
- /*
+/*
** MCI_DUMP -- dump the contents of an MCI structure.
**
** Parameters:
@@ -448,7 +504,6 @@ struct mcifbits
static struct mcifbits MciFlags[] =
{
{ MCIF_VALID, "VALID" },
- { MCIF_TEMP, "TEMP" },
{ MCIF_CACHED, "CACHED" },
{ MCIF_ESMTP, "ESMTP" },
{ MCIF_EXPN, "EXPN" },
@@ -462,10 +517,18 @@ static struct mcifbits MciFlags[] =
{ MCIF_8BITOK, "8BITOK" },
{ MCIF_CVT7TO8, "CVT7TO8" },
{ MCIF_INMIME, "INMIME" },
+ { MCIF_AUTH, "AUTH" },
+ { MCIF_AUTHACT, "AUTHACT" },
+ { MCIF_ENHSTAT, "ENHSTAT" },
+ { MCIF_PIPELINED, "PIPELINED" },
+#if STARTTLS
+ { MCIF_TLS, "TLS" },
+ { MCIF_TLSACT, "TLSACT" },
+#endif /* STARTTLS */
+ { MCIF_DLVR_BY, "DLVR_BY" },
{ 0, NULL }
};
-
void
mci_dump(mci, logit)
register MCI *mci;
@@ -477,14 +540,14 @@ mci_dump(mci, logit)
sep = logit ? " " : "\n\t";
p = buf;
- snprintf(p, SPACELEFT(buf, p), "MCI@%lx: ", (u_long) mci);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "MCI@%p: ", mci);
p += strlen(p);
if (mci == NULL)
{
- snprintf(p, SPACELEFT(buf, p), "NULL");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "NULL");
goto printit;
}
- snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "flags=%lx", mci->mci_flags);
p += strlen(p);
if (mci->mci_flags != 0)
{
@@ -495,40 +558,39 @@ mci_dump(mci, logit)
{
if (!bitset(f->mcif_bit, mci->mci_flags))
continue;
- snprintf(p, SPACELEFT(buf, p), "%s,", f->mcif_name);
+ (void) sm_strlcpyn(p, SPACELEFT(buf, p), 2,
+ f->mcif_name, ",");
p += strlen(p);
}
p[-1] = '>';
}
- snprintf(p, SPACELEFT(buf, p),
+
+ /* Note: sm_snprintf() takes care of NULL arguments for %s */
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
sep, mci->mci_errno, mci->mci_herrno,
mci->mci_exitstat, mci->mci_state, (int) mci->mci_pid, sep);
p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
"maxsize=%ld, phase=%s, mailer=%s,%s",
- mci->mci_maxsize,
- mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
+ mci->mci_maxsize, mci->mci_phase,
mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
sep);
p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
"status=%s, rstatus=%s,%s",
- mci->mci_status == NULL ? "NULL" : mci->mci_status,
- mci->mci_rstatus == NULL ? "NULL" : mci->mci_rstatus,
- sep);
+ mci->mci_status, mci->mci_rstatus, sep);
p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
"host=%s, lastuse=%s",
- mci->mci_host == NULL ? "NULL" : mci->mci_host,
- ctime(&mci->mci_lastuse));
+ mci->mci_host, ctime(&mci->mci_lastuse));
printit:
if (logit)
sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
else
- printf("%s\n", buf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", buf);
}
- /*
+/*
** MCI_DUMP_ALL -- print the entire MCI cache
**
** Parameters:
@@ -551,7 +613,7 @@ mci_dump_all(logit)
for (i = 0; i < MaxMciCache; i++)
mci_dump(MciCache[i], logit);
}
- /*
+/*
** MCI_LOCK_HOST -- Lock host while sending.
**
** If we are contacting a host, we'll need to
@@ -559,7 +621,7 @@ mci_dump_all(logit)
** file, and if we want to do that, we ought to have
** locked it. This has the (according to some)
** desirable effect of serializing connectivity with
-** remote hosts -- i.e.: one connection to a give
+** remote hosts -- i.e.: one connection to a given
** host at a time.
**
** Parameters:
@@ -577,7 +639,7 @@ mci_lock_host(mci)
if (mci == NULL)
{
if (tTd(56, 1))
- dprintf("mci_lock_host: NULL mci\n");
+ sm_dprintf("mci_lock_host: NULL mci\n");
return EX_OK;
}
@@ -599,15 +661,16 @@ mci_lock_host_statfile(mci)
return EX_OK;
if (tTd(56, 2))
- dprintf("mci_lock_host: attempting to lock %s\n",
- mci->mci_host);
+ sm_dprintf("mci_lock_host: attempting to lock %s\n",
+ mci->mci_host);
- if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, TRUE) < 0)
+ if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname,
+ true) < 0)
{
/* of course this should never happen */
if (tTd(56, 2))
- dprintf("mci_lock_host: Failed to generate host path for %s\n",
- mci->mci_host);
+ sm_dprintf("mci_lock_host: Failed to generate host path for %s\n",
+ mci->mci_host);
retVal = EX_TEMPFAIL;
goto cleanup;
@@ -618,30 +681,30 @@ mci_lock_host_statfile(mci)
if (mci->mci_statfile == NULL)
{
- syserr("mci_lock_host: cannot create host lock file %s",
- fname);
+ syserr("mci_lock_host: cannot create host lock file %s", fname);
goto cleanup;
}
- if (!lockfile(fileno(mci->mci_statfile), fname, "", LOCK_EX|LOCK_NB))
+ if (!lockfile(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
+ fname, "", LOCK_EX|LOCK_NB))
{
if (tTd(56, 2))
- dprintf("mci_lock_host: couldn't get lock on %s\n",
+ sm_dprintf("mci_lock_host: couldn't get lock on %s\n",
fname);
- (void) fclose(mci->mci_statfile);
+ (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
mci->mci_statfile = NULL;
retVal = EX_TEMPFAIL;
goto cleanup;
}
if (tTd(56, 12) && mci->mci_statfile != NULL)
- dprintf("mci_lock_host: Sanity check -- lock is good\n");
+ sm_dprintf("mci_lock_host: Sanity check -- lock is good\n");
cleanup:
errno = save_errno;
return retVal;
}
- /*
+/*
** MCI_UNLOCK_HOST -- unlock host
**
** Clean up the lock on a host, close the file, let
@@ -663,7 +726,7 @@ mci_unlock_host(mci)
if (mci == NULL)
{
if (tTd(56, 1))
- dprintf("mci_unlock_host: NULL mci\n");
+ sm_dprintf("mci_unlock_host: NULL mci\n");
return;
}
@@ -673,37 +736,35 @@ mci_unlock_host(mci)
if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
{
if (tTd(56, 1))
- dprintf("mci_unlock_host: stat file already locked\n");
+ sm_dprintf("mci_unlock_host: stat file already locked\n");
}
else
{
if (tTd(56, 2))
- dprintf("mci_unlock_host: store prior to unlock\n");
-
+ sm_dprintf("mci_unlock_host: store prior to unlock\n");
mci_store_persistent(mci);
}
if (mci->mci_statfile != NULL)
{
- (void) fclose(mci->mci_statfile);
+ (void) sm_io_close(mci->mci_statfile, SM_TIME_DEFAULT);
mci->mci_statfile = NULL;
}
errno = save_errno;
}
- /*
+/*
** MCI_LOAD_PERSISTENT -- load persistent host info
**
** Load information about host that is kept
** in common for all running sendmails.
**
** Parameters:
-** mci -- the host/connection to load persistent info
-** for.
+** mci -- the host/connection to load persistent info for.
**
** Returns:
-** TRUE -- lock was successful
-** FALSE -- lock failed
+** true -- lock was successful
+** false -- lock failed
*/
static bool
@@ -711,33 +772,34 @@ mci_load_persistent(mci)
MCI *mci;
{
int save_errno = errno;
- bool locked = TRUE;
- FILE *fp;
+ bool locked = true;
+ SM_FILE_T *fp;
char fname[MAXPATHLEN + 1];
if (mci == NULL)
{
if (tTd(56, 1))
- dprintf("mci_load_persistent: NULL mci\n");
- return TRUE;
+ sm_dprintf("mci_load_persistent: NULL mci\n");
+ return true;
}
if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
- return TRUE;
+ return true;
/* Already have the persistent information in memory */
if (SingleThreadDelivery && mci->mci_statfile != NULL)
- return TRUE;
+ return true;
if (tTd(56, 1))
- dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
- mci->mci_host);
+ sm_dprintf("mci_load_persistent: Attempting to load persistent information for %s\n",
+ mci->mci_host);
- if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, FALSE) < 0)
+ if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname,
+ false) < 0)
{
/* Not much we can do if the file isn't there... */
if (tTd(56, 1))
- dprintf("mci_load_persistent: Couldn't generate host path\n");
+ sm_dprintf("mci_load_persistent: Couldn't generate host path\n");
goto cleanup;
}
@@ -747,26 +809,28 @@ mci_load_persistent(mci)
{
/* I can't think of any reason this should ever happen */
if (tTd(56, 1))
- dprintf("mci_load_persistent: open(%s): %s\n",
- fname, errstring(errno));
+ sm_dprintf("mci_load_persistent: open(%s): %s\n",
+ fname, sm_errstring(errno));
goto cleanup;
}
FileName = fname;
- locked = lockfile(fileno(fp), fname, "", LOCK_SH|LOCK_NB);
+ locked = lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname, "",
+ LOCK_SH|LOCK_NB);
if (locked)
{
(void) mci_read_persistent(fp, mci);
- (void) lockfile(fileno(fp), fname, "", LOCK_UN);
+ (void) lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), fname,
+ "", LOCK_UN);
}
FileName = NULL;
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
cleanup:
errno = save_errno;
return locked;
}
- /*
+/*
** MCI_READ_PERSISTENT -- read persistent host status file
**
** Parameters:
@@ -787,7 +851,7 @@ cleanup:
static int
mci_read_persistent(fp, mci)
- FILE *fp;
+ SM_FILE_T *fp;
register MCI *mci;
{
int ver;
@@ -801,19 +865,17 @@ mci_read_persistent(fp, mci)
syserr("mci_read_persistent: NULL mci");
if (tTd(56, 93))
{
- dprintf("mci_read_persistent: fp=%lx, mci=", (u_long) fp);
- mci_dump(mci, FALSE);
+ sm_dprintf("mci_read_persistent: fp=%lx, mci=",
+ (unsigned long) fp);
}
- mci->mci_status = NULL;
- if (mci->mci_rstatus != NULL)
- sm_free(mci->mci_rstatus);
- mci->mci_rstatus = NULL;
+ SM_FREE_CLR(mci->mci_status);
+ SM_FREE_CLR(mci->mci_rstatus);
- rewind(fp);
+ sm_io_rewind(fp, SM_TIME_DEFAULT);
ver = -1;
LineNumber = 0;
- while (fgets(buf, sizeof buf, fp) != NULL)
+ while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
LineNumber++;
p = strchr(buf, '\n');
@@ -853,6 +915,8 @@ mci_read_persistent(fp, mci)
break;
case '.': /* end of file */
+ if (tTd(56, 93))
+ mci_dump(mci, false);
return 0;
default:
@@ -865,11 +929,13 @@ mci_read_persistent(fp, mci)
}
}
LineNumber = saveLineNumber;
+ if (tTd(56, 93))
+ sm_dprintf("incomplete (missing dot for EOF)\n");
if (ver < 0)
return -1;
return 0;
}
- /*
+/*
** MCI_STORE_PERSISTENT -- Store persistent MCI information
**
** Store information about host that is kept
@@ -891,7 +957,7 @@ mci_store_persistent(mci)
if (mci == NULL)
{
if (tTd(56, 1))
- dprintf("mci_store_persistent: NULL mci\n");
+ sm_dprintf("mci_store_persistent: NULL mci\n");
return;
}
@@ -899,40 +965,47 @@ mci_store_persistent(mci)
return;
if (tTd(56, 1))
- dprintf("mci_store_persistent: Storing information for %s\n",
- mci->mci_host);
+ sm_dprintf("mci_store_persistent: Storing information for %s\n",
+ mci->mci_host);
if (mci->mci_statfile == NULL)
{
if (tTd(56, 1))
- dprintf("mci_store_persistent: no statfile\n");
+ sm_dprintf("mci_store_persistent: no statfile\n");
return;
}
- rewind(mci->mci_statfile);
+ sm_io_rewind(mci->mci_statfile, SM_TIME_DEFAULT);
#if !NOFTRUNCATE
- (void) ftruncate(fileno(mci->mci_statfile), (off_t) 0);
+ (void) ftruncate(sm_io_getinfo(mci->mci_statfile, SM_IO_WHAT_FD, NULL),
+ (off_t) 0);
#endif /* !NOFTRUNCATE */
- fprintf(mci->mci_statfile, "V0\n");
- fprintf(mci->mci_statfile, "E%d\n", mci->mci_errno);
- fprintf(mci->mci_statfile, "H%d\n", mci->mci_herrno);
- fprintf(mci->mci_statfile, "S%d\n", mci->mci_exitstat);
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "V0\n");
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "E%d\n",
+ mci->mci_errno);
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "H%d\n",
+ mci->mci_herrno);
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "S%d\n",
+ mci->mci_exitstat);
if (mci->mci_status != NULL)
- fprintf(mci->mci_statfile, "D%.80s\n",
- denlstring(mci->mci_status, TRUE, FALSE));
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
+ "D%.80s\n",
+ denlstring(mci->mci_status, true, false));
if (mci->mci_rstatus != NULL)
- fprintf(mci->mci_statfile, "R%.80s\n",
- denlstring(mci->mci_rstatus, TRUE, FALSE));
- fprintf(mci->mci_statfile, "U%ld\n", (long)(mci->mci_lastuse));
- fprintf(mci->mci_statfile, ".\n");
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT,
+ "R%.80s\n",
+ denlstring(mci->mci_rstatus, true, false));
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, "U%ld\n",
+ (long)(mci->mci_lastuse));
+ (void) sm_io_fprintf(mci->mci_statfile, SM_TIME_DEFAULT, ".\n");
- (void) fflush(mci->mci_statfile);
+ (void) sm_io_flush(mci->mci_statfile, SM_TIME_DEFAULT);
errno = save_errno;
return;
}
- /*
+/*
** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
**
** Recursively find all the mci host files in `pathname'. Default to
@@ -972,39 +1045,39 @@ mci_traverse_persistent(action, pathname)
return -1;
if (tTd(56, 1))
- dprintf("mci_traverse: pathname is %s\n", pathname);
+ sm_dprintf("mci_traverse: pathname is %s\n", pathname);
ret = stat(pathname, &statbuf);
if (ret < 0)
{
if (tTd(56, 2))
- dprintf("mci_traverse: Failed to stat %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_traverse: Failed to stat %s: %s\n",
+ pathname, sm_errstring(errno));
return ret;
}
if (S_ISDIR(statbuf.st_mode))
{
- struct dirent *e;
+ bool leftone, removedone;
+ size_t len;
char *newptr;
+ struct dirent *e;
char newpath[MAXPATHLEN + 1];
- bool leftone, removedone;
if ((d = opendir(pathname)) == NULL)
{
if (tTd(56, 2))
- dprintf("mci_traverse: opendir %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_traverse: opendir %s: %s\n",
+ pathname, sm_errstring(errno));
return -1;
}
-
- if (strlen(pathname) >= sizeof newpath - MAXNAMLEN - 3)
+ len = sizeof(newpath) - MAXNAMLEN - 3;
+ if (sm_strlcpy(newpath, pathname, len) >= len)
{
if (tTd(56, 2))
- dprintf("mci_traverse: path \"%s\" too long",
+ sm_dprintf("mci_traverse: path \"%s\" too long",
pathname);
return -1;
}
- (void) strlcpy(newpath, pathname, sizeof newpath);
newptr = newpath + strlen(newpath);
*newptr++ = '/';
@@ -1014,15 +1087,16 @@ mci_traverse_persistent(action, pathname)
** during these loops, but it's better than doing
** a rewinddir() inside the inner loop
*/
+
do
{
- leftone = removedone = FALSE;
+ leftone = removedone = false;
while ((e = readdir(d)) != NULL)
{
if (e->d_name[0] == '.')
continue;
- (void) strlcpy(newptr, e->d_name,
+ (void) sm_strlcpy(newptr, e->d_name,
sizeof newpath -
(newptr - newpath));
@@ -1032,22 +1106,24 @@ mci_traverse_persistent(action, pathname)
if (ret < 0)
break;
if (ret == 1)
- leftone = TRUE;
+ leftone = true;
if (!removedone && ret == 0 &&
action == mci_purge_persistent)
- removedone = TRUE;
+ removedone = true;
}
if (ret < 0)
break;
+
/*
** The following appears to be
** necessary during purges, since
** we modify the directory structure
*/
+
if (removedone)
rewinddir(d);
if (tTd(56, 40))
- dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
+ sm_dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
pathname, ret, removedone, leftone);
} while (removedone);
@@ -1095,12 +1171,13 @@ mci_traverse_persistent(action, pathname)
** Do something with the file containing the persistent
** information.
*/
+
ret = (*action)(pathname, host);
}
return ret;
}
- /*
+/*
** MCI_PRINT_PERSISTENT -- print persistent info
**
** Dump the persistent information in the file 'pathname'
@@ -1118,8 +1195,8 @@ mci_print_persistent(pathname, hostname)
char *pathname;
char *hostname;
{
- static int initflag = FALSE;
- FILE *fp;
+ static bool initflag = false;
+ SM_FILE_T *fp;
int width = Verbose ? 78 : 25;
bool locked;
MCI mcib;
@@ -1133,18 +1210,19 @@ mci_print_persistent(pathname, hostname)
if (!initflag)
{
- initflag = TRUE;
- printf(" -------------- Hostname --------------- How long ago ---------Results---------\n");
+ initflag = true;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " -------------- Hostname --------------- How long ago ---------Results---------\n");
}
- fp = safefopen(pathname, O_RDWR, FileMode,
+ fp = safefopen(pathname, O_RDONLY, FileMode,
SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
if (fp == NULL)
{
if (tTd(56, 1))
- dprintf("mci_print_persistent: cannot open %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_print_persistent: cannot open %s: %s\n",
+ pathname, sm_errstring(errno));
return 0;
}
@@ -1153,47 +1231,53 @@ mci_print_persistent(pathname, hostname)
if (mci_read_persistent(fp, &mcib) < 0)
{
syserr("%s: could not read status file", pathname);
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
FileName = NULL;
return 0;
}
- locked = !lockfile(fileno(fp), pathname, "", LOCK_EX|LOCK_NB);
- (void) fclose(fp);
+ locked = !lockfile(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), pathname,
+ "", LOCK_SH|LOCK_NB);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
FileName = NULL;
- printf("%c%-39s %12s ",
- locked ? '*' : ' ', hostname,
- pintvl(curtime() - mcib.mci_lastuse, TRUE));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%c%-39s %12s ",
+ locked ? '*' : ' ', hostname,
+ pintvl(curtime() - mcib.mci_lastuse, true));
if (mcib.mci_rstatus != NULL)
- printf("%.*s\n", width, mcib.mci_rstatus);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n", width,
+ mcib.mci_rstatus);
else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
- printf("Deferred: %.*s\n", width - 10, errstring(mcib.mci_errno));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Deferred: %.*s\n", width - 10,
+ sm_errstring(mcib.mci_errno));
else if (mcib.mci_exitstat != 0)
{
- int i = mcib.mci_exitstat - EX__BASE;
- extern int N_SysEx;
- extern char *SysExMsg[];
+ char *exmsg = sm_sysexmsg(mcib.mci_exitstat);
- if (i < 0 || i >= N_SysEx)
+ if (exmsg == NULL)
{
char buf[80];
- snprintf(buf, sizeof buf, "Unknown mailer error %d",
+ (void) sm_snprintf(buf, sizeof buf,
+ "Unknown mailer error %d",
mcib.mci_exitstat);
- printf("%.*s\n", width, buf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
+ width, buf);
}
else
- printf("%.*s\n", width, &(SysExMsg[i])[5]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%.*s\n",
+ width, &exmsg[5]);
}
else if (mcib.mci_errno == 0)
- printf("OK\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK\n");
else
- printf("OK: %.*s\n", width - 4, errstring(mcib.mci_errno));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK: %.*s\n",
+ width - 4, sm_errstring(mcib.mci_errno));
return 0;
}
- /*
+/*
** MCI_PURGE_PERSISTENT -- Remove a persistence status file.
**
** Parameters:
@@ -1217,14 +1301,14 @@ mci_purge_persistent(pathname, hostname)
int ret;
if (tTd(56, 1))
- dprintf("mci_purge_persistent: purging %s\n", pathname);
+ sm_dprintf("mci_purge_persistent: purging %s\n", pathname);
ret = stat(pathname, &statbuf);
if (ret < 0)
{
if (tTd(56, 2))
- dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
+ pathname, sm_errstring(errno));
return ret;
}
if (curtime() - statbuf.st_mtime < MciInfoTimeout)
@@ -1232,11 +1316,17 @@ mci_purge_persistent(pathname, hostname)
if (hostname != NULL)
{
/* remove the file */
- if (unlink(pathname) < 0)
+ ret = unlink(pathname);
+ if (ret < 0)
{
+ if (LogLevel > 8)
+ sm_syslog(LOG_ERR, NOQID,
+ "mci_purge_persistent: failed to unlink %s: %s",
+ pathname, sm_errstring(errno));
if (tTd(56, 2))
- dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
+ pathname, sm_errstring(errno));
+ return ret;
}
}
else
@@ -1246,20 +1336,21 @@ mci_purge_persistent(pathname, hostname)
return 1;
if (tTd(56, 1))
- dprintf("mci_purge_persistent: dpurge %s\n", pathname);
+ sm_dprintf("mci_purge_persistent: dpurge %s\n", pathname);
- if (rmdir(pathname) < 0)
+ ret = rmdir(pathname);
+ if (ret < 0)
{
if (tTd(56, 2))
- dprintf("mci_purge_persistent: rmdir %s: %s\n",
- pathname, errstring(errno));
+ sm_dprintf("mci_purge_persistent: rmdir %s: %s\n",
+ pathname, sm_errstring(errno));
+ return ret;
}
-
}
return 0;
}
- /*
+/*
** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
**
** Given `host', convert from a.b.c to $QueueDir/.hoststat/c./b./a,
@@ -1309,7 +1400,7 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
}
if (tTd(56, 80))
- dprintf("mci_generate_persistent_path(%s): ", host);
+ sm_dprintf("mci_generate_persistent_path(%s): ", host);
if (*host == '\0' || *host == '.')
return -1;
@@ -1318,9 +1409,9 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
if (strlen(host) > sizeof t_host - 1)
return -1;
if (host[0] == '[')
- (void) strlcpy(t_host, host + 1, sizeof t_host);
+ (void) sm_strlcpy(t_host, host + 1, sizeof t_host);
else
- (void) strlcpy(t_host, host, sizeof t_host);
+ (void) sm_strlcpy(t_host, host, sizeof t_host);
/*
** Delete any trailing dots from the hostname.
@@ -1332,18 +1423,21 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
(elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
*--elem = '\0';
-#if NETINET || NETINET6
/* check for bogus bracketed address */
- if (host[0] == '['
+ if (host[0] == '[')
+ {
+ bool good = false;
# if NETINET6
- && inet_pton(AF_INET6, t_host, &in6_addr) != 1
+ if (anynet_pton(AF_INET6, t_host, &in6_addr) == 1)
+ good = true;
# endif /* NETINET6 */
# if NETINET
- && inet_addr(t_host) == INADDR_NONE
+ if (inet_addr(t_host) != INADDR_NONE)
+ good = true;
# endif /* NETINET */
- )
- return -1;
-#endif /* NETINET || NETINET6 */
+ if (!good)
+ return -1;
+ }
/* check for what will be the final length of the path */
len = strlen(HostStatDir) + 2;
@@ -1357,10 +1451,8 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
}
if (len > pathlen || len < 1)
return -1;
-
- (void) strlcpy(path, HostStatDir, pathlen);
+ (void) sm_strlcpy(path, HostStatDir, pathlen);
p = path + strlen(path);
-
while (elem > t_host)
{
if (!path_is_dir(path, createflag))
@@ -1385,14 +1477,12 @@ mci_generate_persistent_path(host, path, pathlen, createflag)
*p++ = '.';
*p = '\0';
}
-
if (tTd(56, 80))
{
if (ret < 0)
- dprintf("FAILURE %d\n", ret);
+ sm_dprintf("FAILURE %d\n", ret);
else
- dprintf("SUCCESS %s\n", path);
+ sm_dprintf("SUCCESS %s\n", path);
}
-
return ret;
}
diff --git a/contrib/sendmail/src/milter.c b/contrib/sendmail/src/milter.c
index 9782004..844a3ba 100644
--- a/contrib/sendmail/src/milter.c
+++ b/contrib/sendmail/src/milter.c
@@ -8,13 +8,14 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: milter.c,v 8.50.4.53 2001/08/15 02:01:03 ca Exp $";
-#endif /* ! lint */
+#include <sendmail.h>
-#if _FFR_MILTER
+SM_RCSID("@(#)$Id: milter.c,v 8.185 2001/11/21 02:21:15 gshapiro Exp $")
+
+#if MILTER
+# include <libmilter/mfapi.h>
+# include <libmilter/mfdef.h>
-# include <sendmail.h>
# include <errno.h>
# include <sys/time.h>
@@ -22,12 +23,10 @@ static char id[] = "@(#)$Id: milter.c,v 8.50.4.53 2001/08/15 02:01:03 ca Exp $";
# include <arpa/inet.h>
# endif /* NETINET || NETINET6 */
-# define SM_FD_SET FD_SET
-# define SM_FD_ISSET FD_ISSET
-# define SM_FD_SETSIZE FD_SETSIZE
+# include <sm/fdset.h>
static void milter_connect_timeout __P((void));
-static void milter_error __P((struct milter *));
+static void milter_error __P((struct milter *, ENVELOPE *));
static int milter_open __P((struct milter *, bool, ENVELOPE *));
static void milter_parse_timeouts __P((char *, struct milter *));
@@ -63,7 +62,7 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
!isascii(response[2]) || !isdigit(response[2])) \
{ \
if (response != NULL) \
- sm_free(response); \
+ sm_free(response); /* XXX */ \
response = newstr(default); \
} \
else \
@@ -75,7 +74,7 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
{ \
if (*ptr == '%' && *++ptr != '%') \
{ \
- sm_free(response); \
+ sm_free(response); /* XXX */ \
response = newstr(default); \
break; \
} \
@@ -89,16 +88,16 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
\
if (tTd(64, 5)) \
{ \
- dprintf(msg, dfname, errstring(save_errno)); \
- dprintf("\n"); \
+ sm_dprintf(msg, dfname, sm_errstring(save_errno)); \
+ sm_dprintf("\n"); \
} \
- if (LogLevel > 0) \
- sm_syslog(LOG_ERR, e->e_id, msg, dfname, errstring(save_errno)); \
- if (SuperSafe) \
+ if (MilterLogLevel > 0) \
+ sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \
+ if (SuperSafe == SAFE_REALLY) \
{ \
if (e->e_dfp != NULL) \
{ \
- (void) fclose(e->e_dfp); \
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \
e->e_dfp = NULL; \
} \
e->e_flags &= ~EF_HAS_DF; \
@@ -113,73 +112,85 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
** routine -- routine name for debug/logging
** secs -- number of seconds in timeout
** write -- waiting to read or write?
+** started -- whether this is part of a previous sequence
**
** Assumes 'm' is a milter structure for the current socket.
*/
-# define MILTER_TIMEOUT(routine, secs, write) \
+# define MILTER_TIMEOUT(routine, secs, write, started) \
{ \
int ret; \
int save_errno; \
fd_set fds; \
struct timeval tv; \
\
- if (SM_FD_SETSIZE != 0 && m->mf_sock >= SM_FD_SETSIZE) \
+ if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \
{ \
if (tTd(64, 5)) \
- dprintf("%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
- routine, m->mf_name, m->mf_sock, SM_FD_SETSIZE); \
- if (LogLevel > 0) \
+ sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
+ (routine), m->mf_name, m->mf_sock, \
+ SM_FD_SETSIZE); \
+ if (MilterLogLevel > 0) \
sm_syslog(LOG_ERR, e->e_id, \
- "%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
- routine, m->mf_name, m->mf_sock, SM_FD_SETSIZE); \
- milter_error(m); \
+ "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \
+ m->mf_name, (routine), m->mf_sock, \
+ SM_FD_SETSIZE); \
+ milter_error(m, e); \
return NULL; \
} \
\
FD_ZERO(&fds); \
SM_FD_SET(m->mf_sock, &fds); \
- tv.tv_sec = secs; \
+ tv.tv_sec = (secs); \
tv.tv_usec = 0; \
ret = select(m->mf_sock + 1, \
- write ? NULL : &fds, \
- write ? &fds : NULL, \
+ (write) ? NULL : &fds, \
+ (write) ? &fds : NULL, \
NULL, &tv); \
\
switch (ret) \
{ \
case 0: \
if (tTd(64, 5)) \
- dprintf("%s(%s): timeout\n", routine, m->mf_name); \
- if (LogLevel > 0) \
- sm_syslog(LOG_ERR, e->e_id, "%s(%s): timeout\n", \
- routine, m->mf_name); \
- milter_error(m); \
+ sm_dprintf("milter_%s(%s): timeout\n", (routine), \
+ m->mf_name); \
+ if (MilterLogLevel > 0) \
+ sm_syslog(LOG_ERR, e->e_id, \
+ "Milter (%s): %s %s %s %s", \
+ m->mf_name, "timeout", \
+ started ? "during" : "before", \
+ "data", (routine)); \
+ milter_error(m, e); \
return NULL; \
\
case -1: \
save_errno = errno; \
if (tTd(64, 5)) \
- dprintf("%s(%s): select: %s\n", \
- routine, m->mf_name, errstring(save_errno)); \
- if (LogLevel > 0) \
+ sm_dprintf("milter_%s(%s): select: %s\n", (routine), \
+ m->mf_name, sm_errstring(save_errno)); \
+ if (MilterLogLevel > 0) \
+ { \
sm_syslog(LOG_ERR, e->e_id, \
- "%s(%s): select: %s\n", \
- routine, m->mf_name, errstring(save_errno)); \
- milter_error(m); \
+ "Milter (%s): select(%s): %s", \
+ m->mf_name, (routine), \
+ sm_errstring(save_errno)); \
+ } \
+ milter_error(m, e); \
return NULL; \
\
default: \
if (SM_FD_ISSET(m->mf_sock, &fds)) \
break; \
if (tTd(64, 5)) \
- dprintf("%s(%s): socket not ready\n", \
- routine, m->mf_name); \
- if (LogLevel > 0) \
+ sm_dprintf("milter_%s(%s): socket not ready\n", \
+ (routine), m->mf_name); \
+ if (MilterLogLevel > 0) \
+ { \
sm_syslog(LOG_ERR, e->e_id, \
- "%s(%s): socket not ready\n", \
- m->mf_name, routine); \
- milter_error(m); \
+ "Milter (%s): socket(%s) not ready", \
+ m->mf_name, (routine)); \
+ } \
+ milter_error(m, e); \
return NULL; \
} \
}
@@ -188,7 +199,7 @@ static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
** Low level functions
*/
- /*
+/*
** MILTER_READ -- read from a remote milter filter
**
** Parameters:
@@ -212,6 +223,7 @@ milter_sysread(m, buf, sz, to, e)
{
time_t readstart = 0;
ssize_t len, curl;
+ bool started = false;
curl = 0;
@@ -228,18 +240,22 @@ milter_sysread(m, buf, sz, to, e)
if (now - readstart >= to)
{
if (tTd(64, 5))
- dprintf("milter_read(%s): timeout before data read\n",
- m->mf_name);
- if (LogLevel > 0)
+ sm_dprintf("milter_read (%s): %s %s %s",
+ m->mf_name, "timeout",
+ started ? "during" : "before",
+ "data read");
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_read(%s): timeout before data read\n",
- m->mf_name);
- milter_error(m);
+ "Milter (%s): %s %s %s",
+ m->mf_name, "timeout",
+ started ? "during" : "before",
+ "data read");
+ milter_error(m, e);
return NULL;
}
to -= now - readstart;
readstart = now;
- MILTER_TIMEOUT("milter_read", to, FALSE);
+ MILTER_TIMEOUT("read", to, false, started);
}
len = read(m->mf_sock, buf + curl, sz - curl);
@@ -249,18 +265,19 @@ milter_sysread(m, buf, sz, to, e)
int save_errno = errno;
if (tTd(64, 5))
- dprintf("milter_read(%s): read returned %ld: %s\n",
+ sm_dprintf("milter_read(%s): read returned %ld: %s\n",
m->mf_name, (long) len,
- errstring(save_errno));
- if (LogLevel > 0)
+ sm_errstring(save_errno));
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_read(%s): read returned %ld: %s",
+ "Milter (%s): read returned %ld: %s",
m->mf_name, (long) len,
- errstring(save_errno));
- milter_error(m);
+ sm_errstring(save_errno));
+ milter_error(m, e);
return NULL;
}
+ started = true;
curl += len;
if (len == 0 || curl >= sz)
break;
@@ -270,13 +287,13 @@ milter_sysread(m, buf, sz, to, e)
if (curl != sz)
{
if (tTd(64, 5))
- dprintf("milter_read(%s): read returned %ld, expecting %ld\n",
+ sm_dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n",
m->mf_name, (long) curl, (long) sz);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_read(%s): read returned %ld, expecting %ld",
+ "milter_read(%s): cmd read returned %ld, expecting %ld",
m->mf_name, (long) curl, (long) sz);
- milter_error(m);
+ milter_error(m, e);
return NULL;
}
return buf;
@@ -314,13 +331,13 @@ milter_read(m, cmd, rlen, to, e)
if (now - readstart >= to)
{
if (tTd(64, 5))
- dprintf("milter_read(%s): timeout before data read\n",
+ sm_dprintf("milter_read(%s): timeout before data read\n",
m->mf_name);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_read(%s): timeout before data read\n",
+ "Milter read(%s): timeout before data read",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
return NULL;
}
to -= now - readstart;
@@ -332,40 +349,40 @@ milter_read(m, cmd, rlen, to, e)
expl = ntohl(i) - 1;
if (tTd(64, 25))
- dprintf("milter_read(%s): expecting %ld bytes\n",
+ sm_dprintf("milter_read(%s): expecting %ld bytes\n",
m->mf_name, (long) expl);
if (expl < 0)
{
if (tTd(64, 5))
- dprintf("milter_read(%s): read size %ld out of range\n",
+ sm_dprintf("milter_read(%s): read size %ld out of range\n",
m->mf_name, (long) expl);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"milter_read(%s): read size %ld out of range",
m->mf_name, (long) expl);
- milter_error(m);
+ milter_error(m, e);
return NULL;
}
if (expl == 0)
return NULL;
- buf = (char *)xalloc(expl);
+ buf = (char *) xalloc(expl);
if (milter_sysread(m, buf, expl, to, e) == NULL)
{
- sm_free(buf);
+ sm_free(buf); /* XXX */
return NULL;
}
if (tTd(64, 50))
- dprintf("milter_read(%s): Returning %*s\n",
+ sm_dprintf("milter_read(%s): Returning %*s\n",
m->mf_name, (int) expl, buf);
*rlen = expl;
return buf;
}
- /*
+/*
** MILTER_WRITE -- write to a remote milter filter
**
** Parameters:
@@ -395,23 +412,24 @@ milter_write(m, cmd, buf, len, to, e)
ssize_t sl, i;
mi_int32 nl;
char data[MILTER_LEN_BYTES + 1];
+ bool started = false;
if (len < 0 || len > MILTER_CHUNK_SIZE)
{
if (tTd(64, 5))
- dprintf("milter_write(%s): length %ld out of range\n",
+ sm_dprintf("milter_write(%s): length %ld out of range\n",
m->mf_name, (long) len);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"milter_write(%s): length %ld out of range",
m->mf_name, (long) len);
- milter_error(m);
+ milter_error(m, e);
return NULL;
}
if (tTd(64, 20))
- dprintf("milter_write(%s): cmd %c, len %ld\n",
- m->mf_name, cmd, (long) len);
+ sm_dprintf("milter_write(%s): cmd %c, len %ld\n",
+ m->mf_name, cmd, (long) len);
nl = htonl(len + 1); /* add 1 for the cmd char */
(void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES);
@@ -421,7 +439,7 @@ milter_write(m, cmd, buf, len, to, e)
if (to > 0)
{
writestart = curtime();
- MILTER_TIMEOUT("milter_write", to, TRUE);
+ MILTER_TIMEOUT("write", to, true, started);
}
/* use writev() instead to send the whole stuff at once? */
@@ -431,15 +449,15 @@ milter_write(m, cmd, buf, len, to, e)
int save_errno = errno;
if (tTd(64, 5))
- dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
- m->mf_name, cmd, (long) i, (long) sl,
- errstring(save_errno));
- if (LogLevel > 0)
+ sm_dprintf("milter_write (%s): write(%c) returned %ld, expected %ld: %s\n",
+ m->mf_name, cmd, (long) i, (long) sl,
+ sm_errstring(save_errno));
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_write(%s): write(%c) returned %ld, expected %ld: %s",
+ "Milter (%s): write(%c) returned %ld, expected %ld: %s",
m->mf_name, cmd, (long) i, (long) sl,
- errstring(save_errno));
- milter_error(m);
+ sm_errstring(save_errno));
+ milter_error(m, e);
return buf;
}
@@ -447,8 +465,9 @@ milter_write(m, cmd, buf, len, to, e)
return buf;
if (tTd(64, 50))
- dprintf("milter_write(%s): Sending %*s\n",
- m->mf_name, (int) len, buf);
+ sm_dprintf("milter_write(%s): Sending %*s\n",
+ m->mf_name, (int) len, buf);
+ started = true;
if (to > 0)
{
@@ -458,19 +477,19 @@ milter_write(m, cmd, buf, len, to, e)
if (now - writestart >= to)
{
if (tTd(64, 5))
- dprintf("milter_write(%s): timeout before data send\n",
- m->mf_name);
- if (LogLevel > 0)
+ sm_dprintf("milter_write(%s): timeout before data write\n",
+ m->mf_name);
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_write(%s): timeout before data send\n",
+ "Milter (%s): timeout before data write",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
return NULL;
}
else
{
to -= now - writestart;
- MILTER_TIMEOUT("milter_write", to, TRUE);
+ MILTER_TIMEOUT("write", to, true, started);
}
}
@@ -480,15 +499,15 @@ milter_write(m, cmd, buf, len, to, e)
int save_errno = errno;
if (tTd(64, 5))
- dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
- m->mf_name, cmd, (long) i, (long) sl,
- errstring(save_errno));
- if (LogLevel > 0)
+ sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
+ m->mf_name, cmd, (long) i, (long) sl,
+ sm_errstring(save_errno));
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_write(%s): write(%c) returned %ld, expected %ld: %s",
+ "Milter (%s): write(%c) returned %ld, expected %ld: %s",
m->mf_name, cmd, (long) i, (long) len,
- errstring(save_errno));
- milter_error(m);
+ sm_errstring(save_errno));
+ milter_error(m, e);
return NULL;
}
return buf;
@@ -498,7 +517,7 @@ milter_write(m, cmd, buf, len, to, e)
** Utility functions
*/
- /*
+/*
** MILTER_OPEN -- connect to remote milter filter
**
** Parameters:
@@ -533,16 +552,16 @@ milter_open(m, parseonly, e)
if (m->mf_conn == NULL || m->mf_conn[0] == '\0')
{
if (tTd(64, 5))
- dprintf("X%s: empty or missing socket information\n",
- m->mf_name);
+ sm_dprintf("X%s: empty or missing socket information\n",
+ m->mf_name);
if (parseonly)
syserr("X%s: empty or missing socket information",
m->mf_name);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: empty or missing socket information",
+ "Milter (%s): empty or missing socket information",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
@@ -569,25 +588,25 @@ milter_open(m, parseonly, e)
# else /* NETINET6 */
/* no protocols available */
sm_syslog(LOG_ERR, e->e_id,
- "X%s: no valid socket protocols available",
+ "Milter (%s): no valid socket protocols available",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
return -1;
# endif /* NETINET6 */
# endif /* NETINET */
# endif /* NETUNIX */
}
# if NETUNIX
- else if (strcasecmp(p, "unix") == 0 ||
- strcasecmp(p, "local") == 0)
+ else if (sm_strcasecmp(p, "unix") == 0 ||
+ sm_strcasecmp(p, "local") == 0)
addr.sa.sa_family = AF_UNIX;
# endif /* NETUNIX */
# if NETINET
- else if (strcasecmp(p, "inet") == 0)
+ else if (sm_strcasecmp(p, "inet") == 0)
addr.sa.sa_family = AF_INET;
# endif /* NETINET */
# if NETINET6
- else if (strcasecmp(p, "inet6") == 0)
+ else if (sm_strcasecmp(p, "inet6") == 0)
addr.sa.sa_family = AF_INET6;
# endif /* NETINET6 */
else
@@ -598,16 +617,16 @@ milter_open(m, parseonly, e)
errno = EINVAL;
# endif /* EPROTONOSUPPORT */
if (tTd(64, 5))
- dprintf("X%s: unknown socket type %s\n",
+ sm_dprintf("X%s: unknown socket type %s\n",
m->mf_name, p);
if (parseonly)
syserr("X%s: unknown socket type %s",
m->mf_name, p);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: unknown socket type %s",
+ "Milter (%s): unknown socket type %s",
m->mf_name, p);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
*colon++ = ':';
@@ -628,17 +647,17 @@ milter_open(m, parseonly, e)
if (strlen(colon) >= sizeof addr.sunix.sun_path)
{
if (tTd(64, 5))
- dprintf("X%s: local socket name %s too long\n",
+ sm_dprintf("X%s: local socket name %s too long\n",
m->mf_name, colon);
errno = EINVAL;
if (parseonly)
syserr("X%s: local socket name %s too long",
m->mf_name, colon);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: local socket name %s too long",
+ "Milter (%s): local socket name %s too long",
m->mf_name, colon);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
@@ -649,16 +668,16 @@ milter_open(m, parseonly, e)
{
if (OpMode == MD_DAEMON ||
OpMode == MD_FGDAEMON)
- fprintf(stderr,
- "WARNING: X%s: local socket name %s missing\n",
- m->mf_name, colon);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "WARNING: X%s: local socket name %s missing\n",
+ m->mf_name, colon);
}
else if (errno != 0)
{
/* if not safe, don't create */
save_errno = errno;
if (tTd(64, 5))
- dprintf("X%s: local socket name %s unsafe\n",
+ sm_dprintf("X%s: local socket name %s unsafe\n",
m->mf_name, colon);
errno = save_errno;
if (parseonly)
@@ -669,22 +688,22 @@ milter_open(m, parseonly, e)
syserr("X%s: local socket name %s unsafe",
m->mf_name, colon);
}
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: local socket name %s unsafe",
+ "Milter (%s): local socket name %s unsafe",
m->mf_name, colon);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
- (void) strlcpy(addr.sunix.sun_path, colon,
+ (void) sm_strlcpy(addr.sunix.sun_path, colon,
sizeof addr.sunix.sun_path);
addrlen = sizeof (struct sockaddr_un);
}
else
# endif /* NETUNIX */
# if NETINET || NETINET6
- if (FALSE
+ if (false
# if NETINET
|| addr.sa.sa_family == AF_INET
# endif /* NETINET */
@@ -693,42 +712,42 @@ milter_open(m, parseonly, e)
# endif /* NETINET6 */
)
{
- u_short port;
+ unsigned short port;
/* Parse port@host */
at = strchr(colon, '@');
if (at == NULL)
{
if (tTd(64, 5))
- dprintf("X%s: bad address %s (expected port@host)\n",
+ sm_dprintf("X%s: bad address %s (expected port@host)\n",
m->mf_name, colon);
if (parseonly)
syserr("X%s: bad address %s (expected port@host)",
m->mf_name, colon);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: bad address %s (expected port@host)",
+ "Milter (%s): bad address %s (expected port@host)",
m->mf_name, colon);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
*at = '\0';
if (isascii(*colon) && isdigit(*colon))
- port = htons((u_short) atoi(colon));
+ port = htons((unsigned short) atoi(colon));
else
{
# ifdef NO_GETSERVBYNAME
if (tTd(64, 5))
- dprintf("X%s: invalid port number %s\n",
+ sm_dprintf("X%s: invalid port number %s\n",
m->mf_name, colon);
if (parseonly)
syserr("X%s: invalid port number %s",
m->mf_name, colon);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: invalid port number %s",
+ "Milter (%s): invalid port number %s",
m->mf_name, colon);
- milter_error(m);
+ milter_error(m, e);
return -1;
# else /* NO_GETSERVBYNAME */
register struct servent *sp;
@@ -738,17 +757,17 @@ milter_open(m, parseonly, e)
{
save_errno = errno;
if (tTd(64, 5))
- dprintf("X%s: unknown port name %s\n",
+ sm_dprintf("X%s: unknown port name %s\n",
m->mf_name, colon);
errno = save_errno;
if (parseonly)
syserr("X%s: unknown port name %s",
m->mf_name, colon);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: unknown port name %s",
+ "Milter (%s): unknown port name %s",
m->mf_name, colon);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
port = sp->s_port;
@@ -762,7 +781,7 @@ milter_open(m, parseonly, e)
end = strchr(at, ']');
if (end != NULL)
{
- bool found = FALSE;
+ bool found = false;
# if NETINET
unsigned long hid = INADDR_NONE;
# endif /* NETINET */
@@ -777,50 +796,50 @@ milter_open(m, parseonly, e)
{
addr.sin.sin_addr.s_addr = hid;
addr.sin.sin_port = port;
- found = TRUE;
+ found = true;
}
# endif /* NETINET */
# if NETINET6
(void) memset(&hid6, '\0', sizeof hid6);
if (addr.sa.sa_family == AF_INET6 &&
- inet_pton(AF_INET6, &at[1],
- &hid6.sin6_addr) == 1)
+ anynet_pton(AF_INET6, &at[1],
+ &hid6.sin6_addr) == 1)
{
addr.sin6.sin6_addr = hid6.sin6_addr;
addr.sin6.sin6_port = port;
- found = TRUE;
+ found = true;
}
# endif /* NETINET6 */
*end = ']';
if (!found)
{
if (tTd(64, 5))
- dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
+ sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
m->mf_name, at);
if (parseonly)
syserr("X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: Invalid numeric domain spec \"%s\"",
+ "Milter (%s): Invalid numeric domain spec \"%s\"",
m->mf_name, at);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
}
else
{
if (tTd(64, 5))
- dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
+ sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
m->mf_name, at);
if (parseonly)
syserr("X%s: Invalid numeric domain spec \"%s\"",
m->mf_name, at);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: Invalid numeric domain spec \"%s\"",
+ "Milter (%s): Invalid numeric domain spec \"%s\"",
m->mf_name, at);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
}
@@ -831,17 +850,17 @@ milter_open(m, parseonly, e)
{
save_errno = errno;
if (tTd(64, 5))
- dprintf("X%s: Unknown host name %s\n",
- m->mf_name, at);
+ sm_dprintf("X%s: Unknown host name %s\n",
+ m->mf_name, at);
errno = save_errno;
if (parseonly)
syserr("X%s: Unknown host name %s",
m->mf_name, at);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: Unknown host name %s",
+ "Milter (%s): Unknown host name %s",
m->mf_name, at);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
addr.sa.sa_family = hp->h_addrtype;
@@ -850,8 +869,7 @@ milter_open(m, parseonly, e)
# if NETINET
case AF_INET:
memmove(&addr.sin.sin_addr,
- hp->h_addr,
- INADDRSZ);
+ hp->h_addr, INADDRSZ);
addr.sin.sin_port = port;
addrlen = sizeof (struct sockaddr_in);
addrno = 1;
@@ -861,8 +879,7 @@ milter_open(m, parseonly, e)
# if NETINET6
case AF_INET6:
memmove(&addr.sin6.sin6_addr,
- hp->h_addr,
- IN6ADDRSZ);
+ hp->h_addr, IN6ADDRSZ);
addr.sin6.sin6_port = port;
addrlen = sizeof (struct sockaddr_in6);
addrno = 1;
@@ -871,21 +888,21 @@ milter_open(m, parseonly, e)
default:
if (tTd(64, 5))
- dprintf("X%s: Unknown protocol for %s (%d)\n",
- m->mf_name, at,
- hp->h_addrtype);
+ sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
+ m->mf_name, at,
+ hp->h_addrtype);
if (parseonly)
syserr("X%s: Unknown protocol for %s (%d)",
m->mf_name, at, hp->h_addrtype);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: Unknown protocol for %s (%d)",
+ "Milter (%s): Unknown protocol for %s (%d)",
m->mf_name, at,
hp->h_addrtype);
- milter_error(m);
-# if _FFR_FREEHOSTENT && NETINET6
+ milter_error(m, e);
+# if NETINET6
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return -1;
}
}
@@ -894,13 +911,15 @@ milter_open(m, parseonly, e)
# endif /* NETINET || NETINET6 */
{
if (tTd(64, 5))
- dprintf("X%s: unknown socket protocol\n", m->mf_name);
+ sm_dprintf("X%s: unknown socket protocol\n",
+ m->mf_name);
if (parseonly)
syserr("X%s: unknown socket protocol", m->mf_name);
- else if (LogLevel > 10)
+ else if (MilterLogLevel > 10)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: unknown socket protocol", m->mf_name);
- milter_error(m);
+ "Milter (%s): unknown socket protocol",
+ m->mf_name);
+ milter_error(m, e);
return -1;
}
@@ -908,10 +927,10 @@ milter_open(m, parseonly, e)
if (parseonly)
{
m->mf_state = SMFS_READY;
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return 0;
}
@@ -921,13 +940,13 @@ milter_open(m, parseonly, e)
{
/* shouldn't happen */
if (tTd(64, 1))
- dprintf("milter_open(%s): Trying to open filter in state %c\n",
- m->mf_name, (char) m->mf_state);
- milter_error(m);
-# if _FFR_FREEHOSTENT && NETINET6
+ sm_dprintf("Milter (%s): Trying to open filter in state %c\n",
+ m->mf_name, (char) m->mf_state);
+ milter_error(m, e);
+# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return -1;
}
@@ -939,33 +958,34 @@ milter_open(m, parseonly, e)
{
save_errno = errno;
if (tTd(64, 5))
- dprintf("X%s: error creating socket: %s\n",
- m->mf_name, errstring(save_errno));
- if (LogLevel > 0)
+ sm_dprintf("Milter (%s): error creating socket: %s\n",
+ m->mf_name,
+ sm_errstring(save_errno));
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: error creating socket: %s",
- m->mf_name, errstring(save_errno));
- milter_error(m);
-# if _FFR_FREEHOSTENT && NETINET6
+ "Milter (%s): error creating socket: %s",
+ m->mf_name, sm_errstring(save_errno));
+ milter_error(m, e);
+# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return -1;
}
if (setjmp(MilterConnectTimeout) == 0)
{
- EVENT *ev = NULL;
+ SM_EVENT *ev = NULL;
int i;
if (m->mf_timeout[SMFTO_CONNECT] > 0)
- ev = setevent(m->mf_timeout[SMFTO_CONNECT],
- milter_connect_timeout, 0);
+ ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT],
+ milter_connect_timeout, 0);
i = connect(sock, (struct sockaddr *) &addr, addrlen);
save_errno = errno;
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
errno = save_errno;
if (i >= 0)
break;
@@ -976,12 +996,12 @@ milter_open(m, parseonly, e)
p = CurHostName;
CurHostName = at;
if (tTd(64, 5))
- dprintf("milter_open(%s): %s failed: %s\n",
- m->mf_name, at, errstring(save_errno));
- if (LogLevel >= 14)
+ sm_dprintf("milter_open (%s): open %s failed: %s\n",
+ m->mf_name, at, sm_errstring(save_errno));
+ if (MilterLogLevel > 13)
sm_syslog(LOG_INFO, e->e_id,
- "milter_open(%s): %s failed: %s",
- m->mf_name, at, errstring(save_errno));
+ "Milter (%s): open %s failed: %s",
+ m->mf_name, at, sm_errstring(save_errno));
CurHostName = p;
(void) close(sock);
@@ -1008,18 +1028,18 @@ milter_open(m, parseonly, e)
default:
if (tTd(64, 5))
- dprintf("X%s: Unknown protocol for %s (%d)\n",
- m->mf_name, at,
- hp->h_addrtype);
- if (LogLevel > 0)
+ sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
+ m->mf_name, at,
+ hp->h_addrtype);
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: Unknown protocol for %s (%d)",
+ "Milter (%s): Unknown protocol for %s (%d)",
m->mf_name, at,
hp->h_addrtype);
- milter_error(m);
-# if _FFR_FREEHOSTENT && NETINET6
+ milter_error(m, e);
+# if NETINET6
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return -1;
}
continue;
@@ -1027,28 +1047,28 @@ milter_open(m, parseonly, e)
p = CurHostName;
CurHostName = at;
if (tTd(64, 5))
- dprintf("X%s: error connecting to filter: %s\n",
- m->mf_name, errstring(save_errno));
- if (LogLevel > 0)
+ sm_dprintf("X%s: error connecting to filter: %s\n",
+ m->mf_name, sm_errstring(save_errno));
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "X%s: error connecting to filter: %s",
- m->mf_name, errstring(save_errno));
+ "Milter (%s): error connecting to filter: %s",
+ m->mf_name, sm_errstring(save_errno));
CurHostName = p;
- milter_error(m);
-# if _FFR_FREEHOSTENT && NETINET6
+ milter_error(m, e);
+# if NETINET6
if (hp != NULL)
freehostent(hp);
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return -1;
}
m->mf_state = SMFS_OPEN;
-# if _FFR_FREEHOSTENT && NETINET6
+# if NETINET6
if (hp != NULL)
{
freehostent(hp);
hp = NULL;
}
-# endif /* _FFR_FREEHOSTENT && NETINET6 */
+# endif /* NETINET6 */
return sock;
}
@@ -1064,7 +1084,7 @@ milter_connect_timeout()
errno = ETIMEDOUT;
longjmp(MilterConnectTimeout, 1);
}
- /*
+/*
** MILTER_SETUP -- setup structure for a mail filter
**
** Parameters:
@@ -1095,12 +1115,12 @@ milter_setup(line)
syserr("name required for mail filter");
return;
}
- m = (struct milter *)xalloc(sizeof *m);
+ m = (struct milter *) xalloc(sizeof *m);
memset((char *) m, '\0', sizeof *m);
m->mf_name = newstr(line);
m->mf_state = SMFS_READY;
m->mf_sock = -1;
- m->mf_timeout[SMFTO_CONNECT] = (time_t) 0;
+ m->mf_timeout[SMFTO_CONNECT] = (time_t) 300;
m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
m->mf_timeout[SMFTO_READ] = (time_t) 10;
m->mf_timeout[SMFTO_EOM] = (time_t) 300;
@@ -1160,7 +1180,7 @@ milter_setup(line)
}
/* early check for errors */
- (void) milter_open(m, TRUE, CurEnv);
+ (void) milter_open(m, true, CurEnv);
/* enter the filter into the symbol table */
s = stab(m->mf_name, ST_MILTER, ST_ENTER);
@@ -1169,8 +1189,8 @@ milter_setup(line)
else
s->s_milter = m;
}
- /*
-** MILTER_PARSE_LIST -- parse option list into an array
+/*
+** MILTER_CONFIG -- parse option list into an array and check config
**
** Called when reading configuration file.
**
@@ -1184,7 +1204,7 @@ milter_setup(line)
*/
void
-milter_parse_list(spec, list, max)
+milter_config(spec, list, max)
char *spec;
struct milter **list;
int max;
@@ -1212,7 +1232,11 @@ milter_parse_list(spec, list, max)
list[0] = NULL;
return;
}
+#if _FFR_MILTER_PERDAEMON
+ p = strpbrk(p, ";,");
+#else /* _FFR_MILTER_PERDAEMON */
p = strpbrk(p, ",");
+#endif /* _FFR_MILTER_PERDAEMON */
if (p != NULL)
*p++ = '\0';
@@ -1226,8 +1250,12 @@ milter_parse_list(spec, list, max)
list[numitems++] = s->s_milter;
}
list[numitems] = NULL;
+
+ /* if not set, set to LogLevel */
+ if (MilterLogLevel == -1)
+ MilterLogLevel = LogLevel;
}
- /*
+/*
** MILTER_PARSE_TIMEOUTS -- parse timeout list
**
** Called when reading configuration file.
@@ -1280,39 +1308,39 @@ milter_parse_timeouts(spec, m)
case 'C':
m->mf_timeout[SMFTO_CONNECT] = convtime(p, 's');
if (tTd(64, 5))
- printf("X%s: %c=%ld\n",
- m->mf_name, fcode,
- (u_long) m->mf_timeout[SMFTO_CONNECT]);
+ sm_dprintf("X%s: %c=%lu\n",
+ m->mf_name, fcode,
+ (unsigned long) m->mf_timeout[SMFTO_CONNECT]);
break;
case 'S':
m->mf_timeout[SMFTO_WRITE] = convtime(p, 's');
if (tTd(64, 5))
- printf("X%s: %c=%ld\n",
- m->mf_name, fcode,
- (u_long) m->mf_timeout[SMFTO_WRITE]);
+ sm_dprintf("X%s: %c=%lu\n",
+ m->mf_name, fcode,
+ (unsigned long) m->mf_timeout[SMFTO_WRITE]);
break;
case 'R':
m->mf_timeout[SMFTO_READ] = convtime(p, 's');
if (tTd(64, 5))
- printf("X%s: %c=%ld\n",
- m->mf_name, fcode,
- (u_long) m->mf_timeout[SMFTO_READ]);
+ sm_dprintf("X%s: %c=%lu\n",
+ m->mf_name, fcode,
+ (unsigned long) m->mf_timeout[SMFTO_READ]);
break;
case 'E':
m->mf_timeout[SMFTO_EOM] = convtime(p, 's');
if (tTd(64, 5))
- printf("X%s: %c=%ld\n",
- m->mf_name, fcode,
- (u_long) m->mf_timeout[SMFTO_EOM]);
+ sm_dprintf("X%s: %c=%lu\n",
+ m->mf_name, fcode,
+ (unsigned long) m->mf_timeout[SMFTO_EOM]);
break;
default:
if (tTd(64, 5))
- printf("X%s: %c unknown\n",
- m->mf_name, fcode);
+ sm_dprintf("X%s: %c unknown\n",
+ m->mf_name, fcode);
syserr("X%s: unknown filter timeout %c",
m->mf_name, fcode);
break;
@@ -1320,7 +1348,7 @@ milter_parse_timeouts(spec, m)
p = delimptr;
}
}
- /*
+/*
** MILTER_SET_OPTION -- set an individual milter option
**
** Parameters:
@@ -1338,8 +1366,8 @@ static BITMAP256 StickyMilterOpt;
static struct milteropt
{
- char *mo_name; /* long name of milter option */
- u_char mo_code; /* code for option */
+ char *mo_name; /* long name of milter option */
+ unsigned char mo_code; /* code for option */
} MilterOptTab[] =
{
# define MO_MACROS_CONNECT 0x01
@@ -1350,6 +1378,8 @@ static struct milteropt
{ "macros.envfrom", MO_MACROS_ENVFROM },
# define MO_MACROS_ENVRCPT 0x04
{ "macros.envrcpt", MO_MACROS_ENVRCPT },
+# define MO_LOGLEVEL 0x05
+ { "loglevel", MO_LOGLEVEL },
{ NULL, 0 },
};
@@ -1365,16 +1395,19 @@ milter_set_option(name, val, sticky)
char **macros = NULL;
if (tTd(37, 2) || tTd(64, 5))
- dprintf("milter_set_option(%s = %s)", name, val);
+ sm_dprintf("milter_set_option(%s = %s)", name, val);
for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
{
- if (strcasecmp(mo->mo_name, name) == 0)
+ if (sm_strcasecmp(mo->mo_name, name) == 0)
break;
}
if (mo->mo_name == NULL)
+ {
syserr("milter_set_option: invalid Milter option %s", name);
+ return;
+ }
/*
** See if this option is preset for us.
@@ -1383,15 +1416,19 @@ milter_set_option(name, val, sticky)
if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
{
if (tTd(37, 2) || tTd(64,5))
- dprintf(" (ignored)\n");
+ sm_dprintf(" (ignored)\n");
return;
}
if (tTd(37, 2) || tTd(64,5))
- dprintf("\n");
+ sm_dprintf("\n");
switch (mo->mo_code)
{
+ case MO_LOGLEVEL:
+ MilterLogLevel = atoi(val);
+ break;
+
case MO_MACROS_CONNECT:
if (macros == NULL)
macros = MilterConnectMacros;
@@ -1448,12 +1485,11 @@ milter_set_option(name, val, sticky)
syserr("milter_set_option: invalid Milter option %s", name);
break;
}
-
if (sticky)
setbitn(mo->mo_code, StickyMilterOpt);
}
- /*
-** MILTER_REOPEN_DF -- open & truncate the df file (for replbody)
+/*
+** MILTER_REOPEN_DF -- open & truncate the data file (for replbody)
**
** Parameters:
** e -- current envelope.
@@ -1468,32 +1504,33 @@ milter_reopen_df(e)
{
char dfname[MAXPATHLEN];
- (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
+ (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname);
/*
- ** In SuperSafe mode, e->e_dfp is a read-only FP so
+ ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so
** close and reopen writable (later close and reopen
** read only again).
**
- ** In !SuperSafe mode, e->e_dfp still points at the
+ ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the
** buffered file I/O descriptor, still open for writing
** so there isn't as much work to do, just truncate it
** and go.
*/
- if (SuperSafe)
+ if (SuperSafe == SAFE_REALLY)
{
- /* close read-only df */
+ /* close read-only data file */
if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
{
- (void) fclose(e->e_dfp);
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
e->e_flags &= ~EF_HAS_DF;
}
/* open writable */
- if ((e->e_dfp = fopen(dfname, "w+")) == NULL)
+ if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
+ SM_IO_RDWR, NULL)) == NULL)
{
- MILTER_DF_ERROR("milter_reopen_df: fopen %s: %s");
+ MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s");
return -1;
}
}
@@ -1506,8 +1543,8 @@ milter_reopen_df(e)
}
return 0;
}
- /*
-** MILTER_RESET_DF -- re-open read-only the df file (for replbody)
+/*
+** MILTER_RESET_DF -- re-open read-only the data file (for replbody)
**
** Parameters:
** e -- current envelope.
@@ -1523,29 +1560,32 @@ milter_reset_df(e)
int afd;
char dfname[MAXPATHLEN];
- (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
+ (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname);
- if (fflush(e->e_dfp) != 0 || ferror(e->e_dfp))
+ if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 ||
+ sm_io_error(e->e_dfp))
{
MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
return -1;
}
- else if (!SuperSafe)
+ else if (SuperSafe != SAFE_REALLY)
{
/* skip next few clauses */
/* EMPTY */
}
- else if ((afd = fileno(e->e_dfp)) >= 0 && fsync(afd) < 0)
+ else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0
+ && fsync(afd) < 0)
{
MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
return -1;
}
- else if (fclose(e->e_dfp) < 0)
+ else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0)
{
MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
return -1;
}
- else if ((e->e_dfp = fopen(dfname, "r")) == NULL)
+ else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
+ SM_IO_RDONLY, NULL)) == NULL)
{
MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
return -1;
@@ -1554,24 +1594,24 @@ milter_reset_df(e)
e->e_flags |= EF_HAS_DF;
return 0;
}
- /*
+/*
** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients?
**
** Parameters:
** none
**
** Returns:
-** TRUE if any filter deletes recipients, FALSE otherwise
+** true if any filter deletes recipients, false otherwise
*/
bool
milter_can_delrcpts()
{
- bool can = FALSE;
+ bool can = false;
int i;
if (tTd(64, 10))
- dprintf("milter_can_delrcpts:");
+ sm_dprintf("milter_can_delrcpts:");
for (i = 0; InputFilters[i] != NULL; i++)
{
@@ -1579,16 +1619,16 @@ milter_can_delrcpts()
if (bitset(SMFIF_DELRCPT, m->mf_fflags))
{
- can = TRUE;
+ can = true;
break;
}
}
if (tTd(64, 10))
- dprintf("%s\n", can ? "TRUE" : "FALSE");
+ sm_dprintf("%s\n", can ? "true" : "false");
return can;
}
- /*
+/*
** MILTER_QUIT_FILTER -- close down a single filter
**
** Parameters:
@@ -1605,7 +1645,10 @@ milter_quit_filter(m, e)
ENVELOPE *e;
{
if (tTd(64, 10))
- dprintf("milter_quit_filter(%s)\n", m->mf_name);
+ sm_dprintf("milter_quit_filter(%s)\n", m->mf_name);
+ if (MilterLogLevel > 18)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter",
+ m->mf_name);
/* Never replace error state */
if (m->mf_state == SMFS_ERROR)
@@ -1630,7 +1673,7 @@ milter_quit_filter(m, e)
if (m->mf_state != SMFS_ERROR)
m->mf_state = SMFS_CLOSED;
}
- /*
+/*
** MILTER_ABORT_FILTER -- tell filter to abort current message
**
** Parameters:
@@ -1647,7 +1690,10 @@ milter_abort_filter(m, e)
ENVELOPE *e;
{
if (tTd(64, 10))
- dprintf("milter_abort_filter(%s)\n", m->mf_name);
+ sm_dprintf("milter_abort_filter(%s)\n", m->mf_name);
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter",
+ m->mf_name);
if (m->mf_sock < 0 ||
m->mf_state != SMFS_INMSG)
@@ -1658,7 +1704,7 @@ milter_abort_filter(m, e)
if (m->mf_state != SMFS_ERROR)
m->mf_state = SMFS_DONE;
}
- /*
+/*
** MILTER_SEND_MACROS -- provide macros to the filters
**
** Parameters:
@@ -1692,7 +1738,7 @@ milter_send_macros(m, macros, cmd, e)
s = 1; /* for the command character */
for (i = 0; macros[i] != NULL; i++)
{
- mid = macid(macros[i], NULL);
+ mid = macid(macros[i]);
if (mid == 0)
continue;
v = macvalue(mid, e);
@@ -1701,12 +1747,15 @@ milter_send_macros(m, macros, cmd, e)
s += strlen(macros[i]) + 1 + strlen(v) + 1;
}
- buf = (char *)xalloc(s);
+ if (s < 0)
+ return;
+
+ buf = (char *) xalloc(s);
bp = buf;
*bp++ = cmd;
for (i = 0; macros[i] != NULL; i++)
{
- mid = macid(macros[i], NULL);
+ mid = macid(macros[i]);
if (mid == 0)
continue;
v = macvalue(mid, e);
@@ -1714,20 +1763,20 @@ milter_send_macros(m, macros, cmd, e)
continue;
if (tTd(64, 10))
- dprintf("milter_send_macros(%s, %c): %s=%s\n",
+ sm_dprintf("milter_send_macros(%s, %c): %s=%s\n",
m->mf_name, cmd, macros[i], v);
- (void) strlcpy(bp, macros[i], s - (bp - buf));
+ (void) sm_strlcpy(bp, macros[i], s - (bp - buf));
bp += strlen(bp) + 1;
- (void) strlcpy(bp, v, s - (bp - buf));
+ (void) sm_strlcpy(bp, v, s - (bp - buf));
bp += strlen(bp) + 1;
}
(void) milter_write(m, SMFIC_MACRO, buf, s,
m->mf_timeout[SMFTO_WRITE], e);
- sm_free(buf);
+ sm_free(buf); /* XXX */
}
- /*
+/*
** MILTER_SEND_COMMAND -- send a command and return the response for a filter
**
** Parameters:
@@ -1753,12 +1802,13 @@ milter_send_command(m, command, data, sz, e, state)
{
char rcmd;
ssize_t rlen;
- u_long skipflag;
+ unsigned long skipflag;
+ char *action;
char *defresponse;
char *response;
if (tTd(64, 10))
- dprintf("milter_send_command(%s): cmd %c len %ld\n",
+ sm_dprintf("milter_send_command(%s): cmd %c len %ld\n",
m->mf_name, (char) command, (long) sz);
/* find skip flag and default failure */
@@ -1766,36 +1816,43 @@ milter_send_command(m, command, data, sz, e, state)
{
case SMFIC_CONNECT:
skipflag = SMFIP_NOCONNECT;
+ action = "connect";
defresponse = "554 Command rejected";
break;
case SMFIC_HELO:
skipflag = SMFIP_NOHELO;
+ action = "helo";
defresponse = "550 Command rejected";
break;
case SMFIC_MAIL:
skipflag = SMFIP_NOMAIL;
+ action = "mail";
defresponse = "550 5.7.1 Command rejected";
break;
case SMFIC_RCPT:
skipflag = SMFIP_NORCPT;
+ action = "rcpt";
defresponse = "550 5.7.1 Command rejected";
break;
case SMFIC_HEADER:
skipflag = SMFIP_NOHDRS;
+ action = "header";
defresponse = "550 5.7.1 Command rejected";
break;
case SMFIC_BODY:
skipflag = SMFIP_NOBODY;
+ action = "body";
defresponse = "554 5.7.1 Command rejected";
break;
case SMFIC_EOH:
skipflag = SMFIP_NOEOH;
+ action = "eoh";
defresponse = "550 5.7.1 Command rejected";
break;
@@ -1809,6 +1866,7 @@ milter_send_command(m, command, data, sz, e, state)
default:
skipflag = 0;
+ action = "default";
defresponse = "550 5.7.1 Command rejected";
break;
}
@@ -1818,7 +1876,7 @@ milter_send_command(m, command, data, sz, e, state)
bitset(skipflag, m->mf_pflags))
return NULL;
-
+ /* send the command to the filter */
(void) milter_write(m, command, data, sz,
m->mf_timeout[SMFTO_WRITE], e);
if (m->mf_state == SMFS_ERROR)
@@ -1827,6 +1885,7 @@ milter_send_command(m, command, data, sz, e, state)
return NULL;
}
+ /* get the response from the filter */
response = milter_read(m, &rcmd, &rlen,
m->mf_timeout[SMFTO_READ], e);
if (m->mf_state == SMFS_ERROR)
@@ -1836,18 +1895,37 @@ milter_send_command(m, command, data, sz, e, state)
}
if (tTd(64, 10))
- dprintf("milter_send_command(%s): returned %c\n",
- m->mf_name, (char) rcmd);
+ sm_dprintf("milter_send_command(%s): returned %c\n",
+ m->mf_name, (char) rcmd);
switch (rcmd)
{
case SMFIR_REPLYCODE:
MILTER_CHECK_REPLYCODE(defresponse);
- /* FALLTHROUGH */
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject=%s",
+ m->mf_name, action, response);
+ *state = rcmd;
+ break;
case SMFIR_REJECT:
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject",
+ m->mf_name, action);
+ *state = rcmd;
+ break;
+
case SMFIR_DISCARD:
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, discard",
+ m->mf_name, action);
+ *state = rcmd;
+ break;
+
case SMFIR_TEMPFAIL:
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, tempfail",
+ m->mf_name, action);
*state = rcmd;
break;
@@ -1858,34 +1936,40 @@ milter_send_command(m, command, data, sz, e, state)
m->mf_state = SMFS_CLOSABLE;
else
m->mf_state = SMFS_DONE;
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, accepted",
+ m->mf_name, action);
break;
case SMFIR_CONTINUE:
/* if MAIL command is ok, filter is in message state */
if (command == SMFIC_MAIL)
m->mf_state = SMFS_INMSG;
+ if (MilterLogLevel > 12)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, continue",
+ m->mf_name, action);
break;
default:
/* Invalid response to command */
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_send_command(%s): returned bogus response %c",
- m->mf_name, rcmd);
- milter_error(m);
+ "milter_send_command(%s): action=%s returned bogus response %c",
+ m->mf_name, action, rcmd);
+ milter_error(m, e);
break;
}
if (*state != SMFIR_REPLYCODE &&
response != NULL)
{
- sm_free(response);
+ sm_free(response); /* XXX */
response = NULL;
}
return response;
}
- /*
+/*
** MILTER_COMMAND -- send a command and return the response for each filter
**
** Parameters:
@@ -1911,9 +1995,10 @@ milter_command(command, data, sz, macros, e, state)
{
int i;
char *response = NULL;
+ time_t tn = 0;
if (tTd(64, 10))
- dprintf("milter_command: cmd %c len %ld\n",
+ sm_dprintf("milter_command: cmd %c len %ld\n",
(char) command, (long) sz);
*state = SMFIR_CONTINUE;
@@ -1944,13 +2029,25 @@ milter_command(command, data, sz, macros, e, state)
}
}
+ if (MilterLogLevel > 21)
+ tn = curtime();
+
response = milter_send_command(m, command, data, sz, e, state);
+
+ if (MilterLogLevel > 21)
+ {
+ /* log the time it took for the command per filter */
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter (%s): time command (%c), %d",
+ m->mf_name, command, (int) (tn - curtime()));
+ }
+
if (*state != SMFIR_CONTINUE)
break;
}
return response;
}
- /*
+/*
** MILTER_NEGOTIATE -- get version and flags from filter
**
** Parameters:
@@ -1977,11 +2074,11 @@ milter_negotiate(m, e)
/* sanity check */
if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
{
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): impossible state",
+ "Milter (%s): negotiate, impossible state",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
@@ -2006,15 +2103,15 @@ milter_negotiate(m, e)
if (rcmd != SMFIC_OPTNEG)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): returned %c instead of %c\n",
+ sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n",
m->mf_name, rcmd, SMFIC_OPTNEG);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): returned %c instead of %c",
+ "Milter (%s): negotiate: returned %c instead of %c",
m->mf_name, rcmd, SMFIC_OPTNEG);
if (response != NULL)
- sm_free(response);
- milter_error(m);
+ sm_free(response); /* XXX */
+ milter_error(m, e);
return -1;
}
@@ -2022,15 +2119,15 @@ milter_negotiate(m, e)
if (response == NULL || rlen < MILTER_LEN_BYTES)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): did not return valid info\n",
+ sm_dprintf("milter_negotiate(%s): did not return valid info\n",
m->mf_name);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): did not return valid info",
+ "Milter (%s): negotiate: did not return valid info",
m->mf_name);
if (response != NULL)
- sm_free(response);
- milter_error(m);
+ sm_free(response); /* XXX */
+ milter_error(m, e);
return -1;
}
@@ -2041,15 +2138,15 @@ milter_negotiate(m, e)
if (rlen != MILTER_OPTLEN)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): did not return enough info\n",
+ sm_dprintf("milter_negotiate(%s): did not return enough info\n",
m->mf_name);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): did not return enough info",
+ "Milter (%s): negotiate: did not return enough info",
m->mf_name);
if (response != NULL)
- sm_free(response);
- milter_error(m);
+ sm_free(response); /* XXX */
+ milter_error(m, e);
return -1;
}
@@ -2057,7 +2154,7 @@ milter_negotiate(m, e)
MILTER_LEN_BYTES);
(void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
MILTER_LEN_BYTES);
- sm_free(response);
+ sm_free(response); /* XXX */
response = NULL;
m->mf_fvers = ntohl(fvers);
@@ -2069,13 +2166,13 @@ milter_negotiate(m, e)
m->mf_fvers > SMFI_VERSION)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): version %lu != MTA milter version %d\n",
+ sm_dprintf("milter_negotiate(%s): version %lu != MTA milter version %d\n",
m->mf_name, m->mf_fvers, SMFI_VERSION);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): version %ld != MTA milter version %d",
+ "Milter (%s): negotiate: version %ld != MTA milter version %d",
m->mf_name, m->mf_fvers, SMFI_VERSION);
- milter_error(m);
+ milter_error(m, e);
return -1;
}
@@ -2083,15 +2180,15 @@ milter_negotiate(m, e)
if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
+ sm_dprintf("milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
m->mf_name, m->mf_fflags,
- (u_long) SMFI_CURR_ACTS);
- if (LogLevel > 0)
+ (unsigned long) SMFI_CURR_ACTS);
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
+ "Milter (%s): negotiate: filter abilities 0x%lx != MTA milter abilities 0x%lx",
m->mf_name, m->mf_fflags,
- (u_long) SMFI_CURR_ACTS);
- milter_error(m);
+ (unsigned long) SMFI_CURR_ACTS);
+ milter_error(m, e);
return -1;
}
@@ -2099,24 +2196,24 @@ milter_negotiate(m, e)
if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags)
{
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
+ sm_dprintf("milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
m->mf_name, m->mf_pflags,
- (u_long) SMFI_CURR_PROT);
- if (LogLevel > 0)
+ (unsigned long) SMFI_CURR_PROT);
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
+ "Milter (%s): negotiate: protocol abilities 0x%lx != MTA milter abilities 0x%lx",
m->mf_name, m->mf_pflags,
- (u_long) SMFI_CURR_PROT);
- milter_error(m);
+ (unsigned long) SMFI_CURR_PROT);
+ milter_error(m, e);
return -1;
}
if (tTd(64, 5))
- dprintf("milter_negotiate(%s): version %lu, fflags 0x%lx, pflags 0x%lx\n",
+ sm_dprintf("milter_negotiate(%s): version %lu, fflags 0x%lx, pflags 0x%lx\n",
m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
return 0;
}
- /*
+/*
** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
**
** Reduce code duplication by putting these checks in one place
@@ -2143,7 +2240,7 @@ milter_per_connection_check(e)
milter_quit_filter(m, e);
}
}
- /*
+/*
** MILTER_ERROR -- Put a milter filter into error state
**
** Parameters:
@@ -2154,8 +2251,9 @@ milter_per_connection_check(e)
*/
static void
-milter_error(m)
+milter_error(m, e)
struct milter *m;
+ ENVELOPE *e;
{
/*
** We could send a quit here but
@@ -2170,8 +2268,12 @@ milter_error(m)
m->mf_sock = -1;
}
m->mf_state = SMFS_ERROR;
+
+ if (MilterLogLevel > 0)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state",
+ m->mf_name);
}
- /*
+/*
** MILTER_HEADERS -- send headers to a single milter filter
**
** Parameters:
@@ -2192,6 +2294,10 @@ milter_headers(m, e, state)
char *response = NULL;
HDR *h;
+ if (MilterLogLevel > 17)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send",
+ m->mf_name);
+
for (h = e->e_header; h != NULL; h = h->h_link)
{
char *buf;
@@ -2210,26 +2316,34 @@ milter_headers(m, e, state)
continue;
if (tTd(64, 10))
- dprintf("milter_headers: %s: %s\n",
+ sm_dprintf("milter_headers: %s: %s\n",
h->h_field, h->h_value);
+ if (MilterLogLevel > 21)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s",
+ m->mf_name, h->h_field);
- s = strlen(h->h_field) + 1 +
- strlen(h->h_value) + 1;
+ s = strlen(h->h_field) + 1 + strlen(h->h_value) + 1;
+ if (s < 0)
+ continue;
buf = (char *) xalloc(s);
- snprintf(buf, s, "%s%c%s", h->h_field, '\0', h->h_value);
+ (void) sm_snprintf(buf, s, "%s%c%s",
+ h->h_field, '\0', h->h_value);
/* send it over */
response = milter_send_command(m, SMFIC_HEADER, buf,
s, e, state);
- sm_free(buf);
+ sm_free(buf); /* XXX */
if (m->mf_state == SMFS_ERROR ||
m->mf_state == SMFS_DONE ||
*state != SMFIR_CONTINUE)
break;
}
+ if (MilterLogLevel > 17)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent",
+ m->mf_name);
return response;
}
- /*
+/*
** MILTER_BODY -- send the body to a filter
**
** Parameters:
@@ -2255,19 +2369,23 @@ milter_body(m, e, state)
char buf[MILTER_CHUNK_SIZE];
if (tTd(64, 10))
- dprintf("milter_body\n");
+ sm_dprintf("milter_body\n");
if (bfrewind(e->e_dfp) < 0)
{
ExitStat = EX_IOERR;
*state = SMFIR_TEMPFAIL;
- syserr("milter_body: %s/df%s: rewind error",
- qid_printqueue(e->e_queuedir), e->e_id);
+ syserr("milter_body: %s/%cf%s: rewind error",
+ qid_printqueue(e->e_qgrp, e->e_qdir),
+ DATAFL_LETTER, e->e_id);
return NULL;
}
+ if (MilterLogLevel > 17)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send",
+ m->mf_name);
bp = buf;
- while ((c = getc(e->e_dfp)) != EOF)
+ while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF)
{
/* Change LF to CRLF */
if (c == '\n')
@@ -2314,7 +2432,7 @@ milter_body(m, e, state)
}
/* check for read errors */
- if (ferror(e->e_dfp))
+ if (sm_io_error(e->e_dfp))
{
ExitStat = EX_IOERR;
if (*state == SMFIR_CONTINUE ||
@@ -2323,12 +2441,13 @@ milter_body(m, e, state)
*state = SMFIR_TEMPFAIL;
if (response != NULL)
{
- sm_free(response);
+ sm_free(response); /* XXX */
response = NULL;
}
}
- syserr("milter_body: %s/df%s: read error",
- qid_printqueue(e->e_queuedir), e->e_id);
+ syserr("milter_body: %s/%cf%s: read error",
+ qid_printqueue(e->e_qgrp, e->e_qdir),
+ DATAFL_LETTER, e->e_id);
return response;
}
@@ -2343,6 +2462,9 @@ milter_body(m, e, state)
e, state);
bp = buf;
}
+ if (MilterLogLevel > 17)
+ sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent",
+ m->mf_name);
return response;
}
@@ -2350,7 +2472,7 @@ milter_body(m, e, state)
** Actions
*/
- /*
+/*
** MILTER_ADDHEADER -- Add the supplied header to the message
**
** Parameters:
@@ -2372,20 +2494,20 @@ milter_addheader(response, rlen, e)
HDR *h;
if (tTd(64, 10))
- dprintf("milter_addheader: ");
+ sm_dprintf("milter_addheader: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
- dprintf("NULL response\n");
+ sm_dprintf("NULL response\n");
return;
}
if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (total len)\n");
+ sm_dprintf("didn't follow protocol (total len)\n");
return;
}
@@ -2396,20 +2518,20 @@ milter_addheader(response, rlen, e)
if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (part len)\n");
+ sm_dprintf("didn't follow protocol (part len)\n");
return;
}
if (*response == '\0')
{
if (tTd(64, 10))
- dprintf("empty field name\n");
+ sm_dprintf("empty field name\n");
return;
}
for (h = e->e_header; h != NULL; h = h->h_link)
{
- if (strcasecmp(h->h_field, response) == 0 &&
+ if (sm_strcasecmp(h->h_field, response) == 0 &&
!bitset(H_USER, h->h_flags) &&
!bitset(H_TRACE, h->h_flags))
break;
@@ -2421,19 +2543,26 @@ milter_addheader(response, rlen, e)
if (h != NULL)
{
if (tTd(64, 10))
- dprintf("Replace default header %s value with %s\n",
- h->h_field, val);
+ sm_dprintf("Replace default header %s value with %s\n",
+ h->h_field, val);
+ if (MilterLogLevel > 8)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter change: default header %s value with %s",
+ h->h_field, val);
h->h_value = newstr(val);
h->h_flags |= H_USER;
}
else
{
if (tTd(64, 10))
- dprintf("Add %s: %s\n", response, val);
- addheader(newstr(response), val, H_USER, &e->e_header);
+ sm_dprintf("Add %s: %s\n", response, val);
+ if (MilterLogLevel > 8)
+ sm_syslog(LOG_INFO, e->e_id, "Milter add: header: %s: %s",
+ response, val);
+ addheader(newstr(response), val, H_USER, e);
}
}
- /*
+/*
** MILTER_CHANGEHEADER -- Change the supplied header in the message
**
** Parameters:
@@ -2456,20 +2585,20 @@ milter_changeheader(response, rlen, e)
HDR *h, *sysheader;
if (tTd(64, 10))
- dprintf("milter_changeheader: ");
+ sm_dprintf("milter_changeheader: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
- dprintf("NULL response\n");
+ sm_dprintf("NULL response\n");
return;
}
if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (total len)\n");
+ sm_dprintf("didn't follow protocol (total len)\n");
return;
}
@@ -2484,21 +2613,21 @@ milter_changeheader(response, rlen, e)
strlen(val) + 1 != (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (part len)\n");
+ sm_dprintf("didn't follow protocol (part len)\n");
return;
}
if (*field == '\0')
{
if (tTd(64, 10))
- dprintf("empty field name\n");
+ sm_dprintf("empty field name\n");
return;
}
sysheader = NULL;
for (h = e->e_header; h != NULL; h = h->h_link)
{
- if (strcasecmp(h->h_field, field) == 0)
+ if (sm_strcasecmp(h->h_field, field) == 0)
{
if (bitset(H_USER, h->h_flags) &&
--index <= 0)
@@ -2530,15 +2659,14 @@ milter_changeheader(response, rlen, e)
if (*val == '\0')
{
if (tTd(64, 10))
- dprintf("Delete (noop) %s:\n", field);
+ sm_dprintf("Delete (noop) %s:\n", field);
}
else
{
/* treat modify value with no existing header as add */
if (tTd(64, 10))
- dprintf("Add %s: %s\n", field, val);
-
- addheader(newstr(field), val, H_USER, &e->e_header);
+ sm_dprintf("Add %s: %s\n", field, val);
+ addheader(newstr(field), val, H_USER, e);
}
return;
}
@@ -2547,32 +2675,67 @@ milter_changeheader(response, rlen, e)
{
if (*val == '\0')
{
- dprintf("Delete%s %s: %s\n",
- h == sysheader ? " (default header)" : "",
- field,
- h->h_value == NULL ? "<NULL>" : h->h_value);
+ sm_dprintf("Delete%s %s: %s\n",
+ h == sysheader ? " (default header)" : "",
+ field,
+ h->h_value == NULL ? "<NULL>" : h->h_value);
}
else
{
- dprintf("Change%s %s: from %s to %s\n",
- h == sysheader ? " (default header)" : "",
- field,
- h->h_value == NULL ? "<NULL>" : h->h_value,
- val);
+ sm_dprintf("Change%s %s: from %s to %s\n",
+ h == sysheader ? " (default header)" : "",
+ field,
+ h->h_value == NULL ? "<NULL>" : h->h_value,
+ val);
+ }
+ }
+
+ if (MilterLogLevel > 8)
+ {
+ if (*val == '\0')
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter delete: header %s %s: %s",
+ h == sysheader ? " (default header)" : "",
+ field,
+ h->h_value == NULL ? "<NULL>" : h->h_value);
+ }
+ else
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter change: header %s %s: from %s to %s",
+ h == sysheader ? " (default header)" : "",
+ field,
+ h->h_value == NULL ? "<NULL>" : h->h_value,
+ val);
}
}
if (h != sysheader && h->h_value != NULL)
{
- e->e_msgsize -= strlen(h->h_value);
- sm_free(h->h_value);
+ size_t l;
+
+ l = strlen(h->h_value);
+ if (l > e->e_msgsize)
+ e->e_msgsize = 0;
+ else
+ e->e_msgsize -= l;
+ /* rpool, don't free: sm_free(h->h_value); XXX */
}
if (*val == '\0')
{
/* Remove "Field: " from message size */
if (h != sysheader)
- e->e_msgsize -= strlen(h->h_field) + 2;
+ {
+ size_t l;
+
+ l = strlen(h->h_field) + 2;
+ if (l > e->e_msgsize)
+ e->e_msgsize = 0;
+ else
+ e->e_msgsize -= l;
+ }
h->h_value = NULL;
}
else
@@ -2582,7 +2745,7 @@ milter_changeheader(response, rlen, e)
e->e_msgsize += strlen(h->h_value);
}
}
- /*
+/*
** MILTER_ADDRCPT -- Add the supplied recipient to the message
**
** Parameters:
@@ -2601,13 +2764,13 @@ milter_addrcpt(response, rlen, e)
ENVELOPE *e;
{
if (tTd(64, 10))
- dprintf("milter_addrcpt: ");
+ sm_dprintf("milter_addrcpt: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
- dprintf("NULL response\n");
+ sm_dprintf("NULL response\n");
return;
}
@@ -2615,17 +2778,19 @@ milter_addrcpt(response, rlen, e)
strlen(response) + 1 != (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (total len %d != rlen %d)\n",
- strlen(response), rlen -1);
+ sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
+ (int) strlen(response), (int) (rlen - 1));
return;
}
if (tTd(64, 10))
- dprintf("%s\n", response);
+ sm_dprintf("%s\n", response);
+ if (MilterLogLevel > 8)
+ sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
(void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
return;
}
- /*
+/*
** MILTER_DELRCPT -- Delete the supplied recipient from the message
**
** Parameters:
@@ -2644,13 +2809,13 @@ milter_delrcpt(response, rlen, e)
ENVELOPE *e;
{
if (tTd(64, 10))
- dprintf("milter_delrcpt: ");
+ sm_dprintf("milter_delrcpt: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
- dprintf("NULL response\n");
+ sm_dprintf("NULL response\n");
return;
}
@@ -2658,17 +2823,20 @@ milter_delrcpt(response, rlen, e)
strlen(response) + 1 != (size_t) rlen)
{
if (tTd(64, 10))
- dprintf("didn't follow protocol (total len)\n");
+ sm_dprintf("didn't follow protocol (total len)\n");
return;
}
if (tTd(64, 10))
- dprintf("%s\n", response);
+ sm_dprintf("%s\n", response);
+ if (MilterLogLevel > 8)
+ sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s",
+ response);
(void) removefromlist(response, &e->e_sendqueue, e);
return;
}
- /*
-** MILTER_REPLBODY -- Replace the current df file with new body
+/*
+** MILTER_REPLBODY -- Replace the current data file with new body
**
** Parameters:
** response -- encoded form of new body.
@@ -2691,51 +2859,88 @@ milter_replbody(response, rlen, newfilter, e)
int i;
if (tTd(64, 10))
- dprintf("milter_replbody\n");
+ sm_dprintf("milter_replbody\n");
- /* If a new filter, reset previous character and truncate df */
+ /* If a new filter, reset previous character and truncate data file */
if (newfilter)
{
off_t prevsize = 0;
char dfname[MAXPATHLEN];
- (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
+ (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
+ sizeof dfname);
/* Reset prevchar */
prevchar = '\0';
- /* Get the current df information */
+ /* Get the current data file information */
if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
{
int afd;
struct stat st;
- afd = fileno(e->e_dfp);
+ afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL);
if (afd > 0 && fstat(afd, &st) == 0)
prevsize = st.st_size;
}
- /* truncate current df file */
- if (bftruncate(e->e_dfp) < 0)
+ /* truncate current data file */
+ if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
{
- MILTER_DF_ERROR("milter_reopen_df: bftruncate %s: %s");
- return -1;
+ if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0)
+ {
+ MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s");
+ return -1;
+ }
}
else
{
- if (prevsize > e->e_msgsize)
- e->e_msgsize = 0;
- else
- e->e_msgsize -= prevsize;
+ int err;
+
+# if NOFTRUNCATE
+ /* XXX: Not much we can do except rewind it */
+ err = sm_io_error(e->e_dfp);
+ (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT);
+
+ /*
+ ** Clear error if tried to fflush()
+ ** a read-only file pointer and
+ ** there wasn't a previous error.
+ */
+
+ if (err == 0)
+ sm_io_clearerr(e->e_dfp);
+
+ /* errno is set implicitly by fseek() before return */
+ err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT,
+ 0, SEEK_SET);
+# else /* NOFTRUNCATE */
+ err = ftruncate(sm_io_getinfo(e->e_dfp,
+ SM_IO_WHAT_FD, NULL),
+ 0);
+# endif /* NOFTRUNCATE */
+ if (err < 0)
+ {
+ MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s");
+ return -1;
+ }
}
+
+ if (prevsize > e->e_msgsize)
+ e->e_msgsize = 0;
+ else
+ e->e_msgsize -= prevsize;
}
+ if (newfilter && MilterLogLevel > 8)
+ sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced");
+
if (response == NULL)
{
/* Flush the buffered '\r' */
if (prevchar == '\r')
{
- (void) putc(prevchar, e->e_dfp);
+ (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar);
e->e_msgsize++;
}
return 0;
@@ -2749,7 +2954,8 @@ milter_replbody(response, rlen, newfilter, e)
/* Not CRLF, output prevchar */
if (response[i] != '\n')
{
- (void) putc(prevchar, e->e_dfp);
+ (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT,
+ prevchar);
e->e_msgsize++;
}
prevchar = '\0';
@@ -2772,7 +2978,7 @@ milter_replbody(response, rlen, newfilter, e)
continue;
}
}
- (void) putc(response[i], e->e_dfp);
+ (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]);
e->e_msgsize++;
}
return 0;
@@ -2782,7 +2988,7 @@ milter_replbody(response, rlen, newfilter, e)
** MTA callouts
*/
- /*
+/*
** MILTER_INIT -- open and negotiate with all of the filters
**
** Parameters:
@@ -2790,11 +2996,11 @@ milter_replbody(response, rlen, newfilter, e)
** state -- return state from response.
**
** Returns:
-** none
+** true iff at least one filter is active
*/
/* ARGSUSED */
-void
+bool
milter_init(e, state)
ENVELOPE *e;
char *state;
@@ -2802,14 +3008,22 @@ milter_init(e, state)
int i;
if (tTd(64, 10))
- dprintf("milter_init\n");
+ sm_dprintf("milter_init\n");
*state = SMFIR_CONTINUE;
+ if (InputFilters[0] == NULL)
+ {
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: no active filter");
+ return false;
+ }
+
for (i = 0; InputFilters[i] != NULL; i++)
{
struct milter *m = InputFilters[i];
- m->mf_sock = milter_open(m, FALSE, e);
+ m->mf_sock = milter_open(m, false, e);
if (m->mf_state == SMFS_ERROR)
{
MILTER_CHECK_ERROR(continue);
@@ -2821,14 +3035,26 @@ milter_init(e, state)
m->mf_state == SMFS_ERROR)
{
if (tTd(64, 5))
- dprintf("milter_init(%s): failed to %s\n",
- m->mf_name,
- m->mf_sock < 0 ? "open" : "negotiate");
+ sm_dprintf("milter_init(%s): failed to %s\n",
+ m->mf_name,
+ m->mf_sock < 0 ? "open" :
+ "negotiate");
+ if (MilterLogLevel > 0)
+ sm_syslog(LOG_ERR, e->e_id,
+ "Milter (%s): init failed to %s",
+ m->mf_name,
+ m->mf_sock < 0 ? "open" :
+ "negotiate");
/* if negotation failure, close socket */
- milter_error(m);
+ milter_error(m, e);
MILTER_CHECK_ERROR(continue);
}
+ if (MilterLogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter (%s): init success to %s",
+ m->mf_name,
+ m->mf_sock < 0 ? "open" : "negotiate");
}
/*
@@ -2839,8 +3065,10 @@ milter_init(e, state)
if (*state != SMFIR_CONTINUE)
milter_quit(e);
+
+ return true;
}
- /*
+/*
** MILTER_CONNECT -- send connection info to milter filters
**
** Parameters:
@@ -2861,7 +3089,7 @@ milter_connect(hostname, addr, e, state)
char *state;
{
char family;
- u_short port;
+ unsigned short port;
char *buf, *bp;
char *response;
char *sockinfo = NULL;
@@ -2871,7 +3099,9 @@ milter_connect(hostname, addr, e, state)
# endif /* NETINET6 */
if (tTd(64, 10))
- dprintf("milter_connect(%s)\n", hostname);
+ sm_dprintf("milter_connect(%s)\n", hostname);
+ if (MilterLogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters");
/* gather data */
switch (addr.sa.sa_family)
@@ -2915,7 +3145,7 @@ milter_connect(hostname, addr, e, state)
if (family != SMFIA_UNKNOWN)
s += sizeof(port) + strlen(sockinfo) + 1;
- buf = (char *)xalloc(s);
+ buf = (char *) xalloc(s);
bp = buf;
/* put together data */
@@ -2935,7 +3165,7 @@ milter_connect(hostname, addr, e, state)
response = milter_command(SMFIC_CONNECT, buf, s,
MilterConnectMacros, e, state);
- sm_free(buf);
+ sm_free(buf); /* XXX */
/*
** If this message connection is done for,
@@ -2943,7 +3173,11 @@ milter_connect(hostname, addr, e, state)
*/
if (*state != SMFIR_CONTINUE)
+ {
+ if (MilterLogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending");
milter_quit(e);
+ }
else
milter_per_connection_check(e);
@@ -2962,13 +3196,13 @@ milter_connect(hostname, addr, e, state)
*state = SMFIR_REJECT;
if (response != NULL)
{
- sm_free(response);
+ sm_free(response); /* XXX */
response = NULL;
}
}
return response;
}
- /*
+/*
** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
**
** Parameters:
@@ -2990,9 +3224,9 @@ milter_helo(helo, e, state)
char *response;
if (tTd(64, 10))
- dprintf("milter_helo(%s)\n", helo);
+ sm_dprintf("milter_helo(%s)\n", helo);
- /* HELO/EHLO can come after encryption is negotiated */
+ /* HELO/EHLO can come at any point */
for (i = 0; InputFilters[i] != NULL; i++)
{
struct milter *m = InputFilters[i];
@@ -3016,7 +3250,7 @@ milter_helo(helo, e, state)
milter_per_connection_check(e);
return response;
}
- /*
+/*
** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
**
** Parameters:
@@ -3041,16 +3275,19 @@ milter_envfrom(args, e, state)
if (tTd(64, 10))
{
- dprintf("milter_envfrom:");
+ sm_dprintf("milter_envfrom:");
for (i = 0; args[i] != NULL; i++)
- dprintf(" %s", args[i]);
- dprintf("\n");
+ sm_dprintf(" %s", args[i]);
+ sm_dprintf("\n");
}
/* sanity check */
if (args[0] == NULL)
{
*state = SMFIR_REJECT;
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: reject, no sender");
return NULL;
}
@@ -3077,18 +3314,28 @@ milter_envfrom(args, e, state)
s = 0;
for (i = 0; args[i] != NULL; i++)
s += strlen(args[i]) + 1;
- buf = (char *)xalloc(s);
+
+ if (s < 0)
+ {
+ *state = SMFIR_TEMPFAIL;
+ return NULL;
+ }
+
+ buf = (char *) xalloc(s);
bp = buf;
for (i = 0; args[i] != NULL; i++)
{
- (void) strlcpy(bp, args[i], s - (bp - buf));
+ (void) sm_strlcpy(bp, args[i], s - (bp - buf));
bp += strlen(bp) + 1;
}
+ if (MilterLogLevel > 14)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: senders: %s", buf);
+
/* send it over */
response = milter_command(SMFIC_MAIL, buf, s,
MilterEnvFromMacros, e, state);
- sm_free(buf);
+ sm_free(buf); /* XXX */
/*
** If filter rejects/discards a per message command,
@@ -3097,9 +3344,11 @@ milter_envfrom(args, e, state)
*/
MILTER_CHECK_DONE_MSG();
+ if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders");
return response;
}
- /*
+/*
** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
**
** Parameters:
@@ -3124,16 +3373,18 @@ milter_envrcpt(args, e, state)
if (tTd(64, 10))
{
- dprintf("milter_envrcpt:");
+ sm_dprintf("milter_envrcpt:");
for (i = 0; args[i] != NULL; i++)
- dprintf(" %s", args[i]);
- dprintf("\n");
+ sm_dprintf(" %s", args[i]);
+ sm_dprintf("\n");
}
/* sanity check */
if (args[0] == NULL)
{
*state = SMFIR_REJECT;
+ if (MilterLogLevel > 10)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt");
return NULL;
}
@@ -3141,21 +3392,31 @@ milter_envrcpt(args, e, state)
s = 0;
for (i = 0; args[i] != NULL; i++)
s += strlen(args[i]) + 1;
- buf = (char *)xalloc(s);
+
+ if (s < 0)
+ {
+ *state = SMFIR_TEMPFAIL;
+ return NULL;
+ }
+
+ buf = (char *) xalloc(s);
bp = buf;
for (i = 0; args[i] != NULL; i++)
{
- (void) strlcpy(bp, args[i], s - (bp - buf));
+ (void) sm_strlcpy(bp, args[i], s - (bp - buf));
bp += strlen(bp) + 1;
}
+ if (MilterLogLevel > 14)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf);
+
/* send it over */
response = milter_command(SMFIC_RCPT, buf, s,
MilterEnvRcptMacros, e, state);
- sm_free(buf);
+ sm_free(buf); /* XXX */
return response;
}
- /*
+/*
** MILTER_DATA -- send message headers/body and gather final message results
**
** Parameters:
@@ -3191,10 +3452,10 @@ milter_data(e, state)
ENVELOPE *e;
char *state;
{
- bool replbody = FALSE; /* milter_replbody() called? */
- bool replfailed = FALSE; /* milter_replbody() failed? */
- bool rewind = FALSE; /* rewind df file? */
- bool dfopen = FALSE; /* df open for writing? */
+ bool replbody = false; /* milter_replbody() called? */
+ bool replfailed = false; /* milter_replbody() failed? */
+ bool rewind = false; /* rewind data file? */
+ bool dfopen = false; /* data file open for writing? */
bool newfilter; /* reset on each new filter */
char rcmd;
int i;
@@ -3204,7 +3465,7 @@ milter_data(e, state)
ssize_t rlen;
if (tTd(64, 10))
- dprintf("milter_data\n");
+ sm_dprintf("milter_data\n");
*state = SMFIR_CONTINUE;
@@ -3232,7 +3493,7 @@ milter_data(e, state)
/* Now reset state for later evaluation */
*state = SMFIR_CONTINUE;
- newfilter = TRUE;
+ newfilter = true;
/* previous problem? */
if (m->mf_state == SMFS_ERROR)
@@ -3259,7 +3520,7 @@ milter_data(e, state)
if (!bitset(SMFIP_NOEOH, m->mf_pflags))
{
if (tTd(64, 10))
- dprintf("milter_data: eoh\n");
+ sm_dprintf("milter_data: eoh\n");
/* send it over */
response = milter_send_command(m, SMFIC_EOH, NULL, 0,
@@ -3271,7 +3532,7 @@ milter_data(e, state)
if (!bitset(SMFIP_NOBODY, m->mf_pflags) &&
e->e_dfp != NULL)
{
- rewind = TRUE;
+ rewind = true;
response = milter_body(m, e, state);
MILTER_CHECK_RESULTS();
}
@@ -3291,13 +3552,13 @@ milter_data(e, state)
curtime() - eomsent >= m->mf_timeout[SMFTO_EOM])
{
if (tTd(64, 5))
- dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
+ sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
m->mf_name);
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
- "milter_data(%s): EOM ACK/NAK timeout\n",
+ "milter_data(%s): EOM ACK/NAK timeout",
m->mf_name);
- milter_error(m);
+ milter_error(m, e);
MILTER_CHECK_ERROR(continue);
break;
}
@@ -3308,20 +3569,40 @@ milter_data(e, state)
break;
if (tTd(64, 10))
- dprintf("milter_data(%s): state %c\n",
- m->mf_name, (char) rcmd);
+ sm_dprintf("milter_data(%s): state %c\n",
+ m->mf_name, (char) rcmd);
switch (rcmd)
{
case SMFIR_REPLYCODE:
MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected");
+ if (MilterLogLevel > 12)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s",
+ m->mf_name, response);
+ *state = rcmd;
+ m->mf_state = SMFS_DONE;
+ break;
+
+ case SMFIR_REJECT: /* log msg at end of function */
+ if (MilterLogLevel > 12)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject",
+ m->mf_name);
*state = rcmd;
m->mf_state = SMFS_DONE;
break;
- case SMFIR_REJECT:
case SMFIR_DISCARD:
+ if (MilterLogLevel > 12)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard",
+ m->mf_name);
+ *state = rcmd;
+ m->mf_state = SMFS_DONE;
+ break;
+
case SMFIR_TEMPFAIL:
+ if (MilterLogLevel > 12)
+ sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail",
+ m->mf_name);
*state = rcmd;
m->mf_state = SMFS_DONE;
break;
@@ -3339,10 +3620,32 @@ milter_data(e, state)
case SMFIR_PROGRESS:
break;
+# if _FFR_QUARANTINE
+ case SMFIR_QUARANTINE:
+ if (!bitset(SMFIF_QUARANTINE, m->mf_fflags))
+ {
+ if (MilterLogLevel > 9)
+ sm_syslog(LOG_WARNING, e->e_id,
+ "milter_data(%s): lied about quarantining, honoring request anyway",
+ m->mf_name);
+ }
+ if (response == NULL)
+ response = newstr("");
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "milter=%s, quarantine=%s",
+ m->mf_name, response);
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
+ response);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
+ break;
+# endif /* _FFR_QUARANTINE */
+
case SMFIR_ADDHEADER:
if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
{
- if (LogLevel > 9)
+ if (MilterLogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"milter_data(%s): lied about adding headers, honoring request anyway",
m->mf_name);
@@ -3353,7 +3656,7 @@ milter_data(e, state)
case SMFIR_CHGHEADER:
if (!bitset(SMFIF_CHGHDRS, m->mf_fflags))
{
- if (LogLevel > 9)
+ if (MilterLogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"milter_data(%s): lied about changing headers, honoring request anyway",
m->mf_name);
@@ -3364,7 +3667,7 @@ milter_data(e, state)
case SMFIR_ADDRCPT:
if (!bitset(SMFIF_ADDRCPT, m->mf_fflags))
{
- if (LogLevel > 9)
+ if (MilterLogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"milter_data(%s) lied about adding recipients, honoring request anyway",
m->mf_name);
@@ -3375,7 +3678,7 @@ milter_data(e, state)
case SMFIR_DELRCPT:
if (!bitset(SMFIF_DELRCPT, m->mf_fflags))
{
- if (LogLevel > 9)
+ if (MilterLogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"milter_data(%s): lied about removing recipients, honoring request anyway",
m->mf_name);
@@ -3386,11 +3689,11 @@ milter_data(e, state)
case SMFIR_REPLBODY:
if (!bitset(SMFIF_MODBODY, m->mf_fflags))
{
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"milter_data(%s): lied about replacing body, rejecting request and tempfailing message",
m->mf_name);
- replfailed = TRUE;
+ replfailed = true;
break;
}
@@ -3402,33 +3705,32 @@ milter_data(e, state)
{
if (milter_reopen_df(e) < 0)
{
- replfailed = TRUE;
+ replfailed = true;
break;
}
- dfopen = TRUE;
- rewind = TRUE;
+ dfopen = true;
+ rewind = true;
}
if (milter_replbody(response, rlen,
newfilter, e) < 0)
- replfailed = TRUE;
- newfilter = FALSE;
- replbody = TRUE;
+ replfailed = true;
+ newfilter = false;
+ replbody = true;
break;
default:
/* Invalid response to command */
- if (LogLevel > 0)
+ if (MilterLogLevel > 0)
sm_syslog(LOG_ERR, e->e_id,
"milter_data(%s): returned bogus response %c",
m->mf_name, rcmd);
- milter_error(m);
+ milter_error(m, e);
break;
}
- if (rcmd != SMFIR_REPLYCODE &&
- response != NULL)
+ if (rcmd != SMFIR_REPLYCODE && response != NULL)
{
- sm_free(response);
+ sm_free(response); /* XXX */
response = NULL;
}
@@ -3440,7 +3742,7 @@ milter_data(e, state)
{
/* flush possible buffered character */
milter_replbody(NULL, 0, !replbody, e);
- replbody = FALSE;
+ replbody = false;
}
if (m->mf_state == SMFS_ERROR)
@@ -3458,21 +3760,17 @@ finishup:
*state == SMFIR_ACCEPT)
{
*state = SMFIR_TEMPFAIL;
- if (response != NULL)
- {
- sm_free(response);
- response = NULL;
- }
+ SM_FREE_CLR(response);
}
if (dfopen)
{
- (void) fclose(e->e_dfp);
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
e->e_dfp = NULL;
e->e_flags &= ~EF_HAS_DF;
- dfopen = FALSE;
+ dfopen = false;
}
- rewind = FALSE;
+ rewind = false;
}
if ((dfopen && milter_reset_df(e) < 0) ||
@@ -3490,21 +3788,21 @@ finishup:
*state == SMFIR_ACCEPT)
{
*state = SMFIR_TEMPFAIL;
- if (response != NULL)
- {
- sm_free(response);
- response = NULL;
- }
+ SM_FREE_CLR(response);
}
errno = save_errno;
- syserr("milter_data: %s/df%s: read error",
- qid_printqueue(e->e_queuedir), e->e_id);
+ syserr("milter_data: %s/%cf%s: read error",
+ qid_printqueue(e->e_qgrp, e->e_qdir),
+ DATAFL_LETTER, e->e_id);
}
+
MILTER_CHECK_DONE_MSG();
+ if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
+ sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data");
return response;
}
- /*
+/*
** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s)
**
** Parameters:
@@ -3521,12 +3819,12 @@ milter_quit(e)
int i;
if (tTd(64, 10))
- dprintf("milter_quit\n");
+ sm_dprintf("milter_quit(%s)\n", e->e_id);
for (i = 0; InputFilters[i] != NULL; i++)
milter_quit_filter(InputFilters[i], e);
}
- /*
+/*
** MILTER_ABORT -- informs the filter(s) that we are aborting current message
**
** Parameters:
@@ -3543,7 +3841,7 @@ milter_abort(e)
int i;
if (tTd(64, 10))
- dprintf("milter_abort\n");
+ sm_dprintf("milter_abort\n");
for (i = 0; InputFilters[i] != NULL; i++)
{
@@ -3556,4 +3854,4 @@ milter_abort(e)
milter_abort_filter(m, e);
}
}
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
diff --git a/contrib/sendmail/src/mime.c b/contrib/sendmail/src/mime.c
index 2ba078f..f5980bb 100644
--- a/contrib/sendmail/src/mime.c
+++ b/contrib/sendmail/src/mime.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1994
@@ -14,15 +14,7 @@
#include <sendmail.h>
#include <string.h>
-#ifndef lint
-static char id[] = "@(#)$Id: mime.c,v 8.94.16.3 2000/10/09 02:46:10 gshapiro Exp $";
-#endif /* ! lint */
-
-static int isboundary __P((char *, char **));
-static int mimeboundary __P((char *, char **));
-static int mime_fromqp __P((u_char *, u_char **, int, int));
-static int mime_getchar __P((FILE *, char **, int *));
-static int mime_getchar_crlf __P((FILE *, char **, int *));
+SM_RCSID("@(#)$Id: mime.c,v 8.125 2001/09/11 04:05:15 gshapiro Exp $")
/*
** MIME support.
@@ -42,6 +34,10 @@ static int mime_getchar_crlf __P((FILE *, char **, int *));
*/
#if MIME8TO7
+static int isboundary __P((char *, char **));
+static int mimeboundary __P((char *, char **));
+static int mime_getchar __P((SM_FILE_T *, char **, int *));
+static int mime_getchar_crlf __P((SM_FILE_T *, char **, int *));
/* character set for hex and base64 encoding */
static char Base16Code[] = "0123456789ABCDEF";
@@ -60,7 +56,7 @@ static char *MimeBoundaryNames[] =
static bool MapNLtoCRLF;
- /*
+/*
** MIME8TO7 -- output 8 bit body in 7 bit format
**
** The header has already been output -- this has to do the
@@ -113,26 +109,26 @@ mime8to7(mci, header, e, boundaries, flags)
char **pvp;
int argc = 0;
char *bp;
- bool use_qp = FALSE;
+ bool use_qp = false;
struct args argv[MAXMIMEARGS];
char bbuf[128];
char buf[MAXLINE];
char pvpbuf[MAXLINE];
- extern u_char MimeTokenTab[256];
+ extern unsigned char MimeTokenTab[256];
if (tTd(43, 1))
{
- dprintf("mime8to7: flags = %x, boundaries =", flags);
+ sm_dprintf("mime8to7: flags = %x, boundaries =", flags);
if (boundaries[0] == NULL)
- dprintf(" <none>");
+ sm_dprintf(" <none>");
else
{
for (i = 0; boundaries[i] != NULL; i++)
- dprintf(" %s", boundaries[i]);
+ sm_dprintf(" %s", boundaries[i]);
}
- dprintf("\n");
+ sm_dprintf("\n");
}
- MapNLtoCRLF = TRUE;
+ MapNLtoCRLF = true;
p = hvalue("Content-Transfer-Encoding", header);
if (p == NULL ||
(pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
@@ -144,7 +140,7 @@ mime8to7(mci, header, e, boundaries, flags)
else
{
cataddr(pvp, NULL, buf, sizeof buf, '\0');
- cte = newstr(buf);
+ cte = sm_rpool_strdup_x(e->e_rpool, buf);
}
type = subtype = NULL;
@@ -164,7 +160,7 @@ mime8to7(mci, header, e, boundaries, flags)
if (tTd(43, 40))
{
for (i = 0; pvp[i] != NULL; i++)
- dprintf("pvp[%d] = \"%s\"\n", i, pvp[i]);
+ sm_dprintf("pvp[%d] = \"%s\"\n", i, pvp[i]);
}
type = *pvp++;
if (*pvp != NULL && strcmp(*pvp, "/") == 0 &&
@@ -222,16 +218,16 @@ mime8to7(mci, header, e, boundaries, flags)
** just copy it through.
*/
- snprintf(buf, sizeof buf, "%.100s/%.100s", type, subtype);
+ (void) sm_snprintf(buf, sizeof buf, "%.100s/%.100s", type, subtype);
if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e')))
flags |= M87F_NO8BIT;
# ifdef USE_B_CLASS
if (wordinclass(buf, 'b') || wordinclass(type, 'b'))
- MapNLtoCRLF = FALSE;
+ MapNLtoCRLF = false;
# endif /* USE_B_CLASS */
if (wordinclass(buf, 'q') || wordinclass(type, 'q'))
- use_qp = TRUE;
+ use_qp = true;
/*
** Multipart requires special processing.
@@ -239,16 +235,16 @@ mime8to7(mci, header, e, boundaries, flags)
** Do a recursive descent into the message.
*/
- if (strcasecmp(type, "multipart") == 0 &&
+ if (sm_strcasecmp(type, "multipart") == 0 &&
(!bitset(M87F_NO8BIT, flags) || bitset(M87F_NO8TO7, flags)))
{
- if (strcasecmp(subtype, "digest") == 0)
+ if (sm_strcasecmp(subtype, "digest") == 0)
flags |= M87F_DIGEST;
for (i = 0; i < argc; i++)
{
- if (strcasecmp(argv[i].a_field, "boundary") == 0)
+ if (sm_strcasecmp(argv[i].a_field, "boundary") == 0)
break;
}
if (i >= argc || argv[i].a_value == NULL)
@@ -265,7 +261,7 @@ mime8to7(mci, header, e, boundaries, flags)
p = argv[i].a_value;
stripquotes(p);
}
- if (strlcpy(bbuf, p, sizeof bbuf) >= sizeof bbuf)
+ if (sm_strlcpy(bbuf, p, sizeof bbuf) >= sizeof bbuf)
{
usrerr("mime8to7: multipart boundary \"%s\" too long",
p);
@@ -275,7 +271,8 @@ mime8to7(mci, header, e, boundaries, flags)
}
if (tTd(43, 1))
- dprintf("mime8to7: multipart boundary \"%s\"\n", bbuf);
+ sm_dprintf("mime8to7: multipart boundary \"%s\"\n",
+ bbuf);
for (i = 0; i < MAXMIMENESTING; i++)
{
if (boundaries[i] == NULL)
@@ -299,26 +296,28 @@ mime8to7(mci, header, e, boundaries, flags)
putline("", mci);
mci->mci_flags &= ~MCIF_INHEADER;
bt = MBT_FINAL;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
{
bt = mimeboundary(buf, boundaries);
if (bt != MBT_NOTSEP)
break;
- putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT);
+ putxline(buf, strlen(buf), mci,
+ PXLF_MAPFROM|PXLF_STRIP8BIT);
if (tTd(43, 99))
- dprintf(" ...%s", buf);
+ sm_dprintf(" ...%s", buf);
}
- if (feof(e->e_dfp))
+ if (sm_io_eof(e->e_dfp))
bt = MBT_FINAL;
while (bt != MBT_FINAL)
{
auto HDR *hdr = NULL;
- snprintf(buf, sizeof buf, "--%s", bbuf);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", bbuf);
putline(buf, mci);
if (tTd(43, 35))
- dprintf(" ...%s\n", buf);
- collect(e->e_dfp, FALSE, &hdr, e);
+ sm_dprintf(" ...%s\n", buf);
+ collect(e->e_dfp, false, &hdr, e);
if (tTd(43, 101))
putline("+++after collect", mci);
putheader(mci, hdr, e, flags);
@@ -326,27 +325,29 @@ mime8to7(mci, header, e, boundaries, flags)
putline("+++after putheader", mci);
bt = mime8to7(mci, hdr, e, boundaries, flags);
}
- snprintf(buf, sizeof buf, "--%s--", bbuf);
+ (void) sm_strlcpyn(buf, sizeof buf, 3, "--", bbuf, "--");
putline(buf, mci);
if (tTd(43, 35))
- dprintf(" ...%s\n", buf);
+ sm_dprintf(" ...%s\n", buf);
boundaries[i] = NULL;
mci->mci_flags &= ~MCIF_INMIME;
/* skip the late "comment" epilogue */
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
{
bt = mimeboundary(buf, boundaries);
if (bt != MBT_NOTSEP)
break;
- putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT);
+ putxline(buf, strlen(buf), mci,
+ PXLF_MAPFROM|PXLF_STRIP8BIT);
if (tTd(43, 99))
- dprintf(" ...%s", buf);
+ sm_dprintf(" ...%s", buf);
}
- if (feof(e->e_dfp))
+ if (sm_io_eof(e->e_dfp))
bt = MBT_FINAL;
if (tTd(43, 3))
- dprintf("\t\t\tmime8to7=>%s (multipart)\n",
+ sm_dprintf("\t\t\tmime8to7=>%s (multipart)\n",
MimeBoundaryNames[bt]);
return bt;
}
@@ -357,7 +358,7 @@ mime8to7(mci, header, e, boundaries, flags)
** Class 's' is predefined to have "rfc822" only.
*/
- if (strcasecmp(type, "message") == 0)
+ if (sm_strcasecmp(type, "message") == 0)
{
if (!wordinclass(subtype, 's'))
{
@@ -370,7 +371,7 @@ mime8to7(mci, header, e, boundaries, flags)
putline("", mci);
mci->mci_flags |= MCIF_INMIME;
- collect(e->e_dfp, FALSE, &hdr, e);
+ collect(e->e_dfp, false, &hdr, e);
if (tTd(43, 101))
putline("+++after collect", mci);
putheader(mci, hdr, e, flags);
@@ -396,12 +397,14 @@ mime8to7(mci, header, e, boundaries, flags)
if (!bitset(M87F_NO8BIT|M87F_NO8TO7, flags))
{
/* remember where we were */
- offset = ftell(e->e_dfp);
+ offset = sm_io_tell(e->e_dfp, SM_TIME_DEFAULT);
if (offset == -1)
- syserr("mime8to7: cannot ftell on df%s", e->e_id);
+ syserr("mime8to7: cannot sm_io_tell on %cf%s",
+ DATAFL_LETTER, e->e_id);
/* do a scan of this body type to count character types */
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
{
if (mimeboundary(buf, boundaries) != MBT_NOTSEP)
break;
@@ -426,10 +429,11 @@ mime8to7(mci, header, e, boundaries, flags)
/* return to the original offset for processing */
/* XXX use relative seeks to handle >31 bit file sizes? */
- if (fseek(e->e_dfp, offset, SEEK_SET) < 0)
- syserr("mime8to7: cannot fseek on df%s", e->e_id);
+ if (sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, offset, SEEK_SET) < 0)
+ syserr("mime8to7: cannot sm_io_fseek on %cf%s",
+ DATAFL_LETTER, e->e_id);
else
- clearerr(e->e_dfp);
+ sm_io_clearerr(e->e_dfp);
}
/*
@@ -442,13 +446,13 @@ mime8to7(mci, header, e, boundaries, flags)
if (tTd(43, 8))
{
- dprintf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n",
+ sm_dprintf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n",
(long) sectionhighbits, (long) sectionsize,
cte == NULL ? "[none]" : cte,
type == NULL ? "[none]" : type,
subtype == NULL ? "[none]" : subtype);
}
- if (cte != NULL && strcasecmp(cte, "binary") == 0)
+ if (cte != NULL && sm_strcasecmp(cte, "binary") == 0)
sectionsize = sectionhighbits;
linelen = 0;
bp = buf;
@@ -468,22 +472,23 @@ mime8to7(mci, header, e, boundaries, flags)
** situation.
*/
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Content-Transfer-Encoding: %.200s", cte);
putline(buf, mci);
if (tTd(43, 36))
- dprintf(" ...%s\n", buf);
+ sm_dprintf(" ...%s\n", buf);
}
putline("", mci);
mci->mci_flags &= ~MCIF_INHEADER;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
{
bt = mimeboundary(buf, boundaries);
if (bt != MBT_NOTSEP)
break;
putline(buf, mci);
}
- if (feof(e->e_dfp))
+ if (sm_io_eof(e->e_dfp))
bt = MBT_FINAL;
}
else if (!MapNLtoCRLF ||
@@ -493,15 +498,16 @@ mime8to7(mci, header, e, boundaries, flags)
int c1, c2;
if (tTd(43, 36))
- dprintf(" ...Content-Transfer-Encoding: base64\n");
+ sm_dprintf(" ...Content-Transfer-Encoding: base64\n");
putline("Content-Transfer-Encoding: base64", mci);
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"X-MIME-Autoconverted: from 8bit to base64 by %s id %s",
MyHostName, e->e_id);
putline(buf, mci);
putline("", mci);
mci->mci_flags &= ~MCIF_INHEADER;
- while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF)
+ while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) !=
+ SM_IO_EOF)
{
if (linelen > 71)
{
@@ -514,7 +520,7 @@ mime8to7(mci, header, e, boundaries, flags)
*bp++ = Base64Code[(c1 >> 2)];
c1 = (c1 & 0x03) << 4;
c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
- if (c2 == EOF)
+ if (c2 == SM_IO_EOF)
{
*bp++ = Base64Code[c1];
*bp++ = '=';
@@ -525,7 +531,7 @@ mime8to7(mci, header, e, boundaries, flags)
*bp++ = Base64Code[c1];
c1 = (c2 & 0x0f) << 2;
c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
- if (c2 == EOF)
+ if (c2 == SM_IO_EOF)
{
*bp++ = Base64Code[c1];
*bp++ = '=';
@@ -558,9 +564,9 @@ mime8to7(mci, header, e, boundaries, flags)
setbitn(*p, badchars);
if (tTd(43, 36))
- dprintf(" ...Content-Transfer-Encoding: quoted-printable\n");
+ sm_dprintf(" ...Content-Transfer-Encoding: quoted-printable\n");
putline("Content-Transfer-Encoding: quoted-printable", mci);
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s",
MyHostName, e->e_id);
putline(buf, mci);
@@ -568,7 +574,8 @@ mime8to7(mci, header, e, boundaries, flags)
mci->mci_flags &= ~MCIF_INHEADER;
fromstate = 0;
c2 = '\n';
- while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF)
+ while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) !=
+ SM_IO_EOF)
{
if (c1 == '\n')
{
@@ -657,18 +664,18 @@ mime8to7(mci, header, e, boundaries, flags)
}
if (tTd(43, 3))
- dprintf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]);
+ sm_dprintf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]);
return bt;
}
- /*
+/*
** MIME_GETCHAR -- get a character for MIME processing
**
-** Treats boundaries as EOF.
+** Treats boundaries as SM_IO_EOF.
**
** Parameters:
** fp -- the input file.
** boundaries -- the current MIME boundaries.
-** btp -- if the return value is EOF, *btp is set to
+** btp -- if the return value is SM_IO_EOF, *btp is set to
** the type of the boundary.
**
** Returns:
@@ -677,16 +684,16 @@ mime8to7(mci, header, e, boundaries, flags)
static int
mime_getchar(fp, boundaries, btp)
- register FILE *fp;
+ register SM_FILE_T *fp;
char **boundaries;
int *btp;
{
int c;
- static u_char *bp = NULL;
+ static unsigned char *bp = NULL;
static int buflen = 0;
- static bool atbol = TRUE; /* at beginning of line */
- static int bt = MBT_SYNTAX; /* boundary type of next EOF */
- static u_char buf[128]; /* need not be a full line */
+ static bool atbol = true; /* at beginning of line */
+ static int bt = MBT_SYNTAX; /* boundary type of next SM_IO_EOF */
+ static unsigned char buf[128]; /* need not be a full line */
int start = 0; /* indicates position of - in buffer */
if (buflen == 1 && *bp == '\n')
@@ -700,33 +707,33 @@ mime_getchar(fp, boundaries, btp)
return *bp++;
}
else
- c = getc(fp);
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
bp = buf;
buflen = 0;
if (c == '\n')
{
/* might be part of a MIME boundary */
*bp++ = c;
- atbol = TRUE;
- c = getc(fp);
+ atbol = true;
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
if (c == '\n')
{
- (void) ungetc(c, fp);
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
return c;
}
start = 1;
}
- if (c != EOF)
+ if (c != SM_IO_EOF)
*bp++ = c;
else
bt = MBT_FINAL;
if (atbol && c == '-')
{
/* check for a message boundary */
- c = getc(fp);
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
if (c != '-')
{
- if (c != EOF)
+ if (c != SM_IO_EOF)
*bp++ = c;
else
bt = MBT_FINAL;
@@ -738,11 +745,12 @@ mime_getchar(fp, boundaries, btp)
/* got "--", now check for rest of separator */
*bp++ = '-';
while (bp < &buf[sizeof buf - 2] &&
- (c = getc(fp)) != EOF && c != '\n')
+ (c = sm_io_getc(fp, SM_TIME_DEFAULT)) != SM_IO_EOF &&
+ c != '\n')
{
*bp++ = c;
}
- *bp = '\0';
+ *bp = '\0'; /* XXX simply cut off? */
bt = mimeboundary((char *) &buf[start], boundaries);
switch (bt)
{
@@ -751,11 +759,11 @@ mime_getchar(fp, boundaries, btp)
/* we have a message boundary */
buflen = 0;
*btp = bt;
- return EOF;
+ return SM_IO_EOF;
}
atbol = c == '\n';
- if (c != EOF)
+ if (c != SM_IO_EOF)
*bp++ = c;
}
@@ -763,18 +771,18 @@ mime_getchar(fp, boundaries, btp)
if (buflen < 0)
{
*btp = bt;
- return EOF;
+ return SM_IO_EOF;
}
bp = buf;
return *bp++;
}
- /*
+/*
** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF
**
** Parameters:
** fp -- the input file.
** boundaries -- the current MIME boundaries.
-** btp -- if the return value is EOF, *btp is set to
+** btp -- if the return value is SM_IO_EOF, *btp is set to
** the type of the boundary.
**
** Returns:
@@ -783,27 +791,27 @@ mime_getchar(fp, boundaries, btp)
static int
mime_getchar_crlf(fp, boundaries, btp)
- register FILE *fp;
+ register SM_FILE_T *fp;
char **boundaries;
int *btp;
{
- static bool sendlf = FALSE;
+ static bool sendlf = false;
int c;
if (sendlf)
{
- sendlf = FALSE;
+ sendlf = false;
return '\n';
}
c = mime_getchar(fp, boundaries, btp);
if (c == '\n' && MapNLtoCRLF)
{
- sendlf = TRUE;
+ sendlf = true;
return '\r';
}
return c;
}
- /*
+/*
** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type
**
** Parameters:
@@ -840,7 +848,7 @@ mimeboundary(line, boundaries)
line[i] = '\0';
if (tTd(43, 5))
- dprintf("mimeboundary: line=\"%s\"... ", line);
+ sm_dprintf("mimeboundary: line=\"%s\"... ", line);
/* check for this as an intermediate boundary */
if (isboundary(&line[2], boundaries) >= 0)
@@ -856,10 +864,10 @@ mimeboundary(line, boundaries)
line[i] = savec;
if (tTd(43, 5))
- dprintf("%s\n", MimeBoundaryNames[type]);
+ sm_dprintf("%s\n", MimeBoundaryNames[type]);
return type;
}
- /*
+/*
** DEFCHARSET -- return default character set for message
**
** The first choice for character set is for the mailer
@@ -886,7 +894,7 @@ defcharset(e)
return DefaultCharSet;
return "unknown-8bit";
}
- /*
+/*
** ISBOUNDARY -- is a given string a currently valid boundary?
**
** Parameters:
@@ -914,8 +922,9 @@ isboundary(line, boundaries)
return -1;
}
#endif /* MIME8TO7 */
-
+
#if MIME7TO8
+static int mime_fromqp __P((unsigned char *, unsigned char **, int, int));
/*
** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format
@@ -965,11 +974,11 @@ mime7to8(mci, header, e)
register char *p;
char *cte;
char **pvp;
- u_char *fbufp;
+ unsigned char *fbufp;
char buf[MAXLINE];
- u_char fbuf[MAXLINE + 1];
+ unsigned char fbuf[MAXLINE + 1];
char pvpbuf[MAXLINE];
- extern u_char MimeTokenTab[256];
+ extern unsigned char MimeTokenTab[256];
p = hvalue("Content-Transfer-Encoding", header);
if (p == NULL ||
@@ -986,22 +995,23 @@ mime7to8(mci, header, e)
/* cheap failsafe algorithm -- should work on text/plain */
if (p != NULL)
{
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Content-Transfer-Encoding: %s", p);
putline(buf, mci);
}
putline("", mci);
mci->mci_flags &= ~MCIF_INHEADER;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
putline(buf, mci);
return;
}
cataddr(pvp, NULL, buf, sizeof buf, '\0');
- cte = newstr(buf);
+ cte = sm_rpool_strdup_x(e->e_rpool, buf);
mci->mci_flags |= MCIF_INHEADER;
putline("Content-Transfer-Encoding: 8bit", mci);
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"X-MIME-Autoconverted: from %.200s to 8bit by %s id %s",
cte, MyHostName, e->e_id);
putline(buf, mci);
@@ -1014,35 +1024,36 @@ mime7to8(mci, header, e)
** it is not base64.
*/
- if (strcasecmp(cte, "base64") == 0)
+ if (sm_strcasecmp(cte, "base64") == 0)
{
int c1, c2, c3, c4;
fbufp = fbuf;
- while ((c1 = fgetc(e->e_dfp)) != EOF)
+ while ((c1 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) !=
+ SM_IO_EOF)
{
if (isascii(c1) && isspace(c1))
continue;
do
{
- c2 = fgetc(e->e_dfp);
+ c2 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
} while (isascii(c2) && isspace(c2));
- if (c2 == EOF)
+ if (c2 == SM_IO_EOF)
break;
do
{
- c3 = fgetc(e->e_dfp);
+ c3 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
} while (isascii(c3) && isspace(c3));
- if (c3 == EOF)
+ if (c3 == SM_IO_EOF)
break;
do
{
- c4 = fgetc(e->e_dfp);
+ c4 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT);
} while (isascii(c4) && isspace(c4));
- if (c4 == EOF)
+ if (c4 == SM_IO_EOF)
break;
if (c1 == '=' || c2 == '=')
@@ -1092,9 +1103,10 @@ mime7to8(mci, header, e)
{
/* quoted-printable */
fbufp = fbuf;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
{
- if (mime_fromqp((u_char *) buf, &fbufp, 0,
+ if (mime_fromqp((unsigned char *) buf, &fbufp, 0,
&fbuf[MAXLINE] - fbufp) == 0)
continue;
@@ -1112,14 +1124,14 @@ mime7to8(mci, header, e)
putxline((char *) fbuf, fbufp - fbuf, mci, PXLF_MAPFROM);
}
if (tTd(43, 3))
- dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte);
+ sm_dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte);
}
- /*
+/*
** The following is based on Borenstein's "codes.c" module, with simplifying
** changes as we do not deal with multipart, and to do the translation in-core,
** with an attempt to prevent overrun of output buffers.
**
-** What is needed here are changes to defned this code better against
+** What is needed here are changes to defend this code better against
** bad encodings. Questionable to always return 0xFF for bad mappings.
*/
@@ -1139,14 +1151,17 @@ static char index_hex[128] =
static int
mime_fromqp(infile, outfile, state, maxlen)
- u_char *infile;
- u_char **outfile;
+ unsigned char *infile;
+ unsigned char **outfile;
int state; /* Decoding body (0) or header (1) */
int maxlen; /* Max # of chars allowed in outfile */
{
int c1, c2;
int nchar = 0;
+ if (maxlen < 0)
+ return 0;
+
while ((c1 = *infile++) != '\0')
{
if (c1 == '=')
diff --git a/contrib/sendmail/src/newaliases.1 b/contrib/sendmail/src/newaliases.1
index 5a7c916..20fd0e7 100644
--- a/contrib/sendmail/src/newaliases.1
+++ b/contrib/sendmail/src/newaliases.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
.\" Copyright (c) 1985, 1990, 1993
@@ -9,9 +9,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: newaliases.1,v 8.15.28.1 2000/12/14 23:08:15 gshapiro Exp $
+.\" $Id: newaliases.1,v 8.19 2001/10/10 03:23:17 ca Exp $
.\"
-.TH NEWALIASES 1 "$Date: 2000/12/14 23:08:15 $"
+.TH NEWALIASES 1 "$Date: 2001/10/10 03:23:17 $"
.SH NAME
newaliases
\- rebuild the data base for the mail aliases file
@@ -29,6 +29,15 @@ is identical to ``sendmail -bi''.
The
.B newaliases
utility exits 0 on success, and >0 if an error occurs.
+.PP
+Notice: do
+.B not
+use
+.B makemap
+to create the aliases data base, because
+.B newaliases
+puts a special token into the data base that is required by
+.B sendmail.
.SH FILES
.TP 2i
/etc/mail/aliases
diff --git a/contrib/sendmail/src/parseaddr.c b/contrib/sendmail/src/parseaddr.c
index 9b51c73..c456506 100644
--- a/contrib/sendmail/src/parseaddr.c
+++ b/contrib/sendmail/src/parseaddr.c
@@ -11,16 +11,15 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: parseaddr.c,v 8.234.4.13 2001/08/14 23:08:13 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-static void allocaddr __P((ADDRESS *, int, char *));
+SM_RCSID("@(#)$Id: parseaddr.c,v 8.349 2001/12/12 02:50:22 gshapiro Exp $")
+
+static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *));
static int callsubr __P((char**, int, ENVELOPE *));
static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
+static bool hasctrlchar __P((register char *, bool));
/*
** PARSEADDR -- Parse an address
@@ -39,7 +38,7 @@ static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
** Parameters:
** addr -- the address to parse.
** a -- a pointer to the address descriptor buffer.
-** If NULL, a header will be created.
+** If NULL, an address will be created.
** flags -- describe detail for parsing. See RF_ definitions
** in sendmail.h.
** delim -- the character to terminate the address, passed
@@ -47,6 +46,8 @@ static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
** delimptr -- if non-NULL, set to the location of the
** delim character that was found.
** e -- the envelope that will contain this address.
+** isrcpt -- true if the address denotes a recipient; false
+** indicates a sender.
**
** Returns:
** A pointer to the address descriptor header (`a' if
@@ -54,22 +55,23 @@ static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
** NULL on error.
**
** Side Effects:
-** none
+** e->e_to = addr
*/
/* following delimiters are inherent to the internal algorithms */
#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
ADDRESS *
-parseaddr(addr, a, flags, delim, delimptr, e)
+parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
char *addr;
register ADDRESS *a;
int flags;
int delim;
char **delimptr;
register ENVELOPE *e;
+ bool isrcpt;
{
- register char **pvp;
+ char **pvp;
auto char *delimptrbuf;
bool qup;
char pvpbuf[PSBUFSIZE];
@@ -80,7 +82,7 @@ parseaddr(addr, a, flags, delim, delimptr, e)
e->e_to = addr;
if (tTd(20, 1))
- dprintf("\n--parseaddr(%s)\n", addr);
+ sm_dprintf("\n--parseaddr(%s)\n", addr);
if (delimptr == NULL)
delimptr = &delimptrbuf;
@@ -89,14 +91,14 @@ parseaddr(addr, a, flags, delim, delimptr, e)
if (pvp == NULL)
{
if (tTd(20, 1))
- dprintf("parseaddr-->NULL\n");
+ sm_dprintf("parseaddr-->NULL\n");
return NULL;
}
- if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
+ if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt))
{
if (tTd(20, 1))
- dprintf("parseaddr-->bad address\n");
+ sm_dprintf("parseaddr-->bad address\n");
return NULL;
}
@@ -114,7 +116,7 @@ parseaddr(addr, a, flags, delim, delimptr, e)
if (savec != '\0')
**delimptr = '\0';
- e->e_to = addr = newstr(addr);
+ e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr);
if (savec != '\0')
**delimptr = savec;
}
@@ -124,12 +126,11 @@ parseaddr(addr, a, flags, delim, delimptr, e)
** Ruleset 0 does basic parsing. It must resolve.
*/
- qup = FALSE;
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
- qup = TRUE;
- if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
- qup = TRUE;
-
+ qup = false;
+ if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
+ qup = true;
+ if (REWRITE(pvp, 0, e) == EX_TEMPFAIL)
+ qup = true;
/*
** Build canonical address from pvp.
@@ -137,16 +138,57 @@ parseaddr(addr, a, flags, delim, delimptr, e)
a = buildaddr(pvp, a, flags, e);
+ if (hasctrlchar(a->q_user, isrcpt))
+ {
+ if (tTd(20, 1))
+ sm_dprintf("parseaddr-->bad q_user\n");
+ return NULL;
+ }
+
/*
** Make local copies of the host & user and then
** transport them out.
*/
- allocaddr(a, flags, addr);
+ allocaddr(a, flags, addr, e);
if (QS_IS_BADADDR(a->q_state))
return a;
/*
+ ** Select a queue directory for recipient addresses.
+ ** This is done here and in split_across_queue_groups(),
+ ** but the latter applies to addresses after aliasing,
+ ** and only if splitting is done.
+ */
+
+ if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) &&
+ !bitset(RF_SENDERADDR|RF_HEADERADDR, flags) &&
+ OpMode != MD_INITALIAS)
+ {
+ int r;
+
+ /* call ruleset which should return a queue group name */
+ r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf,
+ sizeof(pvpbuf));
+ if (r == EX_OK &&
+ pvp != NULL && pvp[0] != NULL &&
+ (pvp[0][0] & 0377) == CANONNET &&
+ pvp[1] != NULL && pvp[1][0] != '\0')
+ {
+ r = name2qid(pvp[1]);
+ if (r == NOQGRP && LogLevel > 10)
+ sm_syslog(LOG_INFO, NOQID,
+ "can't find queue group name %s, selection ignored",
+ pvp[1]);
+ if (tTd(20, 4) && r != NOQGRP)
+ sm_syslog(LOG_INFO, NOQID,
+ "queue group name %s -> %d",
+ pvp[1], r);
+ a->q_qgrp = r == NOQGRP ? ENVQGRP : r;
+ }
+ }
+
+ /*
** If there was a parsing failure, mark it for queueing.
*/
@@ -157,10 +199,10 @@ parseaddr(addr, a, flags, delim, delimptr, e)
if (e->e_sendmode == SM_DEFER)
msg = "Deferring message until queue run";
if (tTd(20, 1))
- dprintf("parseaddr: queuing message\n");
+ sm_dprintf("parseaddr: queuing message\n");
message(msg);
if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
- e->e_message = newstr(msg);
+ e->e_message = sm_rpool_strdup_x(e->e_rpool, msg);
a->q_state = QS_QUEUEUP;
a->q_status = "4.4.3";
}
@@ -171,61 +213,144 @@ parseaddr(addr, a, flags, delim, delimptr, e)
if (tTd(20, 1))
{
- dprintf("parseaddr-->");
- printaddr(a, FALSE);
+ sm_dprintf("parseaddr-->");
+ printaddr(a, false);
}
return a;
}
- /*
-** INVALIDADDR -- check for address containing meta-characters
+/*
+** INVALIDADDR -- check for address containing characters used for macros
**
** Parameters:
** addr -- the address to check.
+** delimptr -- if non-NULL: end of address to check, i.e.,
+** a pointer in the address string.
+** isrcpt -- true iff the address is for a recipient.
**
** Returns:
-** TRUE -- if the address has any "wierd" characters
-** FALSE -- otherwise.
+** true -- if the address has characters that are reservered
+** for macros or is too long.
+** false -- otherwise.
*/
bool
-invalidaddr(addr, delimptr)
+invalidaddr(addr, delimptr, isrcpt)
register char *addr;
char *delimptr;
+ bool isrcpt;
{
+ bool result = false;
char savedelim = '\0';
+ int len = 0;
if (delimptr != NULL)
{
+ /* delimptr points to the end of the address to test */
savedelim = *delimptr;
- if (savedelim != '\0')
- *delimptr = '\0';
+ if (savedelim != '\0') /* if that isn't '\0' already: */
+ *delimptr = '\0'; /* set it */
}
- if (strlen(addr) > MAXNAME - 1)
+ for (; *addr != '\0'; addr++)
{
- usrerr("553 5.1.1 Address too long (%d bytes max)",
- MAXNAME - 1);
- goto failure;
+ if ((*addr & 0340) == 0200)
+ {
+ setstat(EX_USAGE);
+ result = true;
+ break;
+ }
+ if (++len > MAXNAME - 1)
+ {
+ usrerr("553 5.1.0 Address too long (%d bytes max)",
+ MAXNAME - 1);
+ result = true;
+ goto delim;
+ }
}
+ if (result)
+ {
+ if (isrcpt)
+ usrerr("501 5.1.3 Syntax error in mailbox address");
+ else
+ usrerr("501 5.1.7 Syntax error in mailbox address");
+ }
+delim:
+ if (delimptr != NULL && savedelim != '\0')
+ *delimptr = savedelim; /* restore old character at delimptr */
+ return result;
+}
+/*
+** HASCTRLCHAR -- check for address containing meta-characters
+**
+** Checks that the address contains no meta-characters, and contains
+** no "non-printable" characters unless they are quoted or escaped.
+** Quoted or escaped characters are literals.
+**
+** Parameters:
+** addr -- the address to check.
+** isrcpt -- true if the address is for a recipient; false
+** indicates a from.
+**
+** Returns:
+** true -- if the address has any "wierd" characters or
+** non-printable characters or if a quote is unbalanced.
+** false -- otherwise.
+*/
+
+static bool
+hasctrlchar(addr, isrcpt)
+ register char *addr;
+ bool isrcpt;
+{
+ bool result = false;
+ int len = 0;
+ bool quoted = false;
+
+ if (addr == NULL)
+ return false;
for (; *addr != '\0'; addr++)
{
+ if (!quoted && (*addr < 32 || *addr == 127))
+ {
+ result = true; /* a non-printable */
+ break;
+ }
+ if (*addr == '"')
+ quoted = !quoted;
+ else if (*addr == '\\')
+ {
+ /* XXX Generic problem: no '\0' in strings. */
+ if (*++addr == '\0')
+ {
+ result = true;
+ break;
+ }
+ }
if ((*addr & 0340) == 0200)
+ {
+ setstat(EX_USAGE);
+ result = true;
break;
+ }
+ if (++len > MAXNAME - 1)
+ {
+ usrerr("553 5.1.0 Address too long (%d bytes max)",
+ MAXNAME - 1);
+ return true;
+ }
}
- if (*addr == '\0')
+ if (quoted)
+ result = true; /* unbalanced quote */
+ if (result)
{
- if (delimptr != NULL && savedelim != '\0')
- *delimptr = savedelim;
- return FALSE;
+ if (isrcpt)
+ usrerr("501 5.1.3 Syntax error in mailbox address");
+ else
+ usrerr("501 5.1.7 Syntax error in mailbox address");
}
- setstat(EX_USAGE);
- usrerr("553 5.1.1 Address contained invalid control characters");
-failure:
- if (delimptr != NULL && savedelim != '\0')
- *delimptr = savedelim;
- return TRUE;
+ return result;
}
- /*
+/*
** ALLOCADDR -- do local allocations of address on demand.
**
** Also lowercases the host name if requested.
@@ -235,6 +360,7 @@ failure:
** flags -- the copy flag (see RF_ definitions in sendmail.h
** for a description).
** paddr -- the printname of the address.
+** e -- envelope
**
** Returns:
** none.
@@ -244,32 +370,34 @@ failure:
*/
static void
-allocaddr(a, flags, paddr)
+allocaddr(a, flags, paddr, e)
register ADDRESS *a;
int flags;
char *paddr;
+ ENVELOPE *e;
{
if (tTd(24, 4))
- dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
+ sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
a->q_paddr = paddr;
if (a->q_user == NULL)
- a->q_user = newstr("");
+ a->q_user = "";
if (a->q_host == NULL)
- a->q_host = newstr("");
+ a->q_host = "";
if (bitset(RF_COPYPARSE, flags))
{
- a->q_host = newstr(a->q_host);
+ a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host);
if (a->q_user != a->q_paddr)
- a->q_user = newstr(a->q_user);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user);
}
if (a->q_paddr == NULL)
- a->q_paddr = newstr(a->q_user);
+ a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
+ a->q_qgrp = NOAQGRP;
}
- /*
+/*
** PRESCAN -- Prescan name and make it canonical
**
** Scans a name and turns it into a set of tokens. This process
@@ -332,7 +460,7 @@ static short StateTab[NSTATES][NSTATES] =
};
/* token type table -- it gets modified with $o characters */
-static u_char TokTypeTab[256] =
+static unsigned char TokTypeTab[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
@@ -370,7 +498,7 @@ static u_char TokTypeTab[256] =
};
/* token type table for MIME parsing */
-u_char MimeTokenTab[256] =
+unsigned char MimeTokenTab[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
@@ -408,7 +536,7 @@ u_char MimeTokenTab[256] =
};
/* token type table: don't strip comments */
-u_char TokTypeNoC[256] =
+unsigned char TokTypeNoC[256] =
{
/* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
@@ -455,7 +583,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
char pvpbuf[];
int pvpbsize;
char **delimptr;
- u_char *toktab;
+ unsigned char *toktab;
{
register char *p;
register char *q;
@@ -470,7 +598,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
int newstate;
char *saveto = CurEnv->e_to;
static char *av[MAXATOM + 1];
- static char firsttime = TRUE;
+ static bool firsttime = true;
extern int errno;
if (firsttime)
@@ -478,7 +606,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
/* initialize the token type table */
char obuf[50];
- firsttime = FALSE;
+ firsttime = false;
if (OperatorChars == NULL)
{
if (ConfigLevel < 7)
@@ -488,7 +616,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
}
expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS,
CurEnv);
- (void) strlcat(obuf, DELIMCHARS, sizeof obuf);
+ (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf);
for (p = obuf; *p != '\0'; p++)
{
if (TokTypeTab[*p & 0xff] == ATM)
@@ -504,8 +632,8 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
errno = 0;
q = pvpbuf;
- bslashmode = FALSE;
- route_syntax = FALSE;
+ bslashmode = false;
+ route_syntax = false;
cmntcnt = 0;
anglecnt = 0;
avp = av;
@@ -515,9 +643,9 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
CurEnv->e_to = p;
if (tTd(22, 11))
{
- dprintf("prescan: ");
+ sm_dprintf("prescan: ");
xputs(p);
- dprintf("\n");
+ sm_dprintf("\n");
}
do
@@ -533,7 +661,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
if (q >= &pvpbuf[pvpbsize - 5])
{
usrerr("553 5.1.1 Address too long");
- if (strlen(addr) > (SIZE_T) MAXNAME)
+ if (strlen(addr) > MAXNAME)
addr[MAXNAME] = '\0';
returnnull:
if (delimptr != NULL)
@@ -553,18 +681,18 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
/* diagnose and patch up bad syntax */
if (state == QST)
{
- usrerr("653 Unbalanced '\"'");
+ usrerr("553 Unbalanced '\"'");
c = '"';
}
else if (cmntcnt > 0)
{
- usrerr("653 Unbalanced '('");
+ usrerr("553 Unbalanced '('");
c = ')';
}
else if (anglecnt > 0)
{
c = '>';
- usrerr("653 Unbalanced '<'");
+ usrerr("553 Unbalanced '<'");
}
else
break;
@@ -579,20 +707,20 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
/* special case for better error management */
if (delim == ',' && !route_syntax)
{
- usrerr("653 Unbalanced '<'");
+ usrerr("553 Unbalanced '<'");
c = '>';
p--;
}
}
if (tTd(22, 101))
- dprintf("c=%c, s=%d; ", c, state);
+ sm_dprintf("c=%c, s=%d; ", c, state);
/* chew up special characters */
*q = '\0';
if (bslashmode)
{
- bslashmode = FALSE;
+ bslashmode = false;
/* kludge \! for naive users */
if (cmntcnt > 0)
@@ -609,7 +737,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
if (c == '\\')
{
- bslashmode = TRUE;
+ bslashmode = true;
}
else if (state == QST)
{
@@ -625,7 +753,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
{
if (cmntcnt <= 0)
{
- usrerr("653 Unbalanced ')'");
+ usrerr("553 Unbalanced ')'");
c = NOCHAR;
}
else
@@ -643,18 +771,18 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
while (isascii(*ptr) && isspace(*ptr))
ptr++;
if (*ptr == '@')
- route_syntax = TRUE;
+ route_syntax = true;
}
else if (c == '>')
{
if (anglecnt <= 0)
{
- usrerr("653 Unbalanced '>'");
+ usrerr("553 Unbalanced '>'");
c = NOCHAR;
}
else
anglecnt--;
- route_syntax = FALSE;
+ route_syntax = false;
}
else if (delim == ' ' && isascii(c) && isspace(c))
c = ' ';
@@ -668,14 +796,15 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
newstate = StateTab[state][toktab[c & 0xff]];
if (tTd(22, 101))
- dprintf("ns=%02o\n", newstate);
+ sm_dprintf("ns=%02o\n", newstate);
state = newstate & TYPE;
if (state == ILL)
{
if (isascii(c) && isprint(c))
- usrerr("653 Illegal character %c", c);
+ usrerr("553 Illegal character %c", c);
else
- usrerr("653 Illegal character 0x%02x", c);
+ usrerr("553 Illegal character 0x%02x",
+ c & 0x0ff);
}
if (bitset(M, newstate))
c = NOCHAR;
@@ -689,9 +818,9 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
*q++ = '\0';
if (tTd(22, 36))
{
- dprintf("tok=");
+ sm_dprintf("tok=");
xputs(tok);
- dprintf("\n");
+ sm_dprintf("\n");
}
if (avp >= &av[MAXATOM])
{
@@ -712,19 +841,19 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
*delimptr = p;
if (tTd(22, 12))
{
- dprintf("prescan==>");
+ sm_dprintf("prescan==>");
printav(av);
}
CurEnv->e_to = saveto;
if (av[0] == NULL)
{
if (tTd(22, 1))
- dprintf("prescan: null leading token\n");
+ sm_dprintf("prescan: null leading token\n");
return NULL;
}
return av;
}
- /*
+/*
** REWRITE -- apply rewrite rules to token vector.
**
** This routine is an ordered production system. Each rewrite
@@ -751,6 +880,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
** ruleset -- the ruleset to use for rewriting.
** reclevel -- recursion level (to catch loops).
** e -- the current envelope.
+** maxatom -- maximum length of buffer (usually MAXATOM)
**
** Returns:
** A status code. If EX_TEMPFAIL, higher level code should
@@ -768,11 +898,12 @@ struct match
};
int
-rewrite(pvp, ruleset, reclevel, e)
+rewrite(pvp, ruleset, reclevel, e, maxatom)
char **pvp;
int ruleset;
int reclevel;
register ENVELOPE *e;
+ int maxatom;
{
register char *ap; /* address pointer */
register char *rp; /* rewrite pointer */
@@ -798,7 +929,7 @@ rewrite(pvp, ruleset, reclevel, e)
rulename = RuleSetNames[ruleset];
if (rulename == NULL)
{
- snprintf(name, sizeof name, "%d", ruleset);
+ (void) sm_snprintf(name, sizeof name, "%d", ruleset);
rulename = name;
}
if (OpMode == MD_TEST)
@@ -807,12 +938,13 @@ rewrite(pvp, ruleset, reclevel, e)
prefix = "rewrite: ruleset ";
if (OpMode == MD_TEST)
{
- printf("%s%-16.16s input:", prefix, rulename);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s%-16.16s input:", prefix, rulename);
printav(pvp);
}
else if (tTd(21, 1))
{
- dprintf("%s%-16.16s input:", prefix, rulename);
+ sm_dprintf("%s%-16.16s input:", prefix, rulename);
printav(pvp);
}
if (reclevel++ > MaxRuleRecursion)
@@ -842,10 +974,10 @@ rewrite(pvp, ruleset, reclevel, e)
if (tTd(21, 12))
{
if (tTd(21, 15))
- dprintf("-----trying rule (line %d):",
+ sm_dprintf("-----trying rule (line %d):",
rwr->r_line);
else
- dprintf("-----trying rule:");
+ sm_dprintf("-----trying rule:");
printav(rwr->r_lhs);
}
@@ -859,7 +991,7 @@ rewrite(pvp, ruleset, reclevel, e)
rulename, ruleno);
if (tTd(21, 1))
{
- dprintf("workspace: ");
+ sm_dprintf("workspace: ");
printav(pvp);
}
break;
@@ -870,11 +1002,11 @@ rewrite(pvp, ruleset, reclevel, e)
rp = *rvp;
if (tTd(21, 35))
{
- dprintf("ADVANCE rp=");
+ sm_dprintf("ADVANCE rp=");
xputs(rp);
- dprintf(", ap=");
+ sm_dprintf(", ap=");
xputs(ap);
- dprintf("\n");
+ sm_dprintf("\n");
}
if (rp == NULL)
{
@@ -905,16 +1037,16 @@ rewrite(pvp, ruleset, reclevel, e)
{
if (tTd(21, 36))
{
- dprintf("EXTEND rp=");
+ sm_dprintf("EXTEND rp=");
xputs(rp);
- dprintf(", ap=");
+ sm_dprintf(", ap=");
xputs(ap);
- dprintf("\n");
+ sm_dprintf("\n");
}
goto extendclass;
}
if (tTd(21, 36))
- dprintf("CLMATCH\n");
+ sm_dprintf("CLMATCH\n");
mlp++;
break;
@@ -958,7 +1090,7 @@ rewrite(pvp, ruleset, reclevel, e)
ap = macvalue(rp[1], e);
mlp->match_first = avp;
if (tTd(21, 2))
- dprintf("rewrite: LHS $&%s => \"%s\"\n",
+ sm_dprintf("rewrite: LHS $&%s => \"%s\"\n",
macname(rp[1]),
ap == NULL ? "(NULL)" : ap);
@@ -967,7 +1099,8 @@ rewrite(pvp, ruleset, reclevel, e)
while (*ap != '\0')
{
if (*avp == NULL ||
- strncasecmp(ap, *avp, strlen(*avp)) != 0)
+ sm_strncasecmp(ap, *avp,
+ strlen(*avp)) != 0)
{
/* no match */
avp = mlp->match_first;
@@ -1002,11 +1135,11 @@ rewrite(pvp, ruleset, reclevel, e)
if (tTd(21, 36))
{
- dprintf("BACKUP rp=");
+ sm_dprintf("BACKUP rp=");
xputs(rp);
- dprintf(", ap=");
+ sm_dprintf(", ap=");
xputs(ap);
- dprintf("\n");
+ sm_dprintf("\n");
}
if (ap == NULL)
@@ -1045,7 +1178,7 @@ rewrite(pvp, ruleset, reclevel, e)
if (mlp < mlist || *rvp != NULL)
{
if (tTd(21, 10))
- dprintf("----- rule fails\n");
+ sm_dprintf("----- rule fails\n");
rwr = rwr->r_next;
ruleno++;
loopcount = 0;
@@ -1055,7 +1188,7 @@ rewrite(pvp, ruleset, reclevel, e)
rvp = rwr->r_rhs;
if (tTd(21, 12))
{
- dprintf("-----rule matches:");
+ sm_dprintf("-----rule matches:");
printav(rvp);
}
@@ -1095,23 +1228,28 @@ rewrite(pvp, ruleset, reclevel, e)
}
if (tTd(21, 15))
{
- dprintf("$%c:", rp[1]);
+ sm_dprintf("$%c:", rp[1]);
pp = m->match_first;
while (pp <= m->match_last)
{
- dprintf(" %lx=\"",
- (u_long) *pp);
- (void) dflush();
- dprintf("%s\"", *pp++);
+ sm_dprintf(" %p=\"", *pp);
+ sm_dflush();
+ sm_dprintf("%s\"", *pp++);
}
- dprintf("\n");
+ sm_dprintf("\n");
}
pp = m->match_first;
while (pp <= m->match_last)
{
- if (avp >= &npvp[MAXATOM])
+ if (avp >= &npvp[maxatom])
{
syserr("554 5.3.0 rewrite: expansion too long");
+ if (LogLevel > 9)
+ sm_syslog(LOG_ERR,
+ e->e_id,
+ "rewrite: expansion too long, ruleset=%s, ruleno=%d",
+ rulename,
+ ruleno);
return EX_DATAERR;
}
*avp++ = *pp++;
@@ -1120,10 +1258,14 @@ rewrite(pvp, ruleset, reclevel, e)
else
{
/* some sort of replacement */
- if (avp >= &npvp[MAXATOM])
+ if (avp >= &npvp[maxatom])
{
toolong:
syserr("554 5.3.0 rewrite: expansion too long");
+ if (LogLevel > 9)
+ sm_syslog(LOG_ERR, e->e_id,
+ "rewrite: expansion too long, ruleset=%s, ruleno=%d",
+ rulename, ruleno);
return EX_DATAERR;
}
if ((*rp & 0377) != MACRODEXPAND)
@@ -1142,7 +1284,7 @@ rewrite(pvp, ruleset, reclevel, e)
char pvpbuf[PSBUFSIZE];
if (tTd(21, 2))
- dprintf("rewrite: RHS $&%s => \"%s\"\n",
+ sm_dprintf("rewrite: RHS $&%s => \"%s\"\n",
macname(rp[1]),
mval == NULL ? "(NULL)" : mval);
if (mval == NULL || *mval == '\0')
@@ -1155,7 +1297,8 @@ rewrite(pvp, ruleset, reclevel, e)
{
if (pvpb1 != NULL)
sm_free(pvpb1);
- pvpb1 = (char **)xalloc(trsize);
+ pvpb1 = (char **)
+ sm_pmalloc_x(trsize);
pvpb1_size = trsize;
}
@@ -1177,15 +1320,16 @@ rewrite(pvp, ruleset, reclevel, e)
while (*xpvp != NULL)
{
if (tTd(21, 19))
- dprintf(" ... %s\n",
+ sm_dprintf(" ... %s\n",
*xpvp);
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
+ *avp++ = sm_rpool_strdup_x(
+ e->e_rpool, *xpvp);
+ if (avp >= &npvp[maxatom])
goto toolong;
xpvp++;
}
if (tTd(21, 19))
- dprintf(" ... DONE\n");
+ sm_dprintf(" ... DONE\n");
/* restore the old trailing input */
memmove((char *) pvp,
@@ -1335,15 +1479,15 @@ rewrite(pvp, ruleset, reclevel, e)
/* append it to the token list */
for (avp = hbrvp; *xpvp != NULL; xpvp++)
{
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
+ *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp);
+ if (avp >= &npvp[maxatom])
goto toolong;
}
/* restore the old trailing information */
rvp = avp - 1;
for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
- if (avp >= &npvp[MAXATOM])
+ if (avp >= &npvp[maxatom])
goto toolong;
}
@@ -1363,24 +1507,25 @@ rewrite(pvp, ruleset, reclevel, e)
if (tTd(21, 4))
{
- dprintf("rewritten as:");
+ sm_dprintf("rewritten as:");
printav(pvp);
}
}
if (OpMode == MD_TEST)
{
- printf("%s%-16.16s returns:", prefix, rulename);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s%-16.16s returns:", prefix, rulename);
printav(pvp);
}
else if (tTd(21, 1))
{
- dprintf("%s%-16.16s returns:", prefix, rulename);
+ sm_dprintf("%s%-16.16s returns:", prefix, rulename);
printav(pvp);
}
return rstat;
}
- /*
+/*
** CALLSUBR -- call subroutines in rewrite vector
**
** Parameters:
@@ -1402,14 +1547,25 @@ callsubr(pvp, reclevel, e)
ENVELOPE *e;
{
char **avp;
- char **rvp;
register int i;
- int subr;
+ int subr, j;
+ int nsubr;
int status;
int rstat = EX_OK;
- char *tpvp[MAXATOM + 1];
+#define MAX_SUBR 16
+ int subrnumber[MAX_SUBR];
+ int subrindex[MAX_SUBR];
+
+ nsubr = 0;
- for (avp = pvp; *avp != NULL; avp++)
+ /*
+ ** Look for subroutine calls in pvp, collect them into subr*[]
+ ** We will perform the calls in the next loop, because we will
+ ** call the "last" subroutine first to avoid recursive calls
+ ** and too much copying.
+ */
+
+ for (avp = pvp, j = 0; *avp != NULL; avp++, j++)
{
if ((**avp & 0377) == CALLSUBR && avp[1] != NULL)
{
@@ -1417,81 +1573,74 @@ callsubr(pvp, reclevel, e)
subr = strtorwset(avp[1], NULL, ST_FIND);
if (subr < 0)
{
- syserr("Unknown ruleset %s", avp[1]);
+ syserr("554 5.3.5 Unknown ruleset %s", avp[1]);
return EX_CONFIG;
}
- if (tTd(21, 3))
- dprintf("-----callsubr %s (%d)\n",
- avp[1], subr);
-
- /*
- ** Take care of possible inner calls first.
- ** use a full size temporary buffer to avoid
- ** overflows in rewrite, but strip off the
- ** subroutine call.
- */
-
- for (i = 2; avp[i] != NULL; i++)
- tpvp[i - 2] = avp[i];
- tpvp[i - 2] = NULL;
-
- status = callsubr(tpvp, reclevel, e);
- if (rstat == EX_OK || status == EX_TEMPFAIL)
- rstat = status;
-
/*
- ** Now we need to call the ruleset specified for
- ** the subroutine. we can do this with the
- ** temporary buffer that we set up earlier,
- ** since it has all the data we want to rewrite.
+ ** XXX instead of doing this we could optimize
+ ** the rules after reading them: just remove
+ ** calls to empty rulesets
*/
- status = rewrite(tpvp, subr, reclevel, e);
- if (rstat == EX_OK || status == EX_TEMPFAIL)
- rstat = status;
-
- /*
- ** Find length of tpvp and current offset into
- ** pvp, if the total is greater than MAXATOM,
- ** then it would overflow the buffer if we copied
- ** it back in to pvp, in which case we throw a
- ** fit.
- */
-
- for (rvp = tpvp; *rvp != NULL; rvp++)
+ /* subroutine is an empty ruleset? don't call it */
+ if (RewriteRules[subr] == NULL)
+ {
+ if (tTd(21, 3))
+ sm_dprintf("-----skip subr %s (%d)\n",
+ avp[1], subr);
+ for (i = 2; avp[i] != NULL; i++)
+ avp[i - 2] = avp[i];
+ avp[i - 2] = NULL;
continue;
- if (((rvp - tpvp) + (avp - pvp)) > MAXATOM)
+ }
+ if (++nsubr >= MAX_SUBR)
{
- syserr("554 5.3.0 callsubr: expansion too long");
- return EX_DATAERR;
+ syserr("554 5.3.0 Too many subroutine calls (%d max)",
+ MAX_SUBR);
+ return EX_CONFIG;
}
+ subrnumber[nsubr] = subr;
+ subrindex[nsubr] = j;
+ }
+ }
- /*
- ** Now we can copy the rewritten code over
- ** the initial subroutine call in the buffer.
- */
+ /*
+ ** Perform the actual subroutines calls, "last" one first, i.e.,
+ ** go from the right to the left through all calls,
+ ** do the rewriting in place.
+ */
- for (i = 0; tpvp[i] != NULL; i++)
- avp[i] = tpvp[i];
- avp[i] = NULL;
+ for (; nsubr > 0; nsubr--)
+ {
+ subr = subrnumber[nsubr];
+ avp = pvp + subrindex[nsubr];
- /*
- ** If we got this far, we've processed the left
- ** most subroutine, and recursively called ourselves
- ** to handle any other subroutines. We're done.
- */
+ /* remove the subroutine call and name */
+ for (i = 2; avp[i] != NULL; i++)
+ avp[i - 2] = avp[i];
+ avp[i - 2] = NULL;
- break;
- }
+ /*
+ ** Now we need to call the ruleset specified for
+ ** the subroutine. we can do this inplace since
+ ** we call the "last" subroutine first.
+ */
+
+ status = rewrite(avp, subr, reclevel, e,
+ MAXATOM - subrindex[nsubr]);
+ if (status != EX_OK && status != EX_TEMPFAIL)
+ return status;
+ if (rstat == EX_OK || status == EX_TEMPFAIL)
+ rstat = status;
}
return rstat;
}
- /*
+/*
** MAP_LOOKUP -- do lookup in map
**
** Parameters:
-** map -- the map to use for the lookup.
+** smap -- the map to use for the lookup.
** key -- the key to look up.
** argvect -- arguments to pass to the map lookup.
** pstat -- a pointer to an integer in which to store the
@@ -1526,7 +1675,7 @@ map_lookup(smap, key, argvect, pstat, e)
{
/* don't do any map lookups */
if (tTd(60, 1))
- dprintf("map_lookup(%s, %s) => DEFERRED\n",
+ sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
smap->s_name, key);
*pstat = EX_TEMPFAIL;
return NULL;
@@ -1537,19 +1686,19 @@ map_lookup(smap, key, argvect, pstat, e)
if (tTd(60, 1))
{
- dprintf("map_lookup(%s, %s", smap->s_name, key);
+ sm_dprintf("map_lookup(%s, %s", smap->s_name, key);
if (tTd(60, 5))
{
int i;
for (i = 0; argvect[i] != NULL; i++)
- dprintf(", %%%d=%s", i, argvect[i]);
+ sm_dprintf(", %%%d=%s", i, argvect[i]);
}
- dprintf(") => ");
+ sm_dprintf(") => ");
}
replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
if (tTd(60, 1))
- dprintf("%s (%d)\n",
+ sm_dprintf("%s (%d)\n",
replac != NULL ? replac : "NOT FOUND",
status);
@@ -1558,17 +1707,17 @@ map_lookup(smap, key, argvect, pstat, e)
{
*pstat = EX_TEMPFAIL;
if (tTd(60, 1))
- dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
+ sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
smap->s_name, key, errno);
if (e->e_message == NULL)
{
char mbuf[320];
- snprintf(mbuf, sizeof mbuf,
+ (void) sm_snprintf(mbuf, sizeof mbuf,
"%.80s map: lookup (%s): deferred",
smap->s_name,
shortenstring(key, MAXSHORTSTR));
- e->e_message = newstr(mbuf);
+ e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf);
}
}
if (status == EX_TEMPFAIL && map->map_tapp != NULL)
@@ -1582,17 +1731,17 @@ map_lookup(smap, key, argvect, pstat, e)
if (rwbuf != NULL)
sm_free(rwbuf);
rwbuflen = i;
- rwbuf = (char *) xalloc(rwbuflen);
+ rwbuf = (char *) sm_pmalloc_x(rwbuflen);
}
- snprintf(rwbuf, rwbuflen, "%s%s", key, map->map_tapp);
+ (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp);
if (tTd(60, 4))
- dprintf("map_lookup tempfail: returning \"%s\"\n",
+ sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
rwbuf);
return rwbuf;
}
return replac;
}
- /*
+/*
** INITERRMAILERS -- initialize error and discard mailers
**
** Parameters:
@@ -1628,7 +1777,7 @@ initerrmailers()
errormailer.m_argv = errorargv;
}
}
- /*
+/*
** BUILDADDR -- build address from token vector.
**
** Parameters:
@@ -1660,13 +1809,10 @@ static struct errcodes
{ "software", EX_SOFTWARE },
{ "tempfail", EX_TEMPFAIL },
{ "protocol", EX_PROTOCOL },
-#ifdef EX_CONFIG
{ "config", EX_CONFIG },
-#endif /* EX_CONFIG */
{ NULL, EX_UNAVAILABLE }
};
-
static ADDRESS *
buildaddr(tv, a, flags, e)
register char **tv;
@@ -1684,12 +1830,12 @@ buildaddr(tv, a, flags, e)
if (tTd(24, 5))
{
- dprintf("buildaddr, flags=%x, tv=", flags);
+ sm_dprintf("buildaddr, flags=%x, tv=", flags);
printav(tv);
}
if (a == NULL)
- a = (ADDRESS *) xalloc(sizeof *a);
+ a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
memset((char *) a, '\0', sizeof *a);
hbuf[0] = '\0';
@@ -1731,20 +1877,22 @@ badaddr:
cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');
/* save away the host name */
- if (strcasecmp(mname, "error") == 0)
+ if (sm_strcasecmp(mname, "error") == 0)
{
/* Set up triplet for use by -bv */
a->q_mailer = &errormailer;
- a->q_user = newstr(ubuf);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
+ /* XXX wrong place? */
if (hostp != NULL)
{
register struct errcodes *ep;
- a->q_host = newstr(hbuf);
+ a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
if (strchr(hbuf, '.') != NULL)
{
- a->q_status = newstr(hbuf);
+ a->q_status = sm_rpool_strdup_x(e->e_rpool,
+ hbuf);
setstat(dsntoexitstat(hbuf));
}
else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
@@ -1754,7 +1902,7 @@ badaddr:
else
{
for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
- if (strcasecmp(ep->ec_name, hbuf) == 0)
+ if (sm_strcasecmp(ep->ec_name, hbuf) == 0)
break;
setstat(ep->ec_code);
}
@@ -1780,7 +1928,7 @@ badaddr:
off = 4;
ubuf[3] = '\0';
}
- (void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf);
+ (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s");
if (off > 4)
usrerr(fmt, ubuf + off);
else if (isenhsc(hbuf, '\0') > 0)
@@ -1798,7 +1946,7 @@ badaddr:
for (mp = Mailer; (m = *mp++) != NULL; )
{
- if (strcasecmp(m->m_name, mname) == 0)
+ if (sm_strcasecmp(m->m_name, mname) == 0)
break;
}
if (m == NULL)
@@ -1819,7 +1967,7 @@ badaddr:
a->q_host = NULL;
}
else
- a->q_host = newstr(hbuf);
+ a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
/* figure out the user */
p = ubuf;
@@ -1841,40 +1989,31 @@ badaddr:
{
/* may be :include: */
stripquotes(ubuf);
- if (strncasecmp(ubuf, ":include:", 9) == 0)
+ if (sm_strncasecmp(ubuf, ":include:", 9) == 0)
{
/* if :include:, don't need further rewriting */
a->q_mailer = m = InclMailer;
- a->q_user = newstr(&ubuf[9]);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]);
return a;
}
}
/* rewrite according recipient mailer rewriting rules */
- define('h', a->q_host, e);
-
-#if _FFR_ADDR_TYPE
- /*
- ** Note, change the 9 to a 10 before removing #if FFR check
- ** in a future version.
- */
+ macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
- if (ConfigLevel >= 9 ||
+ if (ConfigLevel >= 10 ||
!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
-#else /* _FFR_ADDR_TYPE */
- if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
-#endif /* _FFR_ADDR_TYPE */
{
/* sender addresses done later */
- (void) rewrite(tv, 2, 0, e);
+ (void) REWRITE(tv, 2, e);
if (m->m_re_rwset > 0)
- (void) rewrite(tv, m->m_re_rwset, 0, e);
+ (void) REWRITE(tv, m->m_re_rwset, e);
}
- (void) rewrite(tv, 4, 0, e);
+ (void) REWRITE(tv, 4, e);
/* save the result for the command line/RCPT argument */
cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
- a->q_user = newstr(ubuf);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
/*
** Do mapping to lower case as requested by mailer
@@ -1887,12 +2026,12 @@ badaddr:
if (tTd(24, 6))
{
- dprintf("buildaddr => ");
- printaddr(a, FALSE);
+ sm_dprintf("buildaddr => ");
+ printaddr(a, false);
}
return a;
}
- /*
+/*
** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
**
** Parameters:
@@ -1901,7 +2040,7 @@ badaddr:
** use entire pvp.
** buf -- buffer to build the string into.
** sz -- size of buf.
-** spacesub -- the space separator character; if null,
+** spacesub -- the space separator character; if '\0',
** use SpaceSub.
**
** Returns:
@@ -1919,8 +2058,8 @@ cataddr(pvp, evp, buf, sz, spacesub)
register int sz;
int spacesub;
{
- bool oatomtok = FALSE;
- bool natomtok = FALSE;
+ bool oatomtok = false;
+ bool natomtok = false;
register int i;
register char *p;
@@ -1937,15 +2076,17 @@ cataddr(pvp, evp, buf, sz, spacesub)
}
p = buf;
sz -= 2;
- while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1)
+ while (*pvp != NULL && sz > 0)
{
natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
if (oatomtok && natomtok)
{
*p++ = spacesub;
- --sz;
+ if (--sz <= 0)
+ break;
}
- (void) strlcpy(p, *pvp, sz);
+ if ((i = sm_strlcpy(p, *pvp, sz)) >= sz)
+ break;
oatomtok = natomtok;
p += i;
sz -= i;
@@ -1954,7 +2095,7 @@ cataddr(pvp, evp, buf, sz, spacesub)
}
*p = '\0';
}
- /*
+/*
** SAMEADDR -- Determine if two addresses are the same
**
** This is not just a straight comparison -- if the mailer doesn't
@@ -1964,8 +2105,8 @@ cataddr(pvp, evp, buf, sz, spacesub)
** a, b -- pointers to the internal forms to compare.
**
** Returns:
-** TRUE -- they represent the same mailbox.
-** FALSE -- they don't.
+** true -- they represent the same mailbox.
+** false -- they don't.
**
** Side Effects:
** none.
@@ -1980,11 +2121,11 @@ sameaddr(a, b)
/* if they don't have the same mailer, forget it */
if (a->q_mailer != b->q_mailer)
- return FALSE;
+ return false;
/* if the user isn't the same, we can drop out */
if (strcmp(a->q_user, b->q_user) != 0)
- return FALSE;
+ return false;
/* if we have good uids for both but they differ, these are different */
if (a->q_mailer == ProgMailer)
@@ -1994,26 +2135,26 @@ sameaddr(a, b)
if (ca != NULL && cb != NULL &&
bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
ca->q_uid != cb->q_uid)
- return FALSE;
+ return false;
}
/* otherwise compare hosts (but be careful for NULL ptrs) */
if (a->q_host == b->q_host)
{
/* probably both null pointers */
- return TRUE;
+ return true;
}
if (a->q_host == NULL || b->q_host == NULL)
{
/* only one is a null pointer */
- return FALSE;
+ return false;
}
if (strcmp(a->q_host, b->q_host) != 0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
- /*
+/*
** PRINTADDR -- print address (for debugging)
**
** Parameters:
@@ -2029,8 +2170,8 @@ sameaddr(a, b)
struct qflags
{
- char *qf_name;
- u_long qf_bit;
+ char *qf_name;
+ unsigned long qf_bit;
};
static struct qflags AddressFlags[] =
@@ -2066,14 +2207,14 @@ printaddr(a, follow)
if (a == NULL)
{
- printf("[NULL]\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "[NULL]\n");
return;
}
while (a != NULL)
{
- printf("%lx=", (u_long) a);
- (void) fflush(stdout);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%p=", a);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
/* find the mailer -- carefully */
m = a->q_mailer;
@@ -2084,120 +2225,149 @@ printaddr(a, follow)
m->m_name = "NULL";
}
- printf("%s:\n\tmailer %d (%s), host `%s'\n",
- a->q_paddr == NULL ? "<null>" : a->q_paddr,
- m->m_mno, m->m_name,
- a->q_host == NULL ? "<null>" : a->q_host);
- printf("\tuser `%s', ruser `%s'\n",
- a->q_user,
- a->q_ruser == NULL ? "<null>" : a->q_ruser);
- printf("\tstate=");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s:\n\tmailer %d (%s), host `%s'\n",
+ a->q_paddr == NULL ? "<null>" : a->q_paddr,
+ m->m_mno, m->m_name,
+ a->q_host == NULL ? "<null>" : a->q_host);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\tuser `%s', ruser `%s'\n",
+ a->q_user,
+ a->q_ruser == NULL ? "<null>" : a->q_ruser);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tstate=");
switch (a->q_state)
{
case QS_OK:
- printf("OK");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK");
break;
case QS_DONTSEND:
- printf("DONTSEND");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "DONTSEND");
break;
case QS_BADADDR:
- printf("BADADDR");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "BADADDR");
break;
case QS_QUEUEUP:
- printf("QUEUEUP");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "QUEUEUP");
+ break;
+
+ case QS_RETRY:
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "RETRY");
break;
case QS_SENT:
- printf("SENT");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "SENT");
break;
case QS_VERIFIED:
- printf("VERIFIED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "VERIFIED");
break;
case QS_EXPANDED:
- printf("EXPANDED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "EXPANDED");
break;
case QS_SENDER:
- printf("SENDER");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "SENDER");
break;
case QS_CLONED:
- printf("CLONED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "CLONED");
break;
case QS_DISCARDED:
- printf("DISCARDED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "DISCARDED");
break;
case QS_REPLACED:
- printf("REPLACED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "REPLACED");
break;
case QS_REMOVED:
- printf("REMOVED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "REMOVED");
break;
case QS_DUPLICATE:
- printf("DUPLICATE");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "DUPLICATE");
break;
case QS_INCLUDED:
- printf("INCLUDED");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "INCLUDED");
break;
default:
- printf("%d", a->q_state);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%d", a->q_state);
break;
}
- printf(", next=%lx, alias %lx, uid %d, gid %d\n",
- (u_long) a->q_next, (u_long) a->q_alias,
- (int) a->q_uid, (int) a->q_gid);
- printf("\tflags=%lx<", a->q_flags);
- firstone = TRUE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ ", next=%p, alias %p, uid %d, gid %d\n",
+ a->q_next, a->q_alias,
+ (int) a->q_uid, (int) a->q_gid);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tflags=%lx<",
+ a->q_flags);
+ firstone = true;
for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
{
if (!bitset(qfp->qf_bit, a->q_flags))
continue;
if (!firstone)
- printf(",");
- firstone = FALSE;
- printf("%s", qfp->qf_name);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ ",");
+ firstone = false;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s",
+ qfp->qf_name);
}
- printf(">\n");
- printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
- a->q_owner == NULL ? "(none)" : a->q_owner,
- a->q_home == NULL ? "(none)" : a->q_home,
- a->q_fullname == NULL ? "(none)" : a->q_fullname);
- printf("\torcpt=\"%s\", statmta=%s, status=%s\n",
- a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
- a->q_statmta == NULL ? "(none)" : a->q_statmta,
- a->q_status == NULL ? "(none)" : a->q_status);
- printf("\trstatus=\"%s\"\n",
- a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
- printf("\tspecificity=%d, statdate=%s\n",
- a->q_specificity,
- a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
+ a->q_owner == NULL ? "(none)" : a->q_owner,
+ a->q_home == NULL ? "(none)" : a->q_home,
+ a->q_fullname == NULL ? "(none)" : a->q_fullname);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\torcpt=\"%s\", statmta=%s, status=%s\n",
+ a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
+ a->q_statmta == NULL ? "(none)" : a->q_statmta,
+ a->q_status == NULL ? "(none)" : a->q_status);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\tfinalrcpt=\"%s\"\n",
+ a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\trstatus=\"%s\"\n",
+ a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\tstatdate=%s\n",
+ a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
if (!follow)
return;
a = a->q_next;
}
}
- /*
-** EMPTYADDR -- return TRUE if this address is empty (``<>'')
+/*
+** EMPTYADDR -- return true if this address is empty (``<>'')
**
** Parameters:
** a -- pointer to the address
**
** Returns:
-** TRUE -- if this address is "empty" (i.e., no one should
+** true -- if this address is "empty" (i.e., no one should
** ever generate replies to it.
-** FALSE -- if it is a "regular" (read: replyable) address.
+** false -- if it is a "regular" (read: replyable) address.
*/
bool
@@ -2207,7 +2377,7 @@ emptyaddr(a)
return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
}
- /*
+/*
** REMOTENAME -- return the name relative to the current mailer
**
** Parameters:
@@ -2239,44 +2409,36 @@ remotename(name, m, flags, pstat, e)
register ENVELOPE *e;
{
register char **pvp;
- char *fancy;
- char *oldg = macvalue('g', e);
+ char *SM_NONVOLATILE fancy;
+ char *oldg;
int rwset;
static char buf[MAXNAME + 1];
char lbuf[MAXNAME + 1];
char pvpbuf[PSBUFSIZE];
-#if _FFR_ADDR_TYPE
char addrtype[4];
-#endif /* _FFR_ADDR_TYPE */
if (tTd(12, 1))
- dprintf("remotename(%s)\n", name);
+ sm_dprintf("remotename(%s)\n", name);
/* don't do anything if we are tagging it as special */
if (bitset(RF_SENDERADDR, flags))
{
rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
: m->m_se_rwset;
-#if _FFR_ADDR_TYPE
addrtype[2] = 's';
-#endif /* _FFR_ADDR_TYPE */
}
else
{
rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
: m->m_re_rwset;
-#if _FFR_ADDR_TYPE
addrtype[2] = 'r';
-#endif /* _FFR_ADDR_TYPE */
}
if (rwset < 0)
return name;
-#if _FFR_ADDR_TYPE
addrtype[1] = ' ';
addrtype[3] = '\0';
addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
- define(macid("{addr_type}", NULL), addrtype, e);
-#endif /* _FFR_ADDR_TYPE */
+ macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype);
/*
** Do a heuristic crack of this name to extract any comment info.
@@ -2299,7 +2461,7 @@ remotename(name, m, flags, pstat, e)
pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
if (pvp == NULL)
return name;
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
{
@@ -2328,7 +2490,7 @@ remotename(name, m, flags, pstat, e)
break;
}
}
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
}
@@ -2342,17 +2504,17 @@ remotename(name, m, flags, pstat, e)
if (bitset(RF_SENDERADDR, flags))
{
- if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, 1, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
else
{
- if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, 2, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
if (rwset > 0)
{
- if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
}
@@ -2363,7 +2525,7 @@ remotename(name, m, flags, pstat, e)
** may be used as a default to the above rules.
*/
- if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
+ if (REWRITE(pvp, 4, e) == EX_TEMPFAIL)
*pstat = EX_TEMPFAIL;
/*
@@ -2371,21 +2533,24 @@ remotename(name, m, flags, pstat, e)
*/
cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
- define('g', lbuf, e);
+ oldg = macget(&e->e_macro, 'g');
+ macset(&e->e_macro, 'g', lbuf);
- /* need to make sure route-addrs have <angle brackets> */
- if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
- expand("<\201g>", buf, sizeof buf, e);
- else
- expand(fancy, buf, sizeof buf, e);
-
- define('g', oldg, e);
+ SM_TRY
+ /* need to make sure route-addrs have <angle brackets> */
+ if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
+ expand("<\201g>", buf, sizeof buf, e);
+ else
+ expand(fancy, buf, sizeof buf, e);
+ SM_FINALLY
+ macset(&e->e_macro, 'g', oldg);
+ SM_END_TRY
if (tTd(12, 1))
- dprintf("remotename => `%s'\n", buf);
+ sm_dprintf("remotename => `%s'\n", buf);
return buf;
}
- /*
+/*
** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
**
** Parameters:
@@ -2401,7 +2566,8 @@ remotename(name, m, flags, pstat, e)
#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
Q_PINGFLAGS|QHASNOTIFY|\
- QRELAYED|QEXPANDED|QDELIVERED|QDELAYED)
+ QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
+ QBYTRACE|QBYNDELAY|QBYNRELAY)
void
maplocaluser(a, sendq, aliaslevel, e)
@@ -2411,35 +2577,33 @@ maplocaluser(a, sendq, aliaslevel, e)
ENVELOPE *e;
{
register char **pvp;
- register ADDRESS *a1 = NULL;
+ register ADDRESS *SM_NONVOLATILE a1 = NULL;
auto char *delimptr;
char pvpbuf[PSBUFSIZE];
if (tTd(29, 1))
{
- dprintf("maplocaluser: ");
- printaddr(a, FALSE);
+ sm_dprintf("maplocaluser: ");
+ printaddr(a, false);
}
pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
if (pvp == NULL)
{
if (tTd(29, 9))
- dprintf("maplocaluser: cannot prescan %s\n",
+ sm_dprintf("maplocaluser: cannot prescan %s\n",
a->q_user);
return;
}
- define('h', a->q_host, e);
- define('u', a->q_user, e);
- define('z', a->q_home, e);
+ macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
+ macdefine(&e->e_macro, A_PERM, 'u', a->q_user);
+ macdefine(&e->e_macro, A_PERM, 'z', a->q_home);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
- if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL)
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
+ if (REWRITE(pvp, 5, e) == EX_TEMPFAIL)
{
if (tTd(29, 9))
- dprintf("maplocaluser: rewrite tempfail\n");
+ sm_dprintf("maplocaluser: rewrite tempfail\n");
a->q_state = QS_QUEUEUP;
a->q_status = "4.4.3";
return;
@@ -2447,49 +2611,58 @@ maplocaluser(a, sendq, aliaslevel, e)
if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
{
if (tTd(29, 9))
- dprintf("maplocaluser: doesn't resolve\n");
+ sm_dprintf("maplocaluser: doesn't resolve\n");
return;
}
+ SM_TRY
+ a1 = buildaddr(pvp, NULL, 0, e);
+ SM_EXCEPT(exc, "E:mta.quickabort")
+
+ /*
+ ** mark address as bad, S5 returned an error
+ ** and we gave that back to the SMTP client.
+ */
+
+ a->q_state = QS_DONTSEND;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 2);
+ SM_END_TRY
+
/* if non-null, mailer destination specified -- has it changed? */
- a1 = buildaddr(pvp, NULL, 0, e);
if (a1 == NULL || sameaddr(a, a1))
{
if (tTd(29, 9))
- dprintf("maplocaluser: address unchanged\n");
- if (a1 != NULL)
- sm_free(a1);
+ sm_dprintf("maplocaluser: address unchanged\n");
return;
}
/* make new address take on flags and print attributes of old */
a1->q_flags &= ~Q_COPYFLAGS;
a1->q_flags |= a->q_flags & Q_COPYFLAGS;
- a1->q_paddr = newstr(a->q_paddr);
+ a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr);
+ a1->q_finalrcpt = a->q_finalrcpt;
a1->q_orcpt = a->q_orcpt;
/* mark old address as dead; insert new address */
a->q_state = QS_REPLACED;
if (tTd(29, 5))
{
- dprintf("maplocaluser: QS_REPLACED ");
- printaddr(a, FALSE);
+ sm_dprintf("maplocaluser: QS_REPLACED ");
+ printaddr(a, false);
}
a1->q_alias = a;
- allocaddr(a1, RF_COPYALL, newstr(a->q_paddr));
+ allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e);
(void) recipient(a1, sendq, aliaslevel, e);
}
- /*
+/*
** DEQUOTE_INIT -- initialize dequote map
**
-** This is a no-op.
-**
** Parameters:
** map -- the internal map structure.
** args -- arguments.
**
** Returns:
-** TRUE.
+** true.
*/
bool
@@ -2530,9 +2703,9 @@ dequote_init(map, args)
if (map->map_app != NULL)
map->map_app = newstr(map->map_app);
- return TRUE;
+ return true;
}
- /*
+/*
** DEQUOTE_MAP -- unquote an address
**
** Parameters:
@@ -2562,15 +2735,15 @@ dequote_map(map, name, av, statp)
int cmntcnt = 0;
int quotecnt = 0;
int spacecnt = 0;
- bool quotemode = FALSE;
- bool bslashmode = FALSE;
+ bool quotemode = false;
+ bool bslashmode = false;
char spacesub = map->map_spacesub;
for (p = q = name; (c = *p++) != '\0'; )
{
if (bslashmode)
{
- bslashmode = FALSE;
+ bslashmode = false;
*q++ = c;
continue;
}
@@ -2581,7 +2754,7 @@ dequote_map(map, name, av, statp)
switch (c)
{
case '\\':
- bslashmode = TRUE;
+ bslashmode = true;
break;
case '(':
@@ -2630,7 +2803,7 @@ dequote_map(map, name, av, statp)
*q++ = '\0';
return map_rewrite(map, name, strlen(name), NULL);
}
- /*
+/*
** RSCHECK -- check string(s) for validity using rewriting sets
**
** Parameters:
@@ -2640,8 +2813,9 @@ dequote_map(map, name, av, statp)
** e -- the current envelope.
** rmcomm -- remove comments?
** cnt -- count rejections (statistics)?
-** logl -- logging level
+** logl -- logging level.
** host -- NULL or relay host.
+** logid -- id for sm_syslog.
**
** Returns:
** EX_OK -- if the rwset doesn't resolve to $#error
@@ -2649,7 +2823,7 @@ dequote_map(map, name, av, statp)
*/
int
-rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host)
+rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host, logid)
char *rwset;
char *p1;
char *p2;
@@ -2657,23 +2831,28 @@ rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host)
bool rmcomm, cnt;
int logl;
char *host;
+ char *logid;
{
- char *buf;
+ char *volatile buf;
int bufsize;
int saveexitstat;
- int rstat = EX_OK;
+ int volatile rstat = EX_OK;
char **pvp;
int rsno;
- bool discard = FALSE;
+ bool volatile discard = false;
auto ADDRESS a1;
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
+#if _FFR_QUARANTINE
+ bool quarantine = false;
+ char ubuf[BUFSIZ * 2];
+#endif /* _FFR_QUARANTINE */
char buf0[MAXLINE];
char pvpbuf[PSBUFSIZE];
extern char MsgBuf[];
if (tTd(48, 2))
- dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
+ sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
p2 == NULL ? "(NULL)" : p2);
rsno = strtorwset(rwset, NULL, ST_FIND);
@@ -2684,130 +2863,258 @@ rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host)
{
bufsize = strlen(p1) + strlen(p2) + 2;
if (bufsize > sizeof buf0)
- buf = xalloc(bufsize);
+ buf = sm_malloc_x(bufsize);
else
{
buf = buf0;
bufsize = sizeof buf0;
}
- (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
+ (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
}
else
{
bufsize = strlen(p1) + 1;
if (bufsize > sizeof buf0)
- buf = xalloc(bufsize);
+ buf = sm_malloc_x(bufsize);
else
{
buf = buf0;
bufsize = sizeof buf0;
}
- (void) snprintf(buf, bufsize, "%s", p1);
+ (void) sm_strlcpy(buf, p1, bufsize);
}
- SuprErrs = TRUE;
- QuickAbort = FALSE;
- pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL,
- rmcomm ? NULL : TokTypeNoC);
- SuprErrs = saveSuprErrs;
- if (pvp == NULL)
+ SM_TRY
{
- if (tTd(48, 2))
- dprintf("rscheck: cannot prescan input\n");
-/*
- syserr("rscheck: cannot prescan input: \"%s\"",
- shortenstring(buf, MAXSHORTSTR));
- rstat = EX_DATAERR;
-*/
- goto finis;
- }
+ SuprErrs = true;
+ QuickAbort = false;
+ pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL,
+ rmcomm ? NULL : TokTypeNoC);
+ SuprErrs = saveSuprErrs;
+ if (pvp == NULL)
+ {
+ if (tTd(48, 2))
+ sm_dprintf("rscheck: cannot prescan input\n");
+ /*
+ syserr("rscheck: cannot prescan input: \"%s\"",
+ shortenstring(buf, MAXSHORTSTR));
+ rstat = EX_DATAERR;
+ */
+ goto finis;
+ }
+ (void) REWRITE(pvp, rsno, e);
+ if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
+ pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
+ strcmp(pvp[1], "discard") != 0))
+ {
+ goto finis;
+ }
- MapOpenErr = FALSE;
- (void) rewrite(pvp, rsno, 0, e);
- if (MapOpenErr)
- {
- usrerrenh("4.3.0", "451 Temporary failure");
- rstat = EX_TEMPFAIL;
- goto finis;
- }
+ if (strcmp(pvp[1], "discard") == 0)
+ {
+ if (tTd(48, 2))
+ sm_dprintf("rscheck: discard mailer selected\n");
+ e->e_flags |= EF_DISCARD;
+ discard = true;
+ }
+#if _FFR_QUARANTINE
+ else if (strcmp(pvp[1], "error") == 0 &&
+ pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST &&
+ pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0)
+ {
+ if (pvp[4] == NULL ||
+ (pvp[4][0] & 0377) != CANONUSER ||
+ pvp[5] == NULL)
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
+ rwset);
+ else
+ {
+ cataddr(&(pvp[5]), NULL, ubuf,
+ sizeof ubuf, ' ');
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
+ ubuf);
+ }
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
+ quarantine = true;
+ }
+#endif /* _FFR_QUARANTINE */
+ else
+ {
+ int savelogusrerrs = LogUsrErrs;
+ static bool logged = false;
+
+ /* got an error -- process it */
+ saveexitstat = ExitStat;
+ LogUsrErrs = false;
+ (void) buildaddr(pvp, &a1, 0, e);
+ LogUsrErrs = savelogusrerrs;
+ rstat = ExitStat;
+ ExitStat = saveexitstat;
+ if (!logged)
+ {
+ if (cnt)
+ markstats(e, &a1, STATS_REJECT);
+ logged = true;
+ }
+ }
+
+ if (LogLevel > logl)
+ {
+ char *relay;
+ char *p;
+ char lbuf[MAXLINE];
+
+ p = lbuf;
+ if (p2 != NULL)
+ {
+ (void) sm_snprintf(p, SPACELEFT(lbuf, p),
+ ", arg2=%s",
+ p2);
+ p += strlen(p);
+ }
+
+ if (host != NULL)
+ relay = host;
+ else
+ relay = macvalue('_', e);
+ if (relay != NULL)
+ {
+ (void) sm_snprintf(p, SPACELEFT(lbuf, p),
+ ", relay=%s", relay);
+ p += strlen(p);
+ }
+ *p = '\0';
+ if (discard)
+ sm_syslog(LOG_NOTICE, logid,
+ "ruleset=%s, arg1=%s%s, discard",
+ rwset, p1, lbuf);
+#if _FFR_QUARANTINE
+ else if (quarantine)
+ sm_syslog(LOG_NOTICE, logid,
+ "ruleset=%s, arg1=%s%s, quarantine=%s",
+ rwset, p1, lbuf, ubuf);
+#endif /* _FFR_QUARANTINE */
+ else
+ sm_syslog(LOG_NOTICE, logid,
+ "ruleset=%s, arg1=%s%s, reject=%s",
+ rwset, p1, lbuf, MsgBuf);
+ }
- if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
- pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
- strcmp(pvp[1], "discard") != 0))
+ finis: ;
+ }
+ SM_FINALLY
{
- goto finis;
+ /* clean up */
+ if (buf != buf0)
+ sm_free(buf);
+ QuickAbort = saveQuickAbort;
}
+ SM_END_TRY
+
+ setstat(rstat);
+
+ /* rulesets don't set errno */
+ errno = 0;
+ if (rstat != EX_OK && QuickAbort)
+ sm_exc_raisenew_x(&EtypeQuickAbort, 2);
+ return rstat;
+}
+/*
+** RSCAP -- call rewriting set to return capabilities
+**
+** Parameters:
+** rwset -- the rewriting set to use.
+** p1 -- the first string to check.
+** p2 -- the second string to check -- may be null.
+** e -- the current envelope.
+** pvp -- pointer to token vector.
+** pvpbuf -- buffer space.
+**
+** Returns:
+** EX_UNAVAILABLE -- ruleset doesn't exist.
+** EX_DATAERR -- prescan() failed.
+** EX_OK -- rewrite() was successful.
+** else -- return status from rewrite().
+*/
+
+int
+rscap(rwset, p1, p2, e, pvp, pvpbuf, size)
+ char *rwset;
+ char *p1;
+ char *p2;
+ ENVELOPE *e;
+ char ***pvp;
+ char *pvpbuf;
+ int size;
+{
+ char *volatile buf;
+ int bufsize;
+ int volatile rstat = EX_OK;
+ int rsno;
+ bool saveQuickAbort = QuickAbort;
+ bool saveSuprErrs = SuprErrs;
+ char buf0[MAXLINE];
+ extern char MsgBuf[];
+
+ if (tTd(48, 2))
+ sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1,
+ p2 == NULL ? "(NULL)" : p2);
+
+ if (pvp != NULL)
+ *pvp = NULL;
+ rsno = strtorwset(rwset, NULL, ST_FIND);
+ if (rsno < 0)
+ return EX_UNAVAILABLE;
- if (strcmp(pvp[1], "discard") == 0)
+ if (p2 != NULL)
{
- if (tTd(48, 2))
- dprintf("rscheck: discard mailer selected\n");
- e->e_flags |= EF_DISCARD;
- discard = TRUE;
+ bufsize = strlen(p1) + strlen(p2) + 2;
+ if (bufsize > sizeof buf0)
+ buf = sm_malloc_x(bufsize);
+ else
+ {
+ buf = buf0;
+ bufsize = sizeof buf0;
+ }
+ (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
}
else
{
- int savelogusrerrs = LogUsrErrs;
- static bool logged = FALSE;
-
- /* got an error -- process it */
- saveexitstat = ExitStat;
- LogUsrErrs = FALSE;
- (void) buildaddr(pvp, &a1, 0, e);
- LogUsrErrs = savelogusrerrs;
- rstat = ExitStat;
- ExitStat = saveexitstat;
- if (!logged)
+ bufsize = strlen(p1) + 1;
+ if (bufsize > sizeof buf0)
+ buf = sm_malloc_x(bufsize);
+ else
{
- if (cnt)
- markstats(e, &a1, TRUE);
- logged = TRUE;
+ buf = buf0;
+ bufsize = sizeof buf0;
}
+ (void) sm_strlcpy(buf, p1, bufsize);
}
-
- if (LogLevel >= logl)
+ SM_TRY
{
- char *relay;
- char *p;
- char lbuf[MAXLINE];
-
- p = lbuf;
- if (p2 != NULL)
- {
- snprintf(p, SPACELEFT(lbuf, p),
- ", arg2=%s",
- p2);
- p += strlen(p);
- }
-
- if (host != NULL)
- relay = host;
+ SuprErrs = true;
+ QuickAbort = false;
+ *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL);
+ if (*pvp != NULL)
+ rstat = REWRITE(*pvp, rsno, e);
else
- relay = macvalue('_', e);
- if (relay != NULL)
{
- snprintf(p, SPACELEFT(lbuf, p),
- ", relay=%s", relay);
- p += strlen(p);
+ if (tTd(48, 2))
+ sm_dprintf("rscap: cannot prescan input\n");
+ rstat = EX_DATAERR;
}
- *p = '\0';
- if (discard)
- sm_syslog(LOG_NOTICE, e->e_id,
- "ruleset=%s, arg1=%s%s, discard",
- rwset, p1, lbuf);
- else
- sm_syslog(LOG_NOTICE, e->e_id,
- "ruleset=%s, arg1=%s%s, reject=%s",
- rwset, p1, lbuf, MsgBuf);
}
+ SM_FINALLY
+ {
+ /* clean up */
+ if (buf != buf0)
+ sm_free(buf);
+ SuprErrs = saveSuprErrs;
+ QuickAbort = saveQuickAbort;
- finis:
- /* clean up */
- QuickAbort = saveQuickAbort;
- setstat(rstat);
- if (buf != buf0)
- sm_free(buf);
-
- if (rstat != EX_OK && QuickAbort)
- longjmp(TopFrame, 2);
+ /* prevent information leak, this may contain rewrite error */
+ MsgBuf[0] = '\0';
+ }
+ SM_END_TRY
return rstat;
}
diff --git a/contrib/sendmail/src/queue.c b/contrib/sendmail/src/queue.c
index aeed7f9..6a2da9c 100644
--- a/contrib/sendmail/src/queue.c
+++ b/contrib/sendmail/src/queue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,28 +11,41 @@
*
*/
-
#include <sendmail.h>
-#ifndef lint
-# if QUEUE
-static char id[] = "@(#)$Id: queue.c,v 8.343.4.62 2001/07/20 00:53:01 gshapiro Exp $ (with queueing)";
-# else /* QUEUE */
-static char id[] = "@(#)$Id: queue.c,v 8.343.4.62 2001/07/20 00:53:01 gshapiro Exp $ (without queueing)";
-# endif /* QUEUE */
-#endif /* ! lint */
+SM_RCSID("@(#)$Id: queue.c,v 8.834 2002/01/08 23:04:58 ca Exp $")
+
+#include <dirent.h>
+
+#if SM_CONF_SHM
+# include <sm/shm.h>
+#endif /* SM_CONF_SHM */
-# include <dirent.h>
+# define RELEASE_QUEUE (void) 0
+# define ST_INODE(st) (st).st_ino
-#if QUEUE
-# if _FFR_QUEUEDELAY
-# define QF_VERSION 5 /* version number of this queue format */
+/*
+** Historical notes:
+** QF_VERSION==4 was sendmail 8.10/8.11 without _FFR_QUEUEDELAY
+** QF_VERSION==5 was sendmail 8.10/8.11 with _FFR_QUEUEDELAY
+*/
+
+#if _FFR_QUEUEDELAY
+# define QF_VERSION 7 /* version number of this queue format */
static time_t queuedelay __P((ENVELOPE *));
-# else /* _FFR_QUEUEDELAY */
-# define QF_VERSION 4 /* version number of this queue format */
-# define queuedelay(e) MinQueueAge
-# endif /* _FFR_QUEUEDELAY */
+#define queuedelay_qfver_unsupported(qfver) false
+#else /* _FFR_QUEUEDELAY */
+# define QF_VERSION 6 /* version number of this queue format */
+# define queuedelay(e) MinQueueAge
+#define queuedelay_qfver_unsupported(qfver) ((qfver) == 5 || (qfver) == 7)
+#endif /* _FFR_QUEUEDELAY */
+#if _FFR_QUARANTINE
+static char queue_letter __P((ENVELOPE *, int));
+static bool quarantine_queue_item __P((int, int, ENVELOPE *, char *));
+#endif /* _FFR_QUARANTINE */
+
+/* Naming convention: qgrp: index of queue group, qg: QUEUEGROUP */
/*
** Work queue.
@@ -45,28 +58,214 @@ struct work
bool w_lock; /* is message locked? */
bool w_tooyoung; /* is it too young to run? */
long w_pri; /* priority of message, see below */
- time_t w_ctime; /* creation time of message */
+ time_t w_ctime; /* creation time */
+ time_t w_mtime; /* modification time */
+ int w_qgrp; /* queue group located in */
+ int w_qdir; /* queue directory located in */
struct work *w_next; /* next in queue */
};
typedef struct work WORK;
-static WORK *WorkQ; /* queue of things to be done */
+static WORK *WorkQ; /* queue of things to be done */
+static int NumWorkGroups; /* number of work groups */
+
+/*
+** use of DoQueueRun:
+** NumQueue: indicates that a queue run is needed, look at individual bits
+** 0 - NumQueue-1: indicates that a queue run for this queue group
+** is needed.
+*/
+
+static BITMAP256 volatile DoQueueRun; /* non-interrupt time queue run needed */
+
+/*
+** Work group definition structure.
+** Each work group contains one or more queue groups. This is done
+** to manage the number of queue group runners active at the same time
+** to be within the constraints of MaxQueueChildren (if it is set).
+** The number of queue groups that can be run on the next work run
+** is kept track of. The queue groups are run in a round robin.
+*/
+
+struct workgrp
+{
+ int wg_numqgrp; /* number of queue groups in work grp */
+ int wg_runners; /* total runners */
+ int wg_curqgrp; /* current queue group */
+ QUEUEGRP **wg_qgs; /* array of queue groups */
+ int wg_maxact; /* max # of active runners */
+ time_t wg_lowqintvl; /* lowest queue interval */
+ int wg_restart; /* needs restarting? */
+ int wg_restartcnt; /* count of times restarted */
+};
+
+typedef struct workgrp WORKGRP;
+
+static WORKGRP volatile WorkGrp[MAXWORKGROUPS + 1]; /* work groups */
+
+#if SM_HEAP_CHECK
+static SM_DEBUG_T DebugLeakQ = SM_DEBUG_INITIALIZER("leak_q",
+ "@(#)$Debug: leak_q - trace memory leaks during queue processing $");
+#endif /* SM_HEAP_CHECK */
-static void grow_wlist __P((int));
-static int orderq __P((int, bool));
-static void printctladdr __P((ADDRESS *, FILE *));
-static int print_single_queue __P((int));
-static bool readqf __P((ENVELOPE *));
-static void runqueueevent __P((void));
-static int run_single_queue __P((int, bool, bool));
+/*
+** We use EmptyString instead of "" to avoid
+** 'zero-length format string' warnings from gcc
+*/
+
+static const char EmptyString[] = "";
+
+static void grow_wlist __P((int, int));
+static int multiqueue_cache __P((char *, int, QUEUEGRP *, int, unsigned int *));
+static int gatherq __P((int, int, bool, bool *, bool *));
+static int sortq __P((int));
+static void printctladdr __P((ADDRESS *, SM_FILE_T *));
+static bool readqf __P((ENVELOPE *, bool));
+static void restart_work_group __P((int));
+static void runner_work __P((ENVELOPE *, int, bool, int, int));
+static void schedule_queue_runs __P((bool, int));
static char *strrev __P((char *));
-static ADDRESS *setctluser __P((char *, int));
+static ADDRESS *setctluser __P((char *, int, ENVELOPE *));
+#if _FFR_RHS
+static int sm_strshufflecmp __P((char *, char *));
+static void init_shuffle_alphabet __P(());
+#endif /* _FFR_RHS */
static int workcmpf0();
static int workcmpf1();
static int workcmpf2();
static int workcmpf3();
static int workcmpf4();
+static int workcmpf5();
+static int workcmpf6();
+#if _FFR_RHS
+static int workcmpf7();
+#endif /* _FFR_RHS */
+
+#if RANDOMSHIFT
+# define get_rand_mod(m) ((get_random() >> RANDOMSHIFT) % (m))
+#else /* RANDOMSHIFT */
+# define get_rand_mod(m) (get_random() % (m))
+#endif /* RANDOMSHIFT */
+
+/*
+** File system definition.
+** Used to keep track of how much free space is available
+** on a file system in which one or more queue directories reside.
+*/
+
+typedef struct filesys_shared FILESYS;
+
+struct filesys_shared
+{
+ dev_t fs_dev; /* unique device id */
+ long fs_avail; /* number of free blocks available */
+ long fs_blksize; /* block size, in bytes */
+};
+
+/* probably kept in shared memory */
+static FILESYS FileSys[MAXFILESYS]; /* queue file systems */
+static char *FSPath[MAXFILESYS]; /* pathnames for file systems */
+
+#if SM_CONF_SHM
+
+/*
+** Shared memory data
+**
+** Current layout:
+** size -- size of shared memory segment
+** pid -- pid of owner, should be a unique id to avoid misinterpretations
+** by other processes.
+** tag -- should be a unique id to avoid misinterpretations by others.
+** idea: hash over configuration data that will be stored here.
+** NumFileSys -- number of file systems.
+** FileSys -- (arrary of) structure for used file systems.
+** RSATmpCnt -- counter for number of uses of ephemeral RSA key.
+** QShm -- (array of) structure for information about queue directories.
+*/
+
+/*
+** Queue data in shared memory
+*/
+
+typedef struct queue_shared QUEUE_SHM_T;
+
+struct queue_shared
+{
+ int qs_entries; /* number of entries */
+ /* XXX more to follow? */
+};
+
+static void *Pshm; /* pointer to shared memory */
+static FILESYS *PtrFileSys; /* pointer to queue file system array */
+int ShmId = SM_SHM_NO_ID; /* shared memory id */
+static QUEUE_SHM_T *QShm; /* pointer to shared queue data */
+
+# define SHM_OFF_PID(p) (((char *) (p)) + sizeof(int))
+# define SHM_OFF_TAG(p) (((char *) (p)) + sizeof(pid_t) + sizeof(int))
+# define SHM_OFF_HEAD (sizeof(pid_t) + sizeof(int) * 2)
+
+/* how to access FileSys */
+# define FILE_SYS(i) (PtrFileSys[i])
+
+/* first entry is a tag, for now just the size */
+# define OFF_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD)
+
+/* offset for PNumFileSys */
+# define OFF_NUM_FILE_SYS(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys))
+
+/* offset for PRSATmpCnt */
+# define OFF_RSA_TMP_CNT(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int))
+int *PRSATmpCnt;
+
+/* offset for queue_shm */
+# define OFF_QUEUE_SHM(p) (((char *) (p)) + SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
+
+#define QSHM_ENTRIES(i) QShm[i].qs_entries
+
+/* basic size of shared memory segment */
+# define SM_T_SIZE (SHM_OFF_HEAD + sizeof(FileSys) + sizeof(int) * 2)
+
+static unsigned int hash_q __P((char *, unsigned int));
+
+/*
+** HASH_Q -- simple hash function
+**
+** Parameters:
+** p -- string to hash.
+** h -- hash start value (from previous run).
+**
+** Returns:
+** hash value.
+*/
+
+static unsigned int
+hash_q(p, h)
+ char *p;
+ unsigned int h;
+{
+ int c, d;
+
+ while (*p != '\0')
+ {
+ d = *p++;
+ c = d;
+ c ^= c<<6;
+ h += (c<<11) ^ (c>>1);
+ h ^= (d<<14) + (d<<7) + (d<<4) + d;
+ }
+ return h;
+}
+
+#else /* SM_CONF_SHM */
+# define FILE_SYS(i) FileSys[i]
+#endif /* SM_CONF_SHM */
+
+/* access to the various components of file system data */
+#define FILE_SYS_NAME(i) FSPath[i]
+#define FILE_SYS_AVAIL(i) FILE_SYS(i).fs_avail
+#define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize
+#define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev
/*
** Current qf file field assignments:
@@ -75,9 +274,10 @@ static int workcmpf4();
** B body type
** C controlling user
** D data file name
+** d data file directory name (added in 8.12)
** E error recipient
** F flag bits
-** G queue delay algorithm
+** G queue delay algorithm (_FFR_QUEUEDELAY)
** H header
** I data file's inode number
** K time of last delivery attempt
@@ -85,43 +285,44 @@ static int workcmpf4();
** M message (obsolete)
** N number of delivery attempts
** P message priority
+** q quarantine reason (_FFR_QUARANTINE)
** Q original recipient (ORCPT=)
+** r final recipient (Final-Recipient: DSN field)
** R recipient
** S sender
** T init time
** V queue file version
-** X character set (_FFR_SAVE_CHARSET)
-** Y current delay
+** X free (was: character set if _FFR_SAVE_CHARSET)
+** Y current delay (_FFR_QUEUEDELAY)
** Z original envelope id from ESMTP
+** ! deliver by (added in 8.12)
** $ define macro
** . terminate file
*/
- /*
+/*
** QUEUEUP -- queue a message up for future transmission.
**
** Parameters:
** e -- the envelope to queue up.
-** announce -- if TRUE, tell when you are queueing up.
+** announce -- if true, tell when you are queueing up.
+** msync -- if true, then fsync() if SuperSafe interactive mode.
**
** Returns:
** none.
**
** Side Effects:
-** The current request are saved in a control file.
+** The current request is saved in a control file.
** The queue file is left locked.
*/
-# define TEMPQF_LETTER 'T'
-# define LOSEQF_LETTER 'Q'
-
void
-queueup(e, announce)
+queueup(e, announce, msync)
register ENVELOPE *e;
bool announce;
+ bool msync;
{
- char *qf;
- register FILE *tfp;
+ register SM_FILE_T *tfp;
register HDR *h;
register ADDRESS *q;
int tfd = -1;
@@ -130,7 +331,9 @@ queueup(e, announce)
register char *p;
MAILER nullmailer;
MCI mcibuf;
+ char qf[MAXPATHLEN];
char tf[MAXPATHLEN];
+ char df[MAXPATHLEN];
char buf[MAXLINE];
/*
@@ -138,36 +341,28 @@ queueup(e, announce)
*/
newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
-
- /* if newid, queuename will create a locked qf file in e->lockfp */
- (void) strlcpy(tf, queuename(e, 't'), sizeof tf);
+ (void) sm_strlcpy(tf, queuename(e, NEWQFL_LETTER), sizeof tf);
tfp = e->e_lockfp;
if (tfp == NULL)
- newid = FALSE;
+ newid = false;
- /* if newid, just write the qf file directly (instead of tf file) */
+ /* if newid, write the queue file directly (instead of temp file) */
if (!newid)
{
- int flags;
-
- flags = O_CREAT|O_WRONLY|O_EXCL;
+ const int flags = O_CREAT|O_WRONLY|O_EXCL;
/* get a locked tf file */
for (i = 0; i < 128; i++)
{
if (tfd < 0)
{
-#if _FFR_QUEUE_FILE_MODE
- MODE_T oldumask;
+ MODE_T oldumask = 0;
if (bitset(S_IWGRP, QueueFileMode))
oldumask = umask(002);
tfd = open(tf, flags, QueueFileMode);
if (bitset(S_IWGRP, QueueFileMode))
(void) umask(oldumask);
-#else /* _FFR_QUEUE_FILE_MODE */
- tfd = open(tf, flags, FileMode);
-#endif /* _FFR_QUEUE_FILE_MODE */
if (tfd < 0)
{
@@ -176,7 +371,8 @@ queueup(e, announce)
if (LogLevel > 0 && (i % 32) == 0)
sm_syslog(LOG_ALERT, e->e_id,
"queueup: cannot create %s, uid=%d: %s",
- tf, geteuid(), errstring(errno));
+ tf, geteuid(),
+ sm_errstring(errno));
}
}
if (tfd >= 0)
@@ -186,7 +382,7 @@ queueup(e, announce)
else if (LogLevel > 0 && (i % 32) == 0)
sm_syslog(LOG_ALERT, e->e_id,
"queueup: cannot lock %s: %s",
- tf, errstring(errno));
+ tf, sm_errstring(errno));
if ((i % 32) == 31)
{
(void) close(tfd);
@@ -202,11 +398,13 @@ queueup(e, announce)
else
(void) sleep(i % 32);
}
- if (tfd < 0 || (tfp = fdopen(tfd, "w")) == NULL)
+ if (tfd < 0 || (tfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &tfd, SM_IO_WRONLY,
+ NULL)) == NULL)
{
int save_errno = errno;
- printopenfds(TRUE);
+ printopenfds(true);
errno = save_errno;
syserr("!queueup: cannot create queue temp file %s, uid=%d",
tf, geteuid());
@@ -214,146 +412,192 @@ queueup(e, announce)
}
if (tTd(40, 1))
- dprintf("\n>>>>> queueing %s/qf%s%s >>>>>\n",
- qid_printqueue(e->e_queuedir), e->e_id,
- newid ? " (new id)" : "");
+ sm_dprintf("\n>>>>> queueing %s/%s%s >>>>>\n",
+ qid_printqueue(e->e_qgrp, e->e_qdir),
+ queuename(e, ANYQFL_LETTER),
+ newid ? " (new id)" : "");
if (tTd(40, 3))
{
- dprintf(" e_flags=");
+ sm_dprintf(" e_flags=");
printenvflags(e);
}
if (tTd(40, 32))
{
- dprintf(" sendq=");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf(" sendq=");
+ printaddr(e->e_sendqueue, true);
}
if (tTd(40, 9))
{
- dprintf(" tfp=");
- dumpfd(fileno(tfp), TRUE, FALSE);
- dprintf(" lockfp=");
+ sm_dprintf(" tfp=");
+ dumpfd(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL), true, false);
+ sm_dprintf(" lockfp=");
if (e->e_lockfp == NULL)
- dprintf("NULL\n");
+ sm_dprintf("NULL\n");
else
- dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
+ dumpfd(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL),
+ true, false);
}
/*
** If there is no data file yet, create one.
*/
+ (void) sm_strlcpy(df, queuename(e, DATAFL_LETTER), sizeof df);
if (bitset(EF_HAS_DF, e->e_flags))
{
- if (e->e_dfp != NULL && bfcommit(e->e_dfp) < 0)
+ if (e->e_dfp != NULL &&
+ SuperSafe != SAFE_REALLY &&
+ sm_io_setinfo(e->e_dfp, SM_BF_COMMIT, NULL) < 0 &&
+ errno != EINVAL)
+ {
syserr("!queueup: cannot commit data file %s, uid=%d",
- queuename(e, 'd'), geteuid());
+ queuename(e, DATAFL_LETTER), geteuid());
+ }
+ if (e->e_dfp != NULL &&
+ SuperSafe == SAFE_INTERACTIVE && msync)
+ {
+ if (tTd(40,32))
+ sm_syslog(LOG_INFO, e->e_id,
+ "queueup: fsync(e->e_dfp)");
+
+ if (fsync(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD,
+ NULL)) < 0)
+ {
+ if (newid)
+ syserr("!552 Error writing data file %s",
+ df);
+ else
+ syserr("!452 Error writing data file %s",
+ df);
+ }
+ }
}
else
{
int dfd;
- register FILE *dfp = NULL;
- char dfname[MAXPATHLEN];
+ MODE_T oldumask = 0;
+ register SM_FILE_T *dfp = NULL;
struct stat stbuf;
- if (e->e_dfp != NULL && bftest(e->e_dfp))
+ if (e->e_dfp != NULL &&
+ sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
syserr("committing over bf file");
- (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
-#if _FFR_QUEUE_FILE_MODE
- {
- MODE_T oldumask;
-
- if (bitset(S_IWGRP, QueueFileMode))
- oldumask = umask(002);
- dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC,
- QueueFileMode);
- if (bitset(S_IWGRP, QueueFileMode))
- (void) umask(oldumask);
- }
-#else /* _FFR_QUEUE_FILE_MODE */
- dfd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
-#endif /* _FFR_QUEUE_FILE_MODE */
- if (dfd < 0 || (dfp = fdopen(dfd, "w")) == NULL)
+ if (bitset(S_IWGRP, QueueFileMode))
+ oldumask = umask(002);
+ dfd = open(df, O_WRONLY|O_CREAT|O_TRUNC, QueueFileMode);
+ if (bitset(S_IWGRP, QueueFileMode))
+ (void) umask(oldumask);
+ if (dfd < 0 || (dfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &dfd, SM_IO_WRONLY,
+ NULL)) == NULL)
syserr("!queueup: cannot create data temp file %s, uid=%d",
- dfname, geteuid());
+ df, geteuid());
if (fstat(dfd, &stbuf) < 0)
e->e_dfino = -1;
else
{
e->e_dfdev = stbuf.st_dev;
- e->e_dfino = stbuf.st_ino;
+ e->e_dfino = ST_INODE(stbuf);
}
e->e_flags |= EF_HAS_DF;
memset(&mcibuf, '\0', sizeof mcibuf);
mcibuf.mci_out = dfp;
mcibuf.mci_mailer = FileMailer;
(*e->e_putbody)(&mcibuf, e, NULL);
- if (fclose(dfp) < 0)
+
+ if (SuperSafe == SAFE_REALLY ||
+ (SuperSafe == SAFE_INTERACTIVE && msync))
+ {
+ if (tTd(40,32))
+ sm_syslog(LOG_INFO, e->e_id,
+ "queueup: fsync(dfp)");
+
+ if (fsync(sm_io_getinfo(dfp, SM_IO_WHAT_FD, NULL)) < 0)
+ {
+ if (newid)
+ syserr("!552 Error writing data file %s",
+ df);
+ else
+ syserr("!452 Error writing data file %s",
+ df);
+ }
+ }
+
+ if (sm_io_close(dfp, SM_TIME_DEFAULT) < 0)
syserr("!queueup: cannot save data temp file %s, uid=%d",
- dfname, geteuid());
+ df, geteuid());
e->e_putbody = putbody;
}
/*
** Output future work requests.
** Priority and creation time should be first, since
- ** they are required by orderq.
+ ** they are required by gatherq.
*/
/* output queue version number (must be first!) */
- fprintf(tfp, "V%d\n", QF_VERSION);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "V%d\n", QF_VERSION);
/* output creation time */
- fprintf(tfp, "T%ld\n", (long) e->e_ctime);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "T%ld\n", (long) e->e_ctime);
/* output last delivery time */
-# if _FFR_QUEUEDELAY
- fprintf(tfp, "K%ld\n", (long) e->e_dtime);
- fprintf(tfp, "G%d\n", e->e_queuealg);
- fprintf(tfp, "Y%ld\n", (long) e->e_queuedelay);
+#if _FFR_QUEUEDELAY
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "G%d\n", e->e_queuealg);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Y%ld\n", (long) e->e_queuedelay);
if (tTd(40, 64))
sm_syslog(LOG_INFO, e->e_id,
"queue alg: %d delay %ld next: %ld (now: %ld)\n",
e->e_queuealg, e->e_queuedelay, e->e_dtime, curtime());
-# else /* _FFR_QUEUEDELAY */
- fprintf(tfp, "K%ld\n", (long) e->e_dtime);
-# endif /* _FFR_QUEUEDELAY */
+#else /* _FFR_QUEUEDELAY */
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "K%ld\n", (long) e->e_dtime);
+#endif /* _FFR_QUEUEDELAY */
/* output number of delivery attempts */
- fprintf(tfp, "N%d\n", e->e_ntries);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "N%d\n", e->e_ntries);
/* output message priority */
- fprintf(tfp, "P%ld\n", e->e_msgpriority);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "P%ld\n", e->e_msgpriority);
+
+ /*
+ ** If data file is in a different directory than the queue file,
+ ** output a "d" record naming the directory of the data file.
+ */
+
+ if (e->e_dfqgrp != e->e_qgrp)
+ {
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "d%s\n",
+ Queue[e->e_dfqgrp]->qg_qpaths[e->e_dfqdir].qp_name);
+ }
/* output inode number of data file */
/* XXX should probably include device major/minor too */
if (e->e_dfino != -1)
{
- /*CONSTCOND*/
- if (sizeof e->e_dfino > sizeof(long))
- fprintf(tfp, "I%ld/%ld/%s\n",
- (long) major(e->e_dfdev),
- (long) minor(e->e_dfdev),
- quad_to_string(e->e_dfino));
- else
- fprintf(tfp, "I%ld/%ld/%lu\n",
- (long) major(e->e_dfdev),
- (long) minor(e->e_dfdev),
- (unsigned long) e->e_dfino);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "I%ld/%ld/%llu\n",
+ (long) major(e->e_dfdev),
+ (long) minor(e->e_dfdev),
+ (ULONGLONG_T) e->e_dfino);
}
/* output body type */
if (e->e_bodytype != NULL)
- fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "B%s\n",
+ denlstring(e->e_bodytype, true, false));
-# if _FFR_SAVE_CHARSET
- if (e->e_charset != NULL)
- fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
-# endif /* _FFR_SAVE_CHARSET */
+#if _FFR_QUARANTINE
+ /* quarantine reason */
+ if (e->e_quarmsg != NULL)
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "q%s\n",
+ denlstring(e->e_quarmsg, true, false));
+#endif /* _FFR_QUARANTINE */
/* message from envelope, if it exists */
if (e->e_message != NULL)
- fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
+ denlstring(e->e_message, true, false));
/* send various flag bits through */
p = buf;
@@ -369,28 +613,35 @@ queueup(e, announce)
*p++ = 'd';
if (bitset(EF_NO_BODY_RETN, e->e_flags))
*p++ = 'n';
+ if (bitset(EF_SPLIT, e->e_flags))
+ *p++ = 's';
*p++ = '\0';
if (buf[0] != '\0')
- fprintf(tfp, "F%s\n", buf);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "F%s\n", buf);
/* save $={persistentMacros} macro values */
- queueup_macros(macid("{persistentMacros}", NULL), tfp, e);
+ queueup_macros(macid("{persistentMacros}"), tfp, e);
/* output name of sender */
if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
p = e->e_sender;
else
p = e->e_from.q_paddr;
- fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "S%s\n",
+ denlstring(p, true, false));
/* output ESMTP-supplied "original" information */
if (e->e_envid != NULL)
- fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Z%s\n",
+ denlstring(e->e_envid, true, false));
/* output AUTH= parameter */
if (e->e_auth_param != NULL)
- fprintf(tfp, "A%s\n", denlstring(e->e_auth_param,
- TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "A%s\n",
+ denlstring(e->e_auth_param, true, false));
+ if (e->e_dlvr_flag != 0)
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "!%c %ld\n",
+ (char) e->e_dlvr_flag, e->e_deliver_by);
/* output list of recipient addresses */
printctladdr(NULL, NULL);
@@ -399,40 +650,58 @@ queueup(e, announce)
if (!QS_IS_UNDELIVERED(q->q_state))
continue;
+ /* message for this recipient, if it exists */
+ if (q->q_message != NULL)
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "M%s\n",
+ denlstring(q->q_message, true,
+ false));
+
printctladdr(q, tfp);
if (q->q_orcpt != NULL)
- fprintf(tfp, "Q%s\n",
- denlstring(q->q_orcpt, TRUE, FALSE));
-
- (void) putc('R', tfp);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "Q%s\n",
+ denlstring(q->q_orcpt, true,
+ false));
+ if (q->q_finalrcpt != NULL)
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "r%s\n",
+ denlstring(q->q_finalrcpt, true,
+ false));
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'R');
if (bitset(QPRIMARY, q->q_flags))
- (void) putc('P', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'P');
if (bitset(QHASNOTIFY, q->q_flags))
- (void) putc('N', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'N');
if (bitset(QPINGONSUCCESS, q->q_flags))
- (void) putc('S', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'S');
if (bitset(QPINGONFAILURE, q->q_flags))
- (void) putc('F', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'F');
if (bitset(QPINGONDELAY, q->q_flags))
- (void) putc('D', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D');
if (q->q_alias != NULL &&
bitset(QALIAS, q->q_alias->q_flags))
- (void) putc('A', tfp);
- (void) putc(':', tfp);
- (void) fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A');
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, ':');
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s\n",
+ denlstring(q->q_paddr, true, false));
if (announce)
{
+ char *tag = "queued";
+
+#if _FFR_QUARANTINE
+ if (e->e_quarmsg != NULL)
+ tag = "quarantined";
+#endif /* _FFR_QUARANTINE */
+
e->e_to = q->q_paddr;
- message("queued");
+ message(tag);
if (LogLevel > 8)
logdelivery(q->q_mailer, NULL, q->q_status,
- "queued", NULL, (time_t) 0, e);
+ tag, NULL, (time_t) 0, e);
e->e_to = NULL;
}
if (tTd(40, 1))
{
- dprintf("queueing ");
- printaddr(q, FALSE);
+ sm_dprintf("queueing ");
+ printaddr(q, false);
}
}
@@ -454,7 +723,7 @@ queueup(e, announce)
mcibuf.mci_mailer = &nullmailer;
mcibuf.mci_out = tfp;
- define('g', "\201f", e);
+ macdefine(&e->e_macro, A_PERM, 'g', "\201f");
for (h = e->e_header; h != NULL; h = h->h_link)
{
if (h->h_value == NULL)
@@ -474,16 +743,18 @@ queueup(e, announce)
}
/* output this header */
- fprintf(tfp, "H?");
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "H?");
/* output conditional macro if present */
if (h->h_macro != '\0')
{
if (bitset(0200, h->h_macro))
- fprintf(tfp, "${%s}",
- macname(bitidx(h->h_macro)));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
+ "${%s}",
+ macname(bitidx(h->h_macro)));
else
- fprintf(tfp, "$%c", h->h_macro);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT,
+ "$%c", h->h_macro);
}
else if (!bitzerop(h->h_mflags) &&
bitset(H_CHECK|H_ACHECK, h->h_flags))
@@ -493,28 +764,29 @@ queueup(e, announce)
/* if conditional, output the set of conditions */
for (j = '\0'; j <= '\177'; j++)
if (bitnset(j, h->h_mflags))
- (void) putc(j, tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT,
+ j);
}
- (void) putc('?', tfp);
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, '?');
/* output the header: expand macros, convert addresses */
if (bitset(H_DEFAULT, h->h_flags) &&
!bitset(H_BINDLATE, h->h_flags))
{
- fprintf(tfp, "%s: %s\n",
- h->h_field,
- denlstring(buf, FALSE, TRUE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n",
+ h->h_field,
+ denlstring(buf, false, true));
}
else if (bitset(H_FROM|H_RCPT, h->h_flags) &&
!bitset(H_BINDLATE, h->h_flags))
{
bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
- FILE *savetrace = TrafficLogFile;
+ SM_FILE_T *savetrace = TrafficLogFile;
TrafficLogFile = NULL;
if (bitset(H_FROM, h->h_flags))
- oldstyle = FALSE;
+ oldstyle = false;
commaize(h, h->h_value, oldstyle, &mcibuf, e);
@@ -522,9 +794,10 @@ queueup(e, announce)
}
else
{
- fprintf(tfp, "%s: %s\n",
- h->h_field,
- denlstring(h->h_value, FALSE, TRUE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "%s: %s\n",
+ h->h_field,
+ denlstring(h->h_value, false,
+ true));
}
}
@@ -535,11 +808,13 @@ queueup(e, announce)
** scurrilous crackers from appending any data.
*/
- fprintf(tfp, ".\n");
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ".\n");
- if (fflush(tfp) != 0 ||
- (SuperSafe && fsync(fileno(tfp)) < 0) ||
- ferror(tfp))
+ if (sm_io_flush(tfp, SM_TIME_DEFAULT) != 0 ||
+ ((SuperSafe == SAFE_REALLY ||
+ (SuperSafe == SAFE_INTERACTIVE && msync)) &&
+ fsync(sm_io_getinfo(tfp, SM_IO_WHAT_FD, NULL)) < 0) ||
+ sm_io_error(tfp))
{
if (newid)
syserr("!552 Error writing control file %s", tf);
@@ -549,44 +824,112 @@ queueup(e, announce)
if (!newid)
{
- /* rename (locked) tf to be (locked) qf */
- qf = queuename(e, 'q');
+#if _FFR_QUARANTINE
+ char new = queue_letter(e, ANYQFL_LETTER);
+#endif /* _FFR_QUARANTINE */
+
+ /* rename (locked) tf to be (locked) [qh]f */
+ (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER),
+ sizeof qf);
if (rename(tf, qf) < 0)
syserr("cannot rename(%s, %s), uid=%d",
tf, qf, geteuid());
+# if _FFR_QUARANTINE
+ else
+ {
+ /*
+ ** Check if type has changed and only
+ ** remove the old item if the rename above
+ ** succeeded.
+ */
+
+ if (e->e_qfletter != '\0' &&
+ e->e_qfletter != new)
+ {
+ if (tTd(40, 5))
+ {
+ sm_dprintf("type changed from %c to %c\n",
+ e->e_qfletter, new);
+ }
+
+ if (unlink(queuename(e, e->e_qfletter)) < 0)
+ {
+ /* XXX: something more drastic? */
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, e->e_id,
+ "queueup: unlink(%s) failed: %s",
+ queuename(e, e->e_qfletter),
+ sm_errstring(errno));
+ }
+ }
+ }
+ e->e_qfletter = new;
+# endif /* _FFR_QUARANTINE */
+
/*
- ** fsync() after renaming to make sure
- ** metadata is written to disk on
- ** filesystems in which renames are
- ** not guaranteed such as softupdates.
+ ** fsync() after renaming to make sure metadata is
+ ** written to disk on filesystems in which renames are
+ ** not guaranteed.
*/
- if (tfd >= 0 && SuperSafe && fsync(tfd) < 0)
- syserr("!queueup: cannot fsync queue temp file %s", tf);
+ if (SuperSafe != SAFE_NO)
+ {
+ /* for softupdates */
+ if (tfd >= 0 && fsync(tfd) < 0)
+ {
+ syserr("!queueup: cannot fsync queue temp file %s",
+ tf);
+ }
+ SYNC_DIR(qf, true);
+ }
- /* close and unlock old (locked) qf */
+ /* close and unlock old (locked) queue file */
if (e->e_lockfp != NULL)
- (void) fclose(e->e_lockfp);
+ (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
e->e_lockfp = tfp;
+
+ /* save log info */
+ if (LogLevel > 79)
+ sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", qf);
}
else
- qf = tf;
+ {
+ /* save log info */
+ if (LogLevel > 79)
+ sm_syslog(LOG_DEBUG, e->e_id, "queueup %s", tf);
+
+#if _FFR_QUARANTINE
+ e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
+#endif /* _FFR_QUARANTINE */
+ }
+
errno = 0;
e->e_flags |= EF_INQUEUE;
- /* save log info */
- if (LogLevel > 79)
- sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
-
if (tTd(40, 1))
- dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
+ sm_dprintf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
return;
}
+/*
+** PRINTCTLADDR -- print control address to file.
+**
+** Parameters:
+** a -- address.
+** tfp -- file pointer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** The control address (if changed) is printed to the file.
+** The last control address and uid are saved.
+*/
+
static void
printctladdr(a, tfp)
register ADDRESS *a;
- FILE *tfp;
+ SM_FILE_T *tfp;
{
char *user;
register ADDRESS *q;
@@ -599,7 +942,7 @@ printctladdr(a, tfp)
if (a == NULL || a->q_alias == NULL || tfp == NULL)
{
if (lastctladdr != NULL && tfp != NULL)
- fprintf(tfp, "C\n");
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C\n");
lastctladdr = NULL;
lastuid = 0;
return;
@@ -629,77 +972,414 @@ printctladdr(a, tfp)
lastctladdr = a;
if (uid == 0 || user == NULL || user[0] == '\0')
- fprintf(tfp, "C");
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C");
else
- fprintf(tfp, "C%s:%ld:%ld",
- denlstring(user, TRUE, FALSE), (long) uid, (long) gid);
- fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, "C%s:%ld:%ld",
+ denlstring(user, true, false), (long) uid,
+ (long) gid);
+ (void) sm_io_fprintf(tfp, SM_TIME_DEFAULT, ":%s\n",
+ denlstring(a->q_paddr, true, false));
}
- /*
+
+/*
+** RUNNERS_SIGTERM -- propagate a SIGTERM to queue runner process
+**
+** This propagates the signal to the child processes that are queue
+** runners. This is for a queue runner "cleanup". After all of the
+** child queue runner processes are signaled (it should be SIGTERM
+** being the sig) then the old signal handler (Oldsh) is called
+** to handle any cleanup set for this process (provided it is not
+** SIG_DFL or SIG_IGN). The signal may not be handled immediately
+** if the BlockOldsh flag is set. If the current process doesn't
+** have a parent then handle the signal immediately, regardless of
+** BlockOldsh.
+**
+** Parameters:
+** sig -- the signal number being sent
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets the NoMoreRunners boolean to true to stop more runners
+** from being started in runqueue().
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+static bool volatile NoMoreRunners = false;
+static sigfunc_t Oldsh_term = SIG_DFL;
+static sigfunc_t Oldsh_hup = SIG_DFL;
+static sigfunc_t volatile Oldsh = SIG_DFL;
+static bool BlockOldsh = false;
+static int volatile Oldsig = 0;
+static SIGFUNC_DECL runners_sigterm __P((int));
+static SIGFUNC_DECL runners_sighup __P((int));
+
+static SIGFUNC_DECL
+runners_sigterm(sig)
+ int sig;
+{
+ int save_errno = errno;
+
+ FIX_SYSV_SIGNAL(sig, runners_sigterm);
+ errno = save_errno;
+ CHECK_CRITICAL(sig);
+ NoMoreRunners = true;
+ Oldsh = Oldsh_term;
+ Oldsig = sig;
+ proc_list_signal(PROC_QUEUE, sig);
+
+ if (!BlockOldsh || getppid() <= 1)
+ {
+ /* Check that a valid 'old signal handler' is callable */
+ if (Oldsh_term != SIG_DFL && Oldsh_term != SIG_IGN &&
+ Oldsh_term != runners_sigterm)
+ (*Oldsh_term)(sig);
+ }
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+/*
+** RUNNERS_SIGHUP -- propagate a SIGHUP to queue runner process
+**
+** This propagates the signal to the child processes that are queue
+** runners. This is for a queue runner "cleanup". After all of the
+** child queue runner processes are signaled (it should be SIGHUP
+** being the sig) then the old signal handler (Oldsh) is called to
+** handle any cleanup set for this process (provided it is not SIG_DFL
+** or SIG_IGN). The signal may not be handled immediately if the
+** BlockOldsh flag is set. If the current process doesn't have
+** a parent then handle the signal immediately, regardless of
+** BlockOldsh.
+**
+** Parameters:
+** sig -- the signal number being sent
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets the NoMoreRunners boolean to true to stop more runners
+** from being started in runqueue().
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+static SIGFUNC_DECL
+runners_sighup(sig)
+ int sig;
+{
+ int save_errno = errno;
+
+ FIX_SYSV_SIGNAL(sig, runners_sighup);
+ errno = save_errno;
+ CHECK_CRITICAL(sig);
+ NoMoreRunners = true;
+ Oldsh = Oldsh_hup;
+ Oldsig = sig;
+ proc_list_signal(PROC_QUEUE, sig);
+
+ if (!BlockOldsh || getppid() <= 1)
+ {
+ /* Check that a valid 'old signal handler' is callable */
+ if (Oldsh_hup != SIG_DFL && Oldsh_hup != SIG_IGN &&
+ Oldsh_hup != runners_sighup)
+ (*Oldsh_hup)(sig);
+ }
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+/*
+** MARK_WORK_GROUP_RESTART -- mark a work group as needing a restart
+**
+** Sets a workgroup for restarting.
+**
+** Parameters:
+** wgrp -- the work group id to restart.
+** reason -- why (signal?), -1 to turn off restart
+**
+** Returns:
+** none.
+**
+** Side effects:
+** May set global RestartWorkGroup to true.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+void
+mark_work_group_restart(wgrp, reason)
+ int wgrp;
+ int reason;
+{
+ if (wgrp < 0 || wgrp > NumWorkGroups)
+ return;
+
+ WorkGrp[wgrp].wg_restart = reason;
+ if (reason >= 0)
+ RestartWorkGroup = true;
+}
+/*
+** RESTART_MARKED_WORK_GROUPS -- restart work groups marked as needing restart
+**
+** Restart any workgroup marked as needing a restart provided more
+** runners are allowed.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side effects:
+** Sets global RestartWorkGroup to false.
+*/
+
+void
+restart_marked_work_groups()
+{
+ int i;
+ int wasblocked;
+
+ if (NoMoreRunners)
+ return;
+
+ /* Block SIGCHLD so reapchild() doesn't mess with us */
+ wasblocked = sm_blocksignal(SIGCHLD);
+
+ for (i = 0; i < NumWorkGroups; i++)
+ {
+ if (WorkGrp[i].wg_restart >= 0)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_ERR, NOQID,
+ "restart queue runner=%d due to signal 0x%x",
+ i, WorkGrp[i].wg_restart);
+ restart_work_group(i);
+ }
+ }
+ RestartWorkGroup = false;
+
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGCHLD);
+}
+/*
+** RESTART_WORK_GROUP -- restart a specific work group
+**
+** Restart a specific workgroup provided more runners are allowed.
+** If the requested work group has been restarted too many times log
+** this and refuse to restart.
+**
+** Parameters:
+** wgrp -- the work group id to restart
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** starts another process doing the work of wgrp
+*/
+
+#define MAX_PERSIST_RESTART 10 /* max allowed number of restarts */
+
+static void
+restart_work_group(wgrp)
+ int wgrp;
+{
+ if (NoMoreRunners ||
+ wgrp < 0 || wgrp > NumWorkGroups)
+ return;
+
+ WorkGrp[wgrp].wg_restart = -1;
+ if (WorkGrp[wgrp].wg_restartcnt < MAX_PERSIST_RESTART)
+ {
+ /* avoid overflow; increment here */
+ WorkGrp[wgrp].wg_restartcnt++;
+ (void) run_work_group(wgrp, true, false, true, true);
+ }
+ else
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "ERROR: persistent queue runner=%d restarted too many times, queue runner lost",
+ wgrp);
+ }
+}
+/*
+** SCHEDULE_QUEUE_RUNS -- schedule the next queue run for a work group.
+**
+** Parameters:
+** runall -- schedule even if individual bit is not set.
+** wgrp -- the work group id to schedule.
+**
+** Returns:
+** nothing
+*/
+
+#define INCR_MOD(v, m) if (++v >= m) \
+ v = 0; \
+ else
+
+static void
+schedule_queue_runs(runall, wgrp)
+ bool runall;
+ int wgrp;
+{
+ int qgrp, cgrp, endgrp;
+
+ /*
+ ** This is a bit ugly since we have to duplicate the
+ ** code that "walks" through a work queue group.
+ */
+
+ cgrp = endgrp = WorkGrp[wgrp].wg_curqgrp;
+ do
+ {
+ time_t qintvl;
+
+ qgrp = WorkGrp[wgrp].wg_qgs[cgrp]->qg_index;
+ if (Queue[qgrp]->qg_queueintvl > 0)
+ qintvl = Queue[qgrp]->qg_queueintvl;
+ else if (QueueIntvl > 0)
+ qintvl = QueueIntvl;
+ else
+ qintvl = (time_t) 0;
+ if ((runall || bitnset(qgrp, DoQueueRun)) && qintvl > 0)
+ (void) sm_setevent(qintvl, runqueueevent, qgrp);
+#if _FFR_QUEUE_SCHED_DBG
+ if (tTd(69, 10))
+ sm_syslog(LOG_INFO, NOQID,
+ "sqr: wgrp=%d, cgrp=%d, qgrp=%d, intvl=%ld, QI=%ld, runall=%d, bit=%d, sched=%d",
+ wgrp, cgrp, qgrp, Queue[qgrp]->qg_queueintvl,
+ QueueIntvl, runall, bitnset(qgrp, DoQueueRun),
+ (runall || bitnset(qgrp, DoQueueRun)) &&
+ qintvl > 0);
+#endif /* _FFR_QUEUE_SCHED_DBG */
+ clrbitn(qgrp, DoQueueRun);
+ INCR_MOD(cgrp, WorkGrp[wgrp].wg_numqgrp);
+ } while (endgrp != cgrp);
+}
+/*
** RUNQUEUE -- run the jobs in the queue.
**
** Gets the stuff out of the queue in some presumably logical
** order and processes them.
**
** Parameters:
-** forkflag -- TRUE if the queue scanning should be done in
+** forkflag -- true if the queue scanning should be done in
** a child process. We double-fork so it is not our
** child and we don't have to clean up after it.
-** FALSE can be ignored if we have multiple queues.
-** verbose -- if TRUE, print out status information.
+** false can be ignored if we have multiple queues.
+** verbose -- if true, print out status information.
+** persistent -- persistent queue runner?
+** runall -- run all groups or only a subset (DoQueueRun)?
**
** Returns:
-** TRUE if the queue run successfully began.
+** true if the queue run successfully began.
**
** Side Effects:
-** runs things in the mail queue.
+** runs things in the mail queue using run_work_group().
+** maybe schedules next queue run.
+**
*/
static ENVELOPE QueueEnvelope; /* the queue run envelope */
-int NumQueues = 0; /* number of queues */
static time_t LastQueueTime = 0; /* last time a queue ID assigned */
static pid_t LastQueuePid = -1; /* last PID which had a queue ID */
-struct qpaths_s
-{
- char *qp_name; /* name of queue dir */
- short qp_subdirs; /* use subdirs? */
-};
-
-typedef struct qpaths_s QPATHS;
-
/* values for qp_supdirs */
#define QP_NOSUB 0x0000 /* No subdirectories */
#define QP_SUBDF 0x0001 /* "df" subdirectory */
#define QP_SUBQF 0x0002 /* "qf" subdirectory */
#define QP_SUBXF 0x0004 /* "xf" subdirectory */
-static QPATHS *QPaths = NULL; /* list of queue directories */
-
bool
-runqueue(forkflag, verbose)
+runqueue(forkflag, verbose, persistent, runall)
bool forkflag;
bool verbose;
+ bool persistent;
+ bool runall;
{
int i;
- bool ret = TRUE;
+ bool ret = true;
static int curnum = 0;
+ sigfunc_t cursh;
+#if SM_HEAP_CHECK
+ SM_NONVOLATILE int oldgroup = 0;
+
+ if (sm_debug_active(&DebugLeakQ, 1))
+ {
+ oldgroup = sm_heap_group();
+ sm_heap_newgroup();
+ sm_dprintf("runqueue() heap group #%d\n", sm_heap_group());
+ }
+#endif /* SM_HEAP_CHECK */
+
+ /* queue run has been started, don't do any more this time */
+ clrbitn(NumQueue, DoQueueRun);
- DoQueueRun = FALSE;
+ /* more than one queue or more than one directory per queue */
+ if (!forkflag && !verbose &&
+ (WorkGrp[0].wg_qgs[0]->qg_numqueues > 1 || NumWorkGroups > 1 ||
+ WorkGrp[0].wg_numqgrp > 1))
+ forkflag = true;
+ /*
+ ** For controlling queue runners via signals sent to this process.
+ ** Oldsh* will get called too by runners_sig* (if it is not SIG_IGN
+ ** or SIG_DFL) to preserve cleanup behavior. Now that this process
+ ** will have children (and perhaps grandchildren) this handler will
+ ** be left in place. This is because this process, once it has
+ ** finished spinning off queue runners, may go back to doing something
+ ** else (like being a daemon). And we still want on a SIG{TERM,HUP} to
+ ** clean up the child queue runners. Only install 'runners_sig*' once
+ ** else we'll get stuck looping forever.
+ */
- if (!forkflag && NumQueues > 1 && !verbose)
- forkflag = TRUE;
+ cursh = sm_signal(SIGTERM, runners_sigterm);
+ if (cursh != runners_sigterm)
+ Oldsh_term = cursh;
+ cursh = sm_signal(SIGHUP, runners_sighup);
+ if (cursh != runners_sighup)
+ Oldsh_hup = cursh;
- for (i = 0; i < NumQueues; i++)
+ for (i = 0; i < NumWorkGroups && !NoMoreRunners; i++)
{
/*
- ** Pick up where we left off, in case we
- ** used up all the children last time
- ** without finishing.
+ ** If MaxQueueChildren active then test whether the start
+ ** of the next queue group's additional queue runners (maximum)
+ ** will result in MaxQueueChildren being exceeded.
+ **
+ ** Note: do not use continue; even though another workgroup
+ ** may have fewer queue runners, this would be "unfair",
+ ** i.e., this work group might "starve" then.
+ */
+
+#if _FFR_QUEUE_SCHED_DBG
+ if (tTd(69, 10))
+ sm_syslog(LOG_INFO, NOQID,
+ "rq: curnum=%d, MaxQueueChildren=%d, CurRunners=%d, WorkGrp[curnum].wg_maxact=%d",
+ curnum, MaxQueueChildren, CurRunners,
+ WorkGrp[curnum].wg_maxact);
+#endif /* _FFR_QUEUE_SCHED_DBG */
+ if (MaxQueueChildren > 0 &&
+ CurRunners + WorkGrp[curnum].wg_maxact > MaxQueueChildren)
+ break;
+
+ /*
+ ** Pick up where we left off (curnum), in case we
+ ** used up all the children last time without finishing.
+ ** This give a round-robin fairness to queue runs.
*/
- ret = run_single_queue(curnum, forkflag, verbose);
+ ret = run_work_group(curnum, forkflag, verbose, persistent,
+ runall);
/*
** Failure means a message was printed for ETRN
@@ -709,71 +1389,289 @@ runqueue(forkflag, verbose)
if (!ret)
break;
- if (++curnum >= NumQueues)
- curnum = 0;
+ /* Success means the runner count needs to be updated. */
+ CurRunners += WorkGrp[curnum].wg_maxact;
+ if (!persistent)
+ schedule_queue_runs(runall, curnum);
+ INCR_MOD(curnum, NumWorkGroups);
+ }
+
+ /* schedule left over queue runs */
+ if (i < NumWorkGroups && !NoMoreRunners && !persistent)
+ {
+ int h;
+
+ for (h = curnum; i < NumWorkGroups; i++)
+ {
+ schedule_queue_runs(runall, h);
+ INCR_MOD(h, NumWorkGroups);
+ }
}
- if (QueueIntvl != 0)
- (void) setevent(QueueIntvl, runqueueevent, 0);
+
+
+#if SM_HEAP_CHECK
+ if (sm_debug_active(&DebugLeakQ, 1))
+ sm_heap_setgroup(oldgroup);
+#endif /* SM_HEAP_CHECK */
return ret;
}
- /*
-** RUN_SINGLE_QUEUE -- run the jobs in a single queue.
+/*
+** RUNNER_WORK -- have a queue runner do its work
+**
+** Have a queue runner do its work a list of entries.
+** When work isn't directly being done then this process can take a signal
+** and terminate immediately (in a clean fashion of course).
+** When work is directly being done, it's not to be interrupted
+** immediately: the work should be allowed to finish at a clean point
+** before termination (in a clean fashion of course).
+**
+** Parameters:
+** e -- envelope.
+** sequenceno -- 'th process to run WorkQ.
+** didfork -- did the calling process fork()?
+** skip -- process only each skip'th item.
+** njobs -- number of jobs in WorkQ.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** runs things in the mail queue.
+*/
+
+/* Get new load average every 30 seconds. */
+#define GET_NEW_LA_TIME 30
+
+static void
+runner_work(e, sequenceno, didfork, skip, njobs)
+ register ENVELOPE *e;
+ int sequenceno;
+ bool didfork;
+ int skip;
+ int njobs;
+{
+ int n;
+ WORK *w;
+ time_t current_la_time, now;
+
+ current_la_time = curtime();
+
+ /*
+ ** Here we temporarily block the second calling of the handlers.
+ ** This allows us to handle the signal without terminating in the
+ ** middle of direct work. If a signal does come, the test for
+ ** NoMoreRunners will find it.
+ */
+
+ BlockOldsh = true;
+
+ /* process them once at a time */
+ while (WorkQ != NULL)
+ {
+#if SM_HEAP_CHECK
+ SM_NONVOLATILE int oldgroup = 0;
+
+ if (sm_debug_active(&DebugLeakQ, 1))
+ {
+ oldgroup = sm_heap_group();
+ sm_heap_newgroup();
+ sm_dprintf("run_queue_group() heap group #%d\n",
+ sm_heap_group());
+ }
+#endif /* SM_HEAP_CHECK */
+
+ /* do no more work */
+ if (NoMoreRunners)
+ {
+ /* Check that a valid signal handler is callable */
+ if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
+ Oldsh != runners_sighup &&
+ Oldsh != runners_sigterm)
+ (*Oldsh)(Oldsig);
+ break;
+ }
+
+ w = WorkQ; /* assign current work item */
+
+ /*
+ ** Set the head of the WorkQ to the next work item.
+ ** It is set 'skip' ahead (the number of parallel queue
+ ** runners working on WorkQ together) since each runner
+ ** works on every 'skip'th (N-th) item.
+ */
+
+ for (n = 0; n < skip && WorkQ != NULL; n++)
+ WorkQ = WorkQ->w_next;
+ e->e_to = NULL;
+
+ /*
+ ** Ignore jobs that are too expensive for the moment.
+ **
+ ** Get new load average every GET_NEW_LA_TIME seconds.
+ */
+
+ now = curtime();
+ if (current_la_time < now - GET_NEW_LA_TIME)
+ {
+ sm_getla();
+ current_la_time = now;
+ }
+ if (shouldqueue(WkRecipFact, current_la_time))
+ {
+ char *msg = "Aborting queue run: load average too high";
+
+ if (Verbose)
+ message("%s", msg);
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
+ break;
+ }
+ if (shouldqueue(w->w_pri, w->w_ctime))
+ {
+ if (Verbose)
+ message(EmptyString);
+ if (QueueSortOrder == QSO_BYPRIORITY)
+ {
+ if (Verbose)
+ message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
+ qid_printqueue(w->w_qgrp,
+ w->w_qdir),
+ w->w_name + 2, sequenceno,
+ njobs);
+ if (LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID,
+ "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
+ qid_printqueue(w->w_qgrp,
+ w->w_qdir),
+ w->w_name + 2, w->w_pri,
+ CurrentLA, sequenceno,
+ njobs);
+ break;
+ }
+ else if (Verbose)
+ message("Skipping %s/%s (sequence %d of %d)",
+ qid_printqueue(w->w_qgrp, w->w_qdir),
+ w->w_name + 2, sequenceno, njobs);
+ }
+ else
+ {
+ if (Verbose)
+ {
+ message(EmptyString);
+ message("Running %s/%s (sequence %d of %d)",
+ qid_printqueue(w->w_qgrp, w->w_qdir),
+ w->w_name + 2, sequenceno, njobs);
+ }
+ if (didfork && MaxQueueChildren > 0)
+ {
+ sm_blocksignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, reapchild);
+ }
+ if (tTd(63, 100))
+ sm_syslog(LOG_DEBUG, NOQID,
+ "runqueue %s dowork(%s)",
+ qid_printqueue(w->w_qgrp, w->w_qdir),
+ w->w_name + 2);
+
+ (void) dowork(w->w_qgrp, w->w_qdir, w->w_name + 2,
+ false, false, e);
+ errno = 0;
+ }
+ sm_free(w->w_name); /* XXX */
+ if (w->w_host != NULL)
+ sm_free(w->w_host); /* XXX */
+ sm_free((char *) w); /* XXX */
+ sequenceno += skip; /* next sequence number */
+#if SM_HEAP_CHECK
+ if (sm_debug_active(&DebugLeakQ, 1))
+ sm_heap_setgroup(oldgroup);
+#endif /* SM_HEAP_CHECK */
+ }
+
+ BlockOldsh = false;
+
+ /* check the signals didn't happen during the revert */
+ if (NoMoreRunners)
+ {
+ /* Check that a valid signal handler is callable */
+ if (Oldsh != SIG_DFL && Oldsh != SIG_IGN &&
+ Oldsh != runners_sighup && Oldsh != runners_sigterm)
+ (*Oldsh)(Oldsig);
+ }
+
+ Oldsh = SIG_DFL; /* after the NoMoreRunners check */
+}
+/*
+** RUN_WORK_GROUP -- run the jobs in a queue group from a work group.
**
** Gets the stuff out of the queue in some presumably logical
** order and processes them.
**
** Parameters:
-** queuedir -- queue to process
-** forkflag -- TRUE if the queue scanning should be done in
+** wgrp -- work group to process.
+** forkflag -- true if the queue scanning should be done in
** a child process. We double-fork so it is not our
** child and we don't have to clean up after it.
-** verbose -- if TRUE, print out status information.
+** verbose -- if true, print out status information.
+** persistent -- persistent queue runner?
+** runall -- true: run all of the queue groups in this work group
**
** Returns:
-** TRUE if the queue run successfully began.
+** true if the queue run successfully began.
**
** Side Effects:
** runs things in the mail queue.
*/
-static bool
-run_single_queue(queuedir, forkflag, verbose)
- int queuedir;
+/* Minimum sleep time for persistent queue runners */
+#define MIN_SLEEP_TIME 5
+
+bool
+run_work_group(wgrp, forkflag, verbose, persistent, runall)
+ int wgrp;
bool forkflag;
bool verbose;
+ bool persistent;
+ bool runall;
{
register ENVELOPE *e;
- int njobs;
- int sequenceno = 0;
- time_t current_la_time, now;
+ int njobs, qdir;
+ int sequenceno = 1;
+ int qgrp, endgrp, h, i;
+ time_t current_la_time;
+ bool full, more;
+ SM_RPOOL_T *rpool;
+ extern void rmexpstab __P((void));
extern ENVELOPE BlankEnvelope;
+ extern SIGFUNC_DECL reapchild __P((int));
+
+ if (wgrp < 0)
+ return false;
/*
** If no work will ever be selected, don't even bother reading
** the queue.
*/
- CurrentLA = sm_getla(NULL); /* get load average */
+ sm_getla(); /* get load average */
current_la_time = curtime();
- if (shouldqueue(WkRecipFact, current_la_time))
+ if (!persistent && shouldqueue(WkRecipFact, current_la_time))
{
char *msg = "Skipping queue run -- load average too high";
if (verbose)
message("458 %s\n", msg);
if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s",
- msg);
- return FALSE;
+ sm_syslog(LOG_INFO, NOQID, "runqueue: %s", msg);
+ return false;
}
/*
** See if we already have too many children.
*/
- if (forkflag && QueueIntvl != 0 &&
+ if (forkflag && WorkGrp[wgrp].wg_lowqintvl > 0 && !persistent &&
MaxChildren > 0 && CurChildren >= MaxChildren)
{
char *msg = "Skipping queue run -- too many children";
@@ -781,10 +1679,9 @@ run_single_queue(queuedir, forkflag, verbose)
if (verbose)
message("458 %s (%d)\n", msg, CurChildren);
if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s (%d)",
+ sm_syslog(LOG_INFO, NOQID, "runqueue: %s (%d)",
msg, CurChildren);
- return FALSE;
+ return false;
}
/*
@@ -795,81 +1692,84 @@ run_single_queue(queuedir, forkflag, verbose)
{
pid_t pid;
- (void) blocksignal(SIGCHLD);
- (void) setsignal(SIGCHLD, reapchild);
+ (void) sm_blocksignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, reapchild);
pid = dofork();
if (pid == -1)
{
const char *msg = "Skipping queue run -- fork() failed";
- const char *err = errstring(errno);
+ const char *err = sm_errstring(errno);
if (verbose)
message("458 %s: %s\n", msg, err);
if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s: %s",
+ sm_syslog(LOG_INFO, NOQID, "runqueue: %s: %s",
msg, err);
- (void) releasesignal(SIGCHLD);
- return FALSE;
+ (void) sm_releasesignal(SIGCHLD);
+ return false;
}
if (pid != 0)
{
/* parent -- pick up intermediate zombie */
- (void) blocksignal(SIGALRM);
- proc_list_add(pid, "Queue runner", PROC_QUEUE);
- (void) releasesignal(SIGALRM);
- (void) releasesignal(SIGCHLD);
- return TRUE;
+ (void) sm_blocksignal(SIGALRM);
+
+ /* wgrp only used when queue runners are persistent */
+ proc_list_add(pid, "Queue runner", PROC_QUEUE,
+ WorkGrp[wgrp].wg_maxact,
+ persistent ? wgrp : -1);
+ (void) sm_releasesignal(SIGALRM);
+ (void) sm_releasesignal(SIGCHLD);
+ return true;
}
+
/* child -- clean up signals */
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
+ CurrentPid = getpid();
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ sm_exc_newthread(fatal_error);
clrcontrol();
proc_list_clear();
/* Add parent process as first child item */
- proc_list_add(getpid(), "Queue runner child process",
- PROC_QUEUE_CHILD);
- (void) releasesignal(SIGCHLD);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_DFL);
- (void) setsignal(SIGTERM, intsig);
+ proc_list_add(CurrentPid, "Queue runner child process",
+ PROC_QUEUE_CHILD, 0, -1);
+ (void) sm_releasesignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ (void) sm_signal(SIGHUP, SIG_DFL);
+ (void) sm_signal(SIGTERM, intsig);
}
- sm_setproctitle(TRUE, CurEnv, "running queue: %s",
- qid_printqueue(queuedir));
-
- if (LogLevel > 69 || tTd(63, 99))
- sm_syslog(LOG_DEBUG, NOQID,
- "runqueue %s, pid=%d, forkflag=%d",
- qid_printqueue(queuedir), (int) getpid(), forkflag);
-
/*
** Release any resources used by the daemon code.
*/
-# if DAEMON
clrdaemon();
-# endif /* DAEMON */
/* force it to run expensive jobs */
- NoConnect = FALSE;
+ NoConnect = false;
/* drop privileges */
if (geteuid() == (uid_t) 0)
- (void) drop_privileges(FALSE);
+ (void) drop_privileges(false);
/*
** Create ourselves an envelope
*/
CurEnv = &QueueEnvelope;
- e = newenvelope(&QueueEnvelope, CurEnv);
+ rpool = sm_rpool_new_x(NULL);
+ e = newenvelope(&QueueEnvelope, CurEnv, rpool);
e->e_flags = BlankEnvelope.e_flags;
e->e_parent = NULL;
@@ -877,7 +1777,7 @@ run_single_queue(queuedir, forkflag, verbose)
if (forkflag)
{
disconnect(1, e);
- QuickAbort = FALSE;
+ QuickAbort = false;
}
/*
@@ -886,200 +1786,494 @@ run_single_queue(queuedir, forkflag, verbose)
*/
if (QueueLimitId != NULL || QueueLimitSender != NULL ||
+#if _FFR_QUARANTINE
+ QueueLimitQuarantine != NULL ||
+#endif /* _FFR_QUARANTINE */
QueueLimitRecipient != NULL)
{
- IgnoreHostStatus = TRUE;
+ IgnoreHostStatus = true;
MinQueueAge = 0;
}
/*
+ ** Here is where we choose the queue group from the work group.
+ ** The caller of the "domorework" label must setup a new envelope.
+ */
+
+ endgrp = WorkGrp[wgrp].wg_curqgrp; /* to not spin endlessly */
+
+ domorework:
+
+ /*
+ ** Run a queue group if:
+ ** runall is set or the bit for this group is set.
+ */
+
+ for (;;)
+ {
+ /*
+ ** Find the next queue group within the work group that
+ ** has been marked as needing a run.
+ */
+
+ qgrp = WorkGrp[wgrp].wg_qgs[WorkGrp[wgrp].wg_curqgrp]->qg_index;
+ WorkGrp[wgrp].wg_curqgrp++; /* advance */
+ WorkGrp[wgrp].wg_curqgrp %= WorkGrp[wgrp].wg_numqgrp; /* wrap */
+ if (runall || bitnset(qgrp, DoQueueRun))
+ break;
+ if (endgrp == WorkGrp[wgrp].wg_curqgrp)
+ {
+ e->e_id = NULL;
+ if (forkflag)
+ finis(true, true, ExitStat);
+ return true; /* we're done */
+ }
+ }
+
+ qdir = Queue[qgrp]->qg_curnum; /* round-robin init of queue position */
+#if _FFR_QUEUE_SCHED_DBG
+ if (tTd(69, 12))
+ sm_syslog(LOG_INFO, NOQID,
+ "rwg: wgrp=%d, qgrp=%d, qdir=%d, name=%s, curqgrp=%d, numgrps=%d",
+ wgrp, qgrp, qdir, qid_printqueue(qgrp, qdir),
+ WorkGrp[wgrp].wg_curqgrp, WorkGrp[wgrp].wg_numqgrp);
+#endif /* _FFR_QUEUE_SCHED_DBG */
+
+#if HASNICE
+ /* tweak niceness of queue runs */
+ if (Queue[qgrp]->qg_nice > 0)
+ (void) nice(Queue[qgrp]->qg_nice);
+#endif /* HASNICE */
+
+ /* XXX running queue group... */
+ sm_setproctitle(true, CurEnv, "running queue: %s",
+ qid_printqueue(qgrp, qdir));
+
+ if (LogLevel > 69 || tTd(63, 99))
+ sm_syslog(LOG_DEBUG, NOQID,
+ "runqueue %s, pid=%d, forkflag=%d",
+ qid_printqueue(qgrp, qdir), (int) CurrentPid,
+ forkflag);
+
+ /*
** Start making passes through the queue.
** First, read and sort the entire queue.
** Then, process the work in that order.
** But if you take too long, start over.
*/
+ for (i = 0; i < Queue[qgrp]->qg_numqueues; i++)
+ {
+ h = gatherq(qgrp, qdir, false, &full, &more);
+#if SM_CONF_SHM
+ if (ShmId != SM_SHM_NO_ID)
+ QSHM_ENTRIES(Queue[qgrp]->qg_qpaths[qdir].qp_idx) = h;
+#endif /* SM_CONF_SHM */
+ /* If there are no more items in this queue advance */
+ if (!more)
+ {
+ /* A round-robin advance */
+ qdir++;
+ qdir %= Queue[qgrp]->qg_numqueues;
+ }
+
+ /* Has the WorkList reached the limit? */
+ if (full)
+ break; /* don't try to gather more */
+ }
+
/* order the existing work requests */
- njobs = orderq(queuedir, FALSE);
+ njobs = sortq(Queue[qgrp]->qg_maxlist);
+ Queue[qgrp]->qg_curnum = qdir; /* update */
- /* process them once at a time */
- while (WorkQ != NULL)
+ if (!Verbose && bitnset(QD_FORK, Queue[qgrp]->qg_flags))
{
- WORK *w = WorkQ;
-
- WorkQ = WorkQ->w_next;
- e->e_to = NULL;
+ int loop, maxrunners;
+ pid_t pid;
/*
- ** Ignore jobs that are too expensive for the moment.
- **
- ** Get new load average every 30 seconds.
+ ** For this WorkQ we want to fork off N children (maxrunners)
+ ** at this point. Each child has a copy of WorkQ. Each child
+ ** will process every N-th item. The parent will wait for all
+ ** of the children to finish before moving on to the next
+ ** queue group within the work group. This saves us forking
+ ** a new runner-child for each work item.
+ ** It's valid for qg_maxqrun == 0 since this may be an
+ ** explicit "don't run this queue" setting.
*/
- now = curtime();
- if (current_la_time < now - 30)
+ maxrunners = Queue[qgrp]->qg_maxqrun;
+
+ /* No need to have more runners then there are jobs */
+ if (maxrunners > njobs)
+ maxrunners = njobs;
+ for (loop = 0; loop < maxrunners; loop++)
{
- CurrentLA = sm_getla(e);
- current_la_time = now;
+ /*
+ ** Since the delivery may happen in a child and the
+ ** parent does not wait, the parent may close the
+ ** maps thereby removing any shared memory used by
+ ** the map. Therefore, close the maps now so the
+ ** child will dynamically open them if necessary.
+ */
+
+ closemaps(false);
+
+ pid = fork();
+ if (pid < 0)
+ {
+ syserr("run_work_group: cannot fork");
+ return 0;
+ }
+ else if (pid > 0)
+ {
+ /* parent -- clean out connection cache */
+ mci_flush(false, NULL);
+ WorkQ = WorkQ->w_next; /* for the skip */
+ sequenceno++;
+ proc_list_add(pid, "Queue child runner process",
+ PROC_QUEUE_CHILD, 0, -1);
+
+ /* No additional work, no additional runners */
+ if (WorkQ == NULL)
+ break;
+ }
+ else
+ {
+ /* child -- Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ CurrentPid = getpid();
+
+ /*
+ ** Initialize exception stack and default
+ ** exception handler for child process.
+ ** When fork()'d the child now has a private
+ ** copy of WorkQ at its current position.
+ */
+
+ sm_exc_newthread(fatal_error);
+
+ /*
+ ** SMTP processes (whether -bd or -bs) set
+ ** SIGCHLD to reapchild to collect
+ ** children status. However, at delivery
+ ** time, that status must be collected
+ ** by sm_wait() to be dealt with properly
+ ** (check success of delivery based
+ ** on status code, etc). Therefore, if we
+ ** are an SMTP process, reset SIGCHLD
+ ** back to the default so reapchild
+ ** doesn't collect status before
+ ** sm_wait().
+ */
+
+ if (OpMode == MD_SMTP ||
+ OpMode == MD_DAEMON ||
+ MaxQueueChildren > 0)
+ {
+ proc_list_clear();
+ sm_releasesignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ }
+
+ /* child -- error messages to the transcript */
+ QuickAbort = OnlyOneError = false;
+ runner_work(e, sequenceno, true,
+ maxrunners, njobs);
+
+ /* This child is done */
+ finis(true, true, ExitStat);
+ /* NOTREACHED */
+ }
}
- if (shouldqueue(WkRecipFact, current_la_time))
+
+ sm_releasesignal(SIGCHLD);
+
+ /*
+ ** Wait until all of the runners have completed before
+ ** seeing if there is another queue group in the
+ ** work group to process.
+ ** XXX Future enhancement: don't wait() for all children
+ ** here, just go ahead and make sure that overall the number
+ ** of children is not exceeded.
+ */
+
+ while (CurChildren > 0)
{
- char *msg = "Aborting queue run: load average too high";
+ int status;
+ pid_t ret;
- if (Verbose)
- message("%s", msg);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s",
- msg);
- break;
+ while ((ret = sm_wait(&status)) <= 0)
+ continue;
+ proc_list_drop(ret, status, NULL);
}
- sequenceno++;
- if (shouldqueue(w->w_pri, w->w_ctime))
+ }
+ else
+ {
+ /*
+ ** When current process will not fork children to do the work,
+ ** it will do the work itself. The 'skip' will be 1 since
+ ** there are no child runners to divide the work across.
+ */
+
+ runner_work(e, sequenceno, false, 1, njobs);
+ }
+
+ /* free memory allocated by newenvelope() above */
+ sm_rpool_free(rpool);
+ QueueEnvelope.e_rpool = NULL;
+
+ /* Are there still more queues in the work group to process? */
+ if (endgrp != WorkGrp[wgrp].wg_curqgrp)
+ {
+ rpool = sm_rpool_new_x(NULL);
+ e = newenvelope(&QueueEnvelope, CurEnv, rpool);
+ e->e_flags = BlankEnvelope.e_flags;
+ goto domorework;
+ }
+
+ /* No more queues in work group to process. Now check persistent. */
+ if (persistent)
+ {
+ time_t now;
+
+ sequenceno = 1;
+ sm_setproctitle(true, CurEnv, "running queue: %s",
+ qid_printqueue(qgrp, qdir));
+
+ /*
+ ** close bogus maps, i.e., maps which caused a tempfail,
+ ** so we get fresh map connections on the next lookup.
+ ** closemaps() is also called when children are started.
+ */
+
+ closemaps(true);
+
+ /* Close any cached connections. */
+ mci_flush(true, NULL);
+
+ /* Clean out expired related entries. */
+ rmexpstab();
+
+#if NAMED_BIND
+ /* Update MX records for FallBackMX. */
+ if (FallBackMX != NULL)
+ (void) getfallbackmxrr(FallBackMX);
+#endif /* NAMED_BIND */
+
+#if USERDB
+ /* close UserDatabase */
+ _udbx_close();
+#endif /* USERDB */
+
+#if SM_HEAP_CHECK
+ if (sm_debug_active(&SmHeapCheck, 2)
+ && access("memdump", F_OK) == 0
+ )
{
- if (Verbose)
- message("");
- if (QueueSortOrder == QSO_BYPRIORITY)
+ SM_FILE_T *out;
+
+ remove("memdump");
+ out = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
+ "memdump.out", SM_IO_APPEND, NULL);
+ if (out != NULL)
{
- if (Verbose)
- message("Skipping %s/%s (sequence %d of %d) and flushing rest of queue",
- qid_printqueue(queuedir),
- w->w_name + 2,
- sequenceno,
- njobs);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: Flushing queue from %s/%s (pri %ld, LA %d, %d of %d)",
- qid_printqueue(queuedir),
- w->w_name + 2,
- w->w_pri,
- CurrentLA,
- sequenceno,
- njobs);
- break;
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n");
+ sm_heap_report(out,
+ sm_debug_level(&SmHeapCheck) - 1);
+ (void) sm_io_close(out, SM_TIME_DEFAULT);
}
- else if (Verbose)
- message("Skipping %s/%s (sequence %d of %d)",
- qid_printqueue(queuedir),
- w->w_name + 2,
- sequenceno, njobs);
}
+#endif /* SM_HEAP_CHECK */
+
+ /* let me rest for a second to catch my breath */
+ if (njobs == 0 && WorkGrp[wgrp].wg_lowqintvl < MIN_SLEEP_TIME)
+ sleep(MIN_SLEEP_TIME);
+ else if (WorkGrp[wgrp].wg_lowqintvl <= 0)
+ sleep(QueueIntvl > 0 ? QueueIntvl : MIN_SLEEP_TIME);
else
- {
- pid_t pid;
+ sleep(WorkGrp[wgrp].wg_lowqintvl);
- if (Verbose)
- {
- message("");
- message("Running %s/%s (sequence %d of %d)",
- qid_printqueue(queuedir),
- w->w_name + 2,
- sequenceno, njobs);
- }
- if (tTd(63, 100))
- sm_syslog(LOG_DEBUG, NOQID,
- "runqueue %s dowork(%s)",
- qid_printqueue(queuedir),
- w->w_name + 2);
+ /*
+ ** Get the LA outside the WorkQ loop if necessary.
+ ** In a persistent queue runner the code is repeated over
+ ** and over but gatherq() may ignore entries due to
+ ** shouldqueue() (do we really have to do this twice?).
+ ** Hence the queue runners would just idle around when once
+ ** CurrentLA caused all entries in a queue to be ignored.
+ */
- pid = dowork(queuedir, w->w_name + 2,
- ForkQueueRuns, FALSE, e);
- errno = 0;
- if (pid != 0)
- (void) waitfor(pid);
+ now = curtime();
+ if (njobs == 0 && current_la_time < now - GET_NEW_LA_TIME)
+ {
+ sm_getla();
+ current_la_time = now;
}
- sm_free(w->w_name);
- if (w->w_host)
- sm_free(w->w_host);
- sm_free((char *) w);
+ rpool = sm_rpool_new_x(NULL);
+ e = newenvelope(&QueueEnvelope, CurEnv, rpool);
+ e->e_flags = BlankEnvelope.e_flags;
+ goto domorework;
}
/* exit without the usual cleanup */
e->e_id = NULL;
if (forkflag)
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
/* NOTREACHED */
- return TRUE;
+ return true;
}
/*
-** RUNQUEUEEVENT -- stub for use in setevent
+** DOQUEUERUN -- do a queue run?
+*/
+
+bool
+doqueuerun()
+{
+ return bitnset(NumQueue, DoQueueRun);
+}
+
+/*
+** RUNQUEUEEVENT -- stub for use in sm_setevent
+**
+** Sets the bit to indicate that on the next run this queue should be
+** processed. The work group that the queue group is a member of has its
+** count of queue's to process updated.
**
** Parameters:
-** none.
+** qgrp -- the index of the queue group.
**
** Returns:
** none.
**
+** Side Effects:
+** The work group that the queue group is a member of has its
+** count of queues to process updated.
+** The invocation of this function via an alarm may interrupt
+** a set of actions. Thus errno may be set in that context.
+** We need to restore errno at the end of this function to ensure
+** that any work done here that sets errno doesn't return a
+** misleading/false errno value. Errno may be EINTR upon entry to
+** this function because of non-restartable/continuable system
+** API was active. Iff this is true we will override errno as
+** a timeout (as a more accurate error message).
+**
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
** DOING.
*/
-static void
-runqueueevent()
+void
+runqueueevent(qgrp)
+ int qgrp;
{
- DoQueueRun = TRUE;
+ int i;
+ int save_errno = errno;
+
+ /*
+ ** Set the general bit that we want a queue run,
+ ** tested in doqueuerun()
+ */
+
+ setbitn(NumQueue, DoQueueRun);
+
+ /* if it is a specific group: set that bit */
+ if (qgrp != NOQGRP)
+ {
+ setbitn(qgrp, DoQueueRun);
+ goto ret;
+ }
+
+ /* for all others: set the bit if it doesn't have a queue interval */
+ for (i = 0; i < NumQueue; i++)
+ {
+ if (Queue[i]->qg_queueintvl <= 0)
+ setbitn(i, DoQueueRun);
+ }
+
+ ret:
+ errno = save_errno;
+ if (errno == EINTR)
+ errno = ETIMEDOUT;
}
- /*
-** ORDERQ -- order the work queue.
+/*
+** GATHERQ -- gather messages from the message queue(s) the work queue.
**
** Parameters:
-** queuedir -- the index of the queue directory.
+** qgrp -- the index of the queue group.
+** qdir -- the index of the queue directory.
** doall -- if set, include everything in the queue (even
** the jobs that cannot be run because the load
-** average is too high). Otherwise, exclude those
-** jobs.
+** average is too high, or MaxQueueRun is reached).
+** Otherwise, exclude those jobs.
+** full -- (optional) to be set 'true' if WorkList is full
+** more -- (optional) to be set 'true' if there are still more
+** messages in this queue not added to WorkList
**
** Returns:
** The number of request in the queue (not necessarily
-** the number of requests in WorkQ however).
+** the number of requests in WorkList however).
**
** Side Effects:
-** Sets WorkQ to the queue of available work, in order.
+** prepares available work into WorkList
*/
-# define NEED_P 001
-# define NEED_T 002
-# define NEED_R 004
-# define NEED_S 010
-# define NEED_H 020
+#define NEED_P 0001 /* 'P': priority */
+#define NEED_T 0002 /* 'T': time */
+#define NEED_R 0004 /* 'R': recipient */
+#define NEED_S 0010 /* 'S': sender */
+#define NEED_H 0020 /* host */
+#if _FFR_QUARANTINE
+# define HAS_QUARANTINE 0040 /* has an unexpected 'q' line */
+# define NEED_QUARANTINE 0100 /* 'q': reason */
+#endif /* _FFR_QUARANTINE */
-static WORK *WorkList = NULL;
-static int WorkListSize = 0;
+static WORK *WorkList = NULL; /* list of unsort work */
+static int WorkListSize = 0; /* current max size of WorkList */
+static int WorkListCount = 0; /* # of work items in WorkList */
static int
-orderq(queuedir, doall)
- int queuedir;
+gatherq(qgrp, qdir, doall, full, more)
+ int qgrp;
+ int qdir;
bool doall;
+ bool *full;
+ bool *more;
{
register struct dirent *d;
register WORK *w;
register char *p;
DIR *f;
- register int i;
- int wn = -1;
- int wc;
+ int i, num_ent;
+ int wn;
QUEUE_CHAR *check;
char qd[MAXPATHLEN];
char qf[MAXPATHLEN];
- if (queuedir == NOQDIR)
- (void) strlcpy(qd, ".", sizeof qd);
+ wn = WorkListCount - 1;
+ num_ent = 0;
+ if (qdir == NOQDIR)
+ (void) sm_strlcpy(qd, ".", sizeof qd);
else
- (void) snprintf(qd, sizeof qd, "%s%s",
- QPaths[queuedir].qp_name,
- (bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
+ (void) sm_strlcpyn(qd, sizeof qd, 2,
+ Queue[qgrp]->qg_qpaths[qdir].qp_name,
+ (bitset(QP_SUBQF,
+ Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
+ ? "/qf" : ""));
if (tTd(41, 1))
{
- dprintf("orderq:\n");
+ sm_dprintf("gatherq:\n");
check = QueueLimitId;
while (check != NULL)
{
- dprintf("\tQueueLimitId = %s\n",
+ sm_dprintf("\tQueueLimitId = %s%s\n",
+ check->queue_negate ? "!" : "",
check->queue_match);
check = check->queue_next;
}
@@ -1087,7 +2281,8 @@ orderq(queuedir, doall)
check = QueueLimitSender;
while (check != NULL)
{
- dprintf("\tQueueLimitSender = %s\n",
+ sm_dprintf("\tQueueLimitSender = %s%s\n",
+ check->queue_negate ? "!" : "",
check->queue_match);
check = check->queue_next;
}
@@ -1095,30 +2290,37 @@ orderq(queuedir, doall)
check = QueueLimitRecipient;
while (check != NULL)
{
- dprintf("\tQueueLimitRecipient = %s\n",
+ sm_dprintf("\tQueueLimitRecipient = %s%s\n",
+ check->queue_negate ? "!" : "",
check->queue_match);
check = check->queue_next;
}
- }
- /* clear out old WorkQ */
- for (w = WorkQ; w != NULL; )
- {
- register WORK *nw = w->w_next;
-
- WorkQ = nw;
- sm_free(w->w_name);
- if (w->w_host != NULL)
- sm_free(w->w_host);
- sm_free((char *) w);
- w = nw;
+#if _FFR_QUARANTINE
+ if (QueueMode == QM_QUARANTINE)
+ {
+ check = QueueLimitQuarantine;
+ while (check != NULL)
+ {
+ sm_dprintf("\tQueueLimitQuarantine = %s%s\n",
+ check->queue_negate ? "!" : "",
+ check->queue_match);
+ check = check->queue_next;
+ }
+ }
+#endif /* _FFR_QUARANTINE */
}
/* open the queue directory */
f = opendir(qd);
if (f == NULL)
{
- syserr("orderq: cannot open \"%s\"", qid_printqueue(queuedir));
+ syserr("gatherq: cannot open \"%s\"",
+ qid_printqueue(qgrp, qdir));
+ if (full != NULL)
+ *full = WorkListCount >= MaxQueueRun && MaxQueueRun > 0;
+ if (more != NULL)
+ *more = false;
return 0;
}
@@ -1128,26 +2330,43 @@ orderq(queuedir, doall)
while ((d = readdir(f)) != NULL)
{
- FILE *cf;
+ SM_FILE_T *cf;
int qfver = 0;
char lbuf[MAXNAME + 1];
struct stat sbuf;
if (tTd(41, 50))
- dprintf("orderq: checking %s\n", d->d_name);
+ sm_dprintf("gatherq: checking %s..", d->d_name);
/* is this an interesting entry? */
- if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
+#if _FFR_QUARANTINE
+ if (!(((QueueMode == QM_NORMAL &&
+ d->d_name[0] == NORMQF_LETTER) ||
+ (QueueMode == QM_QUARANTINE &&
+ d->d_name[0] == QUARQF_LETTER) ||
+ (QueueMode == QM_LOST &&
+ d->d_name[0] == LOSEQF_LETTER)) &&
+ d->d_name[1] == 'f'))
+#else /* _FFR_QUARANTINE */
+ if (d->d_name[0] != NORMQF_LETTER || d->d_name[1] != 'f')
+#endif /* _FFR_QUARANTINE */
+ {
+ if (tTd(41, 50))
+ sm_dprintf(" skipping\n");
continue;
+ }
+ if (tTd(41, 50))
+ sm_dprintf("\n");
if (strlen(d->d_name) >= MAXQFNAME)
{
if (Verbose)
- printf("orderq: %s too long, %d max characters\n",
- d->d_name, MAXQFNAME);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "gatherq: %s too long, %d max characters\n",
+ d->d_name, MAXQFNAME);
if (LogLevel > 0)
sm_syslog(LOG_ALERT, NOQID,
- "orderq: %s too long, %d max characters",
+ "gatherq: %s too long, %d max characters",
d->d_name, MAXQFNAME);
continue;
}
@@ -1155,7 +2374,8 @@ orderq(queuedir, doall)
check = QueueLimitId;
while (check != NULL)
{
- if (strcontainedin(check->queue_match, d->d_name))
+ if (strcontainedin(true, check->queue_match,
+ d->d_name) != check->queue_negate)
break;
else
check = check->queue_next;
@@ -1169,76 +2389,109 @@ orderq(queuedir, doall)
if (wn == MaxQueueRun && LogLevel > 0)
sm_syslog(LOG_WARNING, NOQID,
"WorkList for %s maxed out at %d",
- qid_printqueue(queuedir),
+ qid_printqueue(qgrp, qdir),
MaxQueueRun);
- continue;
+ if (doall)
+ continue; /* just count entries */
+ break;
}
if (wn >= WorkListSize)
{
- grow_wlist(queuedir);
+ grow_wlist(qgrp, qdir);
if (wn >= WorkListSize)
continue;
}
+ SM_ASSERT(wn >= 0);
w = &WorkList[wn];
- (void) snprintf(qf, sizeof qf, "%s/%s", qd, d->d_name);
+ (void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", d->d_name);
if (stat(qf, &sbuf) < 0)
{
if (errno != ENOENT)
sm_syslog(LOG_INFO, NOQID,
- "orderq: can't stat %s/%s",
- qid_printqueue(queuedir), d->d_name);
+ "gatherq: can't stat %s/%s",
+ qid_printqueue(qgrp, qdir),
+ d->d_name);
wn--;
continue;
}
if (!bitset(S_IFREG, sbuf.st_mode))
{
/* Yikes! Skip it or we will hang on open! */
- syserr("orderq: %s/%s is not a regular file",
- qid_printqueue(queuedir), d->d_name);
+ if (!((d->d_name[0] == DATAFL_LETTER ||
+ d->d_name[0] == NORMQF_LETTER ||
+#if _FFR_QUARANTINE
+ d->d_name[0] == QUARQF_LETTER ||
+ d->d_name[0] == LOSEQF_LETTER ||
+#endif /* _FFR_QUARANTINE */
+ d->d_name[0] == XSCRPT_LETTER) &&
+ d->d_name[1] == 'f' && d->d_name[2] == '\0'))
+ syserr("gatherq: %s/%s is not a regular file",
+ qid_printqueue(qgrp, qdir), d->d_name);
wn--;
continue;
}
/* avoid work if possible */
- if (QueueSortOrder == QSO_BYFILENAME &&
+ if ((QueueSortOrder == QSO_BYFILENAME ||
+ QueueSortOrder == QSO_BYMODTIME ||
+ QueueSortOrder == QSO_RANDOM) &&
+#if _FFR_QUARANTINE
+ QueueLimitQuarantine == NULL &&
+#endif /* _FFR_QUARANTINE */
QueueLimitSender == NULL &&
QueueLimitRecipient == NULL)
{
+ w->w_qgrp = qgrp;
+ w->w_qdir = qdir;
w->w_name = newstr(d->d_name);
w->w_host = NULL;
- w->w_lock = w->w_tooyoung = FALSE;
+ w->w_lock = w->w_tooyoung = false;
w->w_pri = 0;
w->w_ctime = 0;
+ w->w_mtime = sbuf.st_mtime;
+ ++num_ent;
continue;
}
/* open control file */
- cf = fopen(qf, "r");
-
- if (cf == NULL)
+ cf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY,
+ NULL);
+ if (cf == NULL && OpMode != MD_PRINT)
{
/* this may be some random person sending hir msgs */
- /* syserr("orderq: cannot open %s", cbuf); */
if (tTd(41, 2))
- dprintf("orderq: cannot open %s: %s\n",
- d->d_name, errstring(errno));
+ sm_dprintf("gatherq: cannot open %s: %s\n",
+ d->d_name, sm_errstring(errno));
errno = 0;
wn--;
continue;
}
+ w->w_qgrp = qgrp;
+ w->w_qdir = qdir;
w->w_name = newstr(d->d_name);
w->w_host = NULL;
- w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
- w->w_tooyoung = FALSE;
+ if (cf != NULL)
+ {
+ w->w_lock = !lockfile(sm_io_getinfo(cf, SM_IO_WHAT_FD,
+ NULL),
+ w->w_name, NULL,
+ LOCK_SH|LOCK_NB);
+ }
+ w->w_tooyoung = false;
/* make sure jobs in creation don't clog queue */
w->w_pri = 0x7fffffff;
w->w_ctime = 0;
+ w->w_mtime = sbuf.st_mtime;
/* extract useful information */
- i = NEED_P | NEED_T;
- if (QueueSortOrder == QSO_BYHOST)
+ i = NEED_P|NEED_T;
+ if (QueueSortOrder == QSO_BYHOST
+#if _FFR_RHS
+ || QueueSortOrder == QSO_BYSHUFFLE
+#endif /* _FFR_RHS */
+ )
{
/* need w_host set for host sort order */
i |= NEED_H;
@@ -1247,7 +2500,13 @@ orderq(queuedir, doall)
i |= NEED_S;
if (QueueLimitRecipient != NULL)
i |= NEED_R;
- while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
+#if _FFR_QUARANTINE
+ if (QueueLimitQuarantine != NULL)
+ i |= NEED_QUARANTINE;
+#endif /* _FFR_QUARANTINE */
+ while (cf != NULL && i != 0 &&
+ sm_io_fgets(cf, SM_TIME_DEFAULT, lbuf,
+ sizeof lbuf) != NULL)
{
int c;
time_t age;
@@ -1258,7 +2517,8 @@ orderq(queuedir, doall)
else
{
/* flush rest of overly long line */
- while ((c = getc(cf)) != EOF && c != '\n')
+ while ((c = sm_io_getc(cf, SM_TIME_DEFAULT))
+ != SM_IO_EOF && c != '\n')
continue;
}
@@ -1278,11 +2538,51 @@ orderq(queuedir, doall)
i &= ~NEED_T;
break;
+#if _FFR_QUARANTINE
+ case 'q':
+ if (QueueMode != QM_QUARANTINE &&
+ QueueMode != QM_LOST)
+ {
+ if (tTd(41, 49))
+ sm_dprintf("%s not marked as quarantined but has a 'q' line\n",
+ w->w_name);
+ i |= HAS_QUARANTINE;
+ }
+ else if (QueueMode == QM_QUARANTINE)
+ {
+ if (QueueLimitQuarantine == NULL)
+ {
+ i &= ~NEED_QUARANTINE;
+ break;
+ }
+ p = &lbuf[1];
+ check = QueueLimitQuarantine;
+ while (check != NULL)
+ {
+ if (strcontainedin(false,
+ check->queue_match,
+ p) !=
+ check->queue_negate)
+ break;
+ else
+ check = check->queue_next;
+ }
+ if (check != NULL)
+ i &= ~NEED_QUARANTINE;
+ }
+ break;
+#endif /* _FFR_QUARANTINE */
+
case 'R':
if (w->w_host == NULL &&
(p = strrchr(&lbuf[1], '@')) != NULL)
{
- w->w_host = strrev(&p[1]);
+#if _FFR_RHS
+ if (QueueSortOrder == QSO_BYSHUFFLE)
+ w->w_host = newstr(&p[1]);
+ else
+#endif /* _FFR_RHS */
+ w->w_host = strrev(&p[1]);
makelower(w->w_host);
i &= ~NEED_H;
}
@@ -1302,8 +2602,10 @@ orderq(queuedir, doall)
check = QueueLimitRecipient;
while (check != NULL)
{
- if (strcontainedin(check->queue_match,
- p))
+ if (strcontainedin(true,
+ check->queue_match,
+ p) !=
+ check->queue_negate)
break;
else
check = check->queue_next;
@@ -1316,8 +2618,10 @@ orderq(queuedir, doall)
check = QueueLimitSender;
while (check != NULL)
{
- if (strcontainedin(check->queue_match,
- &lbuf[1]))
+ if (strcontainedin(true,
+ check->queue_match,
+ &lbuf[1]) !=
+ check->queue_negate)
break;
else
check = check->queue_next;
@@ -1330,15 +2634,15 @@ orderq(queuedir, doall)
age = curtime() - (time_t) atol(&lbuf[1]);
if (age >= 0 && MinQueueAge > 0 &&
age < MinQueueAge)
- w->w_tooyoung = TRUE;
+ w->w_tooyoung = true;
break;
case 'N':
if (atol(&lbuf[1]) == 0)
- w->w_tooyoung = FALSE;
+ w->w_tooyoung = false;
break;
-# if _FFR_QUEUEDELAY
+#if _FFR_QUEUEDELAY
/*
case 'G':
queuealg = atoi(lbuf[1]);
@@ -1347,32 +2651,104 @@ orderq(queuedir, doall)
queuedelay = (time_t) atol(&lbuf[1]);
break;
*/
-# endif /* _FFR_QUEUEDELAY */
+#endif /* _FFR_QUEUEDELAY */
}
}
- (void) fclose(cf);
+ if (cf != NULL)
+ (void) sm_io_close(cf, SM_TIME_DEFAULT);
if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
+#if _FFR_QUARANTINE
+ bitset(HAS_QUARANTINE, i) ||
+ bitset(NEED_QUARANTINE, i) ||
+#endif /* _FFR_QUARANTINE */
bitset(NEED_R|NEED_S, i))
{
/* don't even bother sorting this job in */
if (tTd(41, 49))
- dprintf("skipping %s (%x)\n", w->w_name, i);
- sm_free(w->w_name);
- if (w->w_host)
- sm_free(w->w_host);
+ sm_dprintf("skipping %s (%x)\n", w->w_name, i);
+ sm_free(w->w_name); /* XXX */
+ if (w->w_host != NULL)
+ sm_free(w->w_host); /* XXX */
wn--;
}
+ else
+ ++num_ent;
}
(void) closedir(f);
wn++;
- WorkQ = NULL;
- if (WorkList == NULL)
+ i = wn - WorkListCount;
+ WorkListCount += SM_MIN(num_ent, WorkListSize);
+
+ if (more != NULL)
+ *more = WorkListCount < wn;
+
+ if (full != NULL)
+ *full = (wn >= MaxQueueRun && MaxQueueRun > 0) ||
+ (WorkList == NULL && wn > 0);
+
+ return i;
+}
+/*
+** SORTQ -- sort the work list
+**
+** First the old WorkQ is cleared away. Then the WorkList is sorted
+** for all items so that important (higher sorting value) items are not
+** trunctated off. Then the most important items are moved from
+** WorkList to WorkQ. The lower count of 'max' or MaxListCount items
+** are moved.
+**
+** Parameters:
+** max -- maximum number of items to be placed in WorkQ
+**
+** Returns:
+** the number of items in WorkQ
+**
+** Side Effects:
+** WorkQ gets released and filled with new work. WorkList
+** gets released. Work items get sorted in order.
+*/
+
+static int
+sortq(max)
+ int max;
+{
+ register int i; /* local counter */
+ register WORK *w; /* tmp item pointer */
+ int wc = WorkListCount; /* trim size for WorkQ */
+
+ if (WorkQ != NULL)
+ {
+ /* Clear out old WorkQ. */
+ for (w = WorkQ; w != NULL; )
+ {
+ register WORK *nw = w->w_next;
+
+ WorkQ = nw;
+ sm_free(w->w_name); /* XXX */
+ if (w->w_host != NULL)
+ sm_free(w->w_host); /* XXX */
+ sm_free((char *) w); /* XXX */
+ w = nw;
+ }
+ sm_free((char *) WorkQ);
+ WorkQ = NULL;
+ }
+
+ if (WorkList == NULL || wc <= 0)
return 0;
- wc = min(wn, WorkListSize);
- if (wc > MaxQueueRun && MaxQueueRun > 0)
- wc = MaxQueueRun;
+
+ /* Check if the per queue group item limit will be exceeded */
+ if (wc > max && max > 0)
+ wc = max;
+
+ /*
+ ** The sort now takes place using all of the items in WorkList.
+ ** The list gets trimmed to the most important items after the sort.
+ ** If the trim were to happen before the sort then one or more
+ ** important items might get truncated off -- not what we want.
+ */
if (QueueSortOrder == QSO_BYHOST)
{
@@ -1401,11 +2777,12 @@ orderq(queuedir, doall)
{
if (WorkList[i].w_host == NULL &&
w->w_host == NULL)
- WorkList[i].w_lock = TRUE;
+ WorkList[i].w_lock = true;
else if (WorkList[i].w_host != NULL &&
w->w_host != NULL &&
- sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
- WorkList[i].w_lock = TRUE;
+ sm_strcasecmp(WorkList[i].w_host,
+ w->w_host) == 0)
+ WorkList[i].w_lock = true;
else
break;
}
@@ -1429,11 +2806,42 @@ orderq(queuedir, doall)
else if (QueueSortOrder == QSO_BYFILENAME)
{
/*
- ** Sort based on qf filename.
+ ** Sort based on queue filename.
*/
qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf4);
}
+ else if (QueueSortOrder == QSO_RANDOM)
+ {
+ /*
+ ** Sort randomly.
+ ** workcmpf5() returns a random 1 or -1.
+ ** As long as nobody does a verification pass over the
+ ** sorted list, we should be golden.
+ */
+
+ qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf5);
+ }
+ else if (QueueSortOrder == QSO_BYMODTIME)
+ {
+ /*
+ ** Simple sort based on modification time of queue file.
+ ** This puts the oldest items first.
+ */
+
+ qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf6);
+ }
+#if _FFR_RHS
+ else if (QueueSortOrder == QSO_BYSHUFFLE)
+ {
+ /*
+ ** Simple sort based on shuffled host name.
+ */
+
+ init_shuffle_alphabet();
+ qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf7);
+ }
+#endif /* _FFR_RHS */
else
{
/*
@@ -1446,45 +2854,52 @@ orderq(queuedir, doall)
/*
** Convert the work list into canonical form.
** Should be turning it into a list of envelopes here perhaps.
+ ** Only take the most important items up to the per queue group
+ ** maximum.
*/
for (i = wc; --i >= 0; )
{
w = (WORK *) xalloc(sizeof *w);
+ w->w_qgrp = WorkList[i].w_qgrp;
+ w->w_qdir = WorkList[i].w_qdir;
w->w_name = WorkList[i].w_name;
w->w_host = WorkList[i].w_host;
w->w_lock = WorkList[i].w_lock;
w->w_tooyoung = WorkList[i].w_tooyoung;
w->w_pri = WorkList[i].w_pri;
w->w_ctime = WorkList[i].w_ctime;
+ w->w_mtime = WorkList[i].w_mtime;
w->w_next = WorkQ;
WorkQ = w;
}
if (WorkList != NULL)
- sm_free(WorkList);
+ sm_free(WorkList); /* XXX */
WorkList = NULL;
WorkListSize = 0;
+ WorkListCount = 0;
if (tTd(40, 1))
{
for (w = WorkQ; w != NULL; w = w->w_next)
{
if (w->w_host != NULL)
- dprintf("%22s: pri=%ld %s\n",
+ sm_dprintf("%22s: pri=%ld %s\n",
w->w_name, w->w_pri, w->w_host);
else
- dprintf("%32s: pri=%ld\n",
+ sm_dprintf("%32s: pri=%ld\n",
w->w_name, w->w_pri);
}
}
- return wn;
+ return wc; /* return number of WorkQ items */
}
- /*
+/*
** GROW_WLIST -- make the work list larger
**
** Parameters:
-** queuedir -- the index for the queue directory.
+** qgrp -- the index for the queue group.
+** qdir -- the index for the queue directory.
**
** Returns:
** none.
@@ -1496,11 +2911,12 @@ orderq(queuedir, doall)
*/
static void
-grow_wlist(queuedir)
- int queuedir;
+grow_wlist(qgrp, qdir)
+ int qgrp;
+ int qdir;
{
if (tTd(41, 1))
- dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
+ sm_dprintf("grow_wlist: WorkListSize=%d\n", WorkListSize);
if (WorkList == NULL)
{
WorkList = (WORK *) xalloc((sizeof *WorkList) *
@@ -1510,8 +2926,8 @@ grow_wlist(queuedir)
else
{
int newsize = WorkListSize + QUEUESEGSIZE;
- WORK *newlist = (WORK *) xrealloc((char *)WorkList,
- (unsigned)sizeof(WORK) * (newsize + 1));
+ WORK *newlist = (WORK *) sm_realloc((char *) WorkList,
+ (unsigned) sizeof(WORK) * (newsize + 1));
if (newlist != NULL)
{
@@ -1521,7 +2937,7 @@ grow_wlist(queuedir)
{
sm_syslog(LOG_INFO, NOQID,
"grew WorkList for %s to %d",
- qid_printqueue(queuedir),
+ qid_printqueue(qgrp, qdir),
WorkListSize);
}
}
@@ -1529,13 +2945,13 @@ grow_wlist(queuedir)
{
sm_syslog(LOG_ALERT, NOQID,
"FAILED to grow WorkList for %s to %d",
- qid_printqueue(queuedir), newsize);
+ qid_printqueue(qgrp, qdir), newsize);
}
}
if (tTd(41, 1))
- dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
+ sm_dprintf("grow_wlist: WorkListSize now %d\n", WorkListSize);
}
- /*
+/*
** WORKCMPF0 -- simple priority-only compare function.
**
** Parameters:
@@ -1547,8 +2963,6 @@ grow_wlist(queuedir)
** 0 if a == b
** +1 if a > b
**
-** Side Effects:
-** none.
*/
static int
@@ -1566,7 +2980,7 @@ workcmpf0(a, b)
else
return -1;
}
- /*
+/*
** WORKCMPF1 -- first compare function for ordering work based on host name.
**
** Sorts on host name, lock status, and priority in that order.
@@ -1580,8 +2994,6 @@ workcmpf0(a, b)
** 0 if a == b
** >0 if a > b
**
-** Side Effects:
-** none.
*/
static int
@@ -1607,7 +3019,7 @@ workcmpf1(a, b)
/* job priority */
return workcmpf0(a, b);
}
- /*
+/*
** WORKCMPF2 -- second compare function for ordering work based on host name.
**
** Sorts on lock status, host name, and priority in that order.
@@ -1621,8 +3033,6 @@ workcmpf1(a, b)
** 0 if a == b
** >0 if a > b
**
-** Side Effects:
-** none.
*/
static int
@@ -1648,7 +3058,7 @@ workcmpf2(a, b)
/* job priority */
return workcmpf0(a, b);
}
- /*
+/*
** WORKCMPF3 -- simple submission-time-only compare function.
**
** Parameters:
@@ -1660,8 +3070,6 @@ workcmpf2(a, b)
** 0 if a == b
** +1 if a > b
**
-** Side Effects:
-** none.
*/
static int
@@ -1676,7 +3084,7 @@ workcmpf3(a, b)
else
return 0;
}
- /*
+/*
** WORKCMPF4 -- compare based on file name
**
** Parameters:
@@ -1688,8 +3096,6 @@ workcmpf3(a, b)
** 0 if a == b
** +1 if a > b
**
-** Side Effects:
-** none.
*/
static int
@@ -1699,7 +3105,93 @@ workcmpf4(a, b)
{
return strcmp(a->w_name, b->w_name);
}
- /*
+/*
+** WORKCMPF5 -- compare based on assigned random number
+**
+** Parameters:
+** a -- the first argument (ignored).
+** b -- the second argument (ignored).
+**
+** Returns:
+** randomly 1/-1
+*/
+
+/* ARGSUSED0 */
+static int
+workcmpf5(a, b)
+ register WORK *a;
+ register WORK *b;
+{
+ return (get_rand_mod(2)) ? 1 : -1;
+}
+/*
+** WORKCMPF6 -- simple modification-time-only compare function.
+**
+** Parameters:
+** a -- the first argument.
+** b -- the second argument.
+**
+** Returns:
+** -1 if a < b
+** 0 if a == b
+** +1 if a > b
+**
+*/
+
+static int
+workcmpf6(a, b)
+ register WORK *a;
+ register WORK *b;
+{
+ if (a->w_mtime > b->w_mtime)
+ return 1;
+ else if (a->w_mtime < b->w_mtime)
+ return -1;
+ else
+ return 0;
+}
+#if _FFR_RHS
+/*
+** WORKCMPF7 -- compare function for ordering work based on shuffled host name.
+**
+** Sorts on lock status, host name, and priority in that order.
+**
+** Parameters:
+** a -- the first argument.
+** b -- the second argument.
+**
+** Returns:
+** <0 if a < b
+** 0 if a == b
+** >0 if a > b
+**
+*/
+
+static int
+workcmpf7(a, b)
+ register WORK *a;
+ register WORK *b;
+{
+ int i;
+
+ /* lock status */
+ if (a->w_lock != b->w_lock)
+ return a->w_lock - b->w_lock;
+
+ /* host name */
+ if (a->w_host != NULL && b->w_host == NULL)
+ return 1;
+ else if (a->w_host == NULL && b->w_host != NULL)
+ return -1;
+ if (a->w_host != NULL && b->w_host != NULL &&
+ (i = sm_strshufflecmp(a->w_host, b->w_host)) != 0)
+ return i;
+
+ /* job priority */
+ return workcmpf0(a, b);
+}
+#endif /* _FFR_RHS */
+/*
** STRREV -- reverse string
**
** Returns a pointer to a new string that is the reverse of
@@ -1727,11 +3219,71 @@ strrev(fwd)
rev[len] = '\0';
return rev;
}
- /*
+
+#if _FFR_RHS
+
+#define NASCII 128
+#define NCHAR 256
+
+static unsigned char ShuffledAlphabet[NCHAR];
+
+void
+init_shuffle_alphabet()
+{
+ static bool init = false;
+ int i;
+
+ if (init)
+ return;
+
+ /* fill the ShuffledAlphabet */
+ for (i = 0; i < NCHAR; i++)
+ ShuffledAlphabet[i] = i;
+
+ /* mix it */
+ for (i = 1; i < NCHAR; i++)
+ {
+ register int j = get_random() % NCHAR;
+ register int tmp;
+
+ tmp = ShuffledAlphabet[j];
+ ShuffledAlphabet[j] = ShuffledAlphabet[i];
+ ShuffledAlphabet[i] = tmp;
+ }
+
+ /* make it case insensitive */
+ for (i = 'A'; i <= 'Z'; i++)
+ ShuffledAlphabet[i] = ShuffledAlphabet[i + 'a' - 'A'];
+
+ /* fill the upper part */
+ for (i = 0; i < NCHAR; i++)
+ ShuffledAlphabet[i + NCHAR] = ShuffledAlphabet[i];
+ init = true;
+}
+
+static int
+sm_strshufflecmp(a, b)
+ char *a;
+ char *b;
+{
+ const unsigned char *us1 = (const unsigned char *) a;
+ const unsigned char *us2 = (const unsigned char *) b;
+
+ while (ShuffledAlphabet[*us1] == ShuffledAlphabet[*us2++])
+ {
+ if (*us1++ == '\0')
+ return 0;
+ }
+ return (ShuffledAlphabet[*us1] - ShuffledAlphabet[*--us2]);
+}
+#endif /* _FFR_RHS */
+
+/*
** DOWORK -- do a work request.
**
** Parameters:
-** queuedir -- the index of the queue directory for the job.
+** qgrp -- the index of the queue group for the job.
+** qdir -- the index of the queue directory for the job.
** id -- the ID of the job to run.
** forkflag -- if set, run this in background.
** requeueflag -- if set, reinstantiate the queue quickly.
@@ -1748,17 +3300,19 @@ strrev(fwd)
*/
pid_t
-dowork(queuedir, id, forkflag, requeueflag, e)
- int queuedir;
+dowork(qgrp, qdir, id, forkflag, requeueflag, e)
+ int qgrp;
+ int qdir;
char *id;
bool forkflag;
bool requeueflag;
register ENVELOPE *e;
{
register pid_t pid;
+ SM_RPOOL_T *rpool;
if (tTd(40, 1))
- dprintf("dowork(%s/%s)\n", qid_printqueue(queuedir), id);
+ sm_dprintf("dowork(%s/%s)\n", qid_printqueue(qgrp, qdir), id);
/*
** Fork for work.
@@ -1774,7 +3328,7 @@ dowork(queuedir, id, forkflag, requeueflag, e)
** child will dynamically open them if necessary.
*/
- closemaps();
+ closemaps(false);
pid = fork();
if (pid < 0)
@@ -1785,12 +3339,38 @@ dowork(queuedir, id, forkflag, requeueflag, e)
else if (pid > 0)
{
/* parent -- clean out connection cache */
- mci_flush(FALSE, NULL);
+ mci_flush(false, NULL);
}
else
{
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ /* Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ CurrentPid = getpid();
+ sm_exc_newthread(fatal_error);
+
+ /*
+ ** See note above about SMTP processes and SIGCHLD.
+ */
+
+ if (OpMode == MD_SMTP ||
+ OpMode == MD_DAEMON ||
+ MaxQueueChildren > 0)
+ {
+ proc_list_clear();
+ sm_releasesignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ }
+
/* child -- error messages to the transcript */
- QuickAbort = OnlyOneError = FALSE;
+ QuickAbort = OnlyOneError = false;
}
}
else
@@ -1808,94 +3388,306 @@ dowork(queuedir, id, forkflag, requeueflag, e)
** can recover on interrupt.
*/
- /* Reset global flags */
- RestartRequest = NULL;
- ShutdownRequest = NULL;
- PendingSignal = 0;
+ if (forkflag)
+ {
+ /* Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ }
/* set basic modes, etc. */
- (void) alarm(0);
+ sm_clear_events();
clearstats();
- clearenvelope(e, FALSE);
+ rpool = sm_rpool_new_x(NULL);
+ clearenvelope(e, false, rpool);
e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
set_delivery_mode(SM_DELIVER, e);
e->e_errormode = EM_MAIL;
e->e_id = id;
- e->e_queuedir = queuedir;
- GrabTo = UseErrorsTo = FALSE;
+ e->e_qgrp = qgrp;
+ e->e_qdir = qdir;
+ GrabTo = UseErrorsTo = false;
ExitStat = EX_OK;
if (forkflag)
{
disconnect(1, e);
- OpMode = MD_QUEUERUN;
+ set_op_mode(MD_QUEUERUN);
}
- sm_setproctitle(TRUE, e, "%s: from queue", qid_printname(e));
+ sm_setproctitle(true, e, "%s from queue", qid_printname(e));
if (LogLevel > 76)
- sm_syslog(LOG_DEBUG, e->e_id,
- "dowork, pid=%d",
- (int) getpid());
+ sm_syslog(LOG_DEBUG, e->e_id, "dowork, pid=%d",
+ (int) CurrentPid);
/* don't use the headers from sendmail.cf... */
e->e_header = NULL;
/* read the queue control file -- return if locked */
- if (!readqf(e))
+ if (!readqf(e, false))
{
if (tTd(40, 4) && e->e_id != NULL)
- dprintf("readqf(%s) failed\n",
+ sm_dprintf("readqf(%s) failed\n",
qid_printname(e));
e->e_id = NULL;
if (forkflag)
- finis(FALSE, EX_OK);
+ finis(false, true, EX_OK);
else
+ {
+ /* adding this frees 8 bytes */
+ clearenvelope(e, false, rpool);
+
+ /* adding this frees 12 bytes */
+ sm_rpool_free(rpool);
+ e->e_rpool = NULL;
return 0;
+ }
}
e->e_flags |= EF_INQUEUE;
- eatheader(e, requeueflag);
+ eatheader(e, requeueflag, true);
if (requeueflag)
- queueup(e, FALSE);
+ queueup(e, false, false);
/* do the delivery */
sendall(e, SM_DELIVER);
/* finish up and exit */
if (forkflag)
- finis(TRUE, ExitStat);
+ finis(true, true, ExitStat);
else
- dropenvelope(e, TRUE);
+ {
+ dropenvelope(e, true, false);
+ sm_rpool_free(rpool);
+ e->e_rpool = NULL;
+ }
}
e->e_id = NULL;
return pid;
}
- /*
+
+/*
+** DOWORKLIST -- process a list of envelopes as work requests
+**
+** Similar to dowork(), except that after forking, it processes an
+** envelope and its siblings, treating each envelope as a work request.
+**
+** Parameters:
+** el -- envelope to be processed including its siblings.
+** forkflag -- if set, run this in background.
+** requeueflag -- if set, reinstantiate the queue quickly.
+** This is used when expanding aliases in the queue.
+** If forkflag is also set, it doesn't wait for the
+** child.
+**
+** Returns:
+** process id of process that is running the queue job.
+**
+** Side Effects:
+** The work request is satisfied if possible.
+*/
+
+pid_t
+doworklist(el, forkflag, requeueflag)
+ ENVELOPE *el;
+ bool forkflag;
+ bool requeueflag;
+{
+ register pid_t pid;
+ ENVELOPE *ei;
+
+ if (tTd(40, 1))
+ sm_dprintf("doworklist()\n");
+
+ /*
+ ** Fork for work.
+ */
+
+ if (forkflag)
+ {
+ /*
+ ** Since the delivery may happen in a child and the
+ ** parent does not wait, the parent may close the
+ ** maps thereby removing any shared memory used by
+ ** the map. Therefore, close the maps now so the
+ ** child will dynamically open them if necessary.
+ */
+
+ closemaps(false);
+
+ pid = fork();
+ if (pid < 0)
+ {
+ syserr("doworklist: cannot fork");
+ return 0;
+ }
+ else if (pid > 0)
+ {
+ /* parent -- clean out connection cache */
+ mci_flush(false, NULL);
+ }
+ else
+ {
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ /* Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ CurrentPid = getpid();
+ sm_exc_newthread(fatal_error);
+
+ /*
+ ** See note above about SMTP processes and SIGCHLD.
+ */
+
+ if (OpMode == MD_SMTP ||
+ OpMode == MD_DAEMON ||
+ MaxQueueChildren > 0)
+ {
+ proc_list_clear();
+ sm_releasesignal(SIGCHLD);
+ (void) sm_signal(SIGCHLD, SIG_DFL);
+ }
+
+ /* child -- error messages to the transcript */
+ QuickAbort = OnlyOneError = false;
+ }
+ }
+ else
+ {
+ pid = 0;
+ }
+
+ if (pid != 0)
+ return pid;
+
+ /*
+ ** IN CHILD
+ ** Lock the control file to avoid duplicate deliveries.
+ ** Then run the file as though we had just read it.
+ ** We save an idea of the temporary name so we
+ ** can recover on interrupt.
+ */
+
+ if (forkflag)
+ {
+ /* Reset global flags */
+ RestartRequest = NULL;
+ RestartWorkGroup = false;
+ ShutdownRequest = NULL;
+ PendingSignal = 0;
+ }
+
+ /* set basic modes, etc. */
+ sm_clear_events();
+ clearstats();
+ GrabTo = UseErrorsTo = false;
+ ExitStat = EX_OK;
+ if (forkflag)
+ {
+ disconnect(1, el);
+ set_op_mode(MD_QUEUERUN);
+ }
+ if (LogLevel > 76)
+ sm_syslog(LOG_DEBUG, el->e_id, "doworklist, pid=%d",
+ (int) CurrentPid);
+
+ for (ei = el; ei != NULL; ei = ei->e_sibling)
+ {
+ ENVELOPE e;
+ SM_RPOOL_T *rpool;
+
+ if (WILL_BE_QUEUED(ei->e_sendmode))
+ continue;
+#if _FFR_QUARANTINE
+ else if (QueueMode != QM_QUARANTINE &&
+ ei->e_quarmsg != NULL)
+ continue;
+#endif /* _FFR_QUARANTINE */
+
+ rpool = sm_rpool_new_x(NULL);
+ clearenvelope(&e, true, rpool);
+ e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
+ set_delivery_mode(SM_DELIVER, &e);
+ e.e_errormode = EM_MAIL;
+ e.e_id = ei->e_id;
+ e.e_qgrp = ei->e_qgrp;
+ e.e_qdir = ei->e_qdir;
+ openxscript(&e);
+ sm_setproctitle(true, &e, "%s from queue", qid_printname(&e));
+
+ /* don't use the headers from sendmail.cf... */
+ e.e_header = NULL;
+ CurEnv = &e;
+
+ /* read the queue control file -- return if locked */
+ if (readqf(&e, false))
+ {
+ e.e_flags |= EF_INQUEUE;
+ eatheader(&e, requeueflag, true);
+
+ if (requeueflag)
+ queueup(&e, false, false);
+
+ /* do the delivery */
+ sendall(&e, SM_DELIVER);
+ dropenvelope(&e, true, false);
+ }
+ else
+ {
+ if (tTd(40, 4) && e.e_id != NULL)
+ sm_dprintf("readqf(%s) failed\n",
+ qid_printname(&e));
+ }
+ sm_rpool_free(rpool);
+ ei->e_id = NULL;
+ }
+
+ /* restore CurEnv */
+ CurEnv = el;
+
+ /* finish up and exit */
+ if (forkflag)
+ finis(true, true, ExitStat);
+ return 0;
+}
+/*
** READQF -- read queue file and set up environment.
**
** Parameters:
** e -- the envelope of the job to run.
+** openonly -- only open the qf (returned as e_lockfp)
**
** Returns:
-** TRUE if it successfully read the queue file.
-** FALSE otherwise.
+** true if it successfully read the queue file.
+** false otherwise.
**
** Side Effects:
** The queue file is returned locked.
*/
static bool
-readqf(e)
+readqf(e, openonly)
register ENVELOPE *e;
+ bool openonly;
{
- register FILE *qfp;
+ register SM_FILE_T *qfp;
ADDRESS *ctladdr;
struct stat st, stf;
char *bp;
int qfver = 0;
long hdrsize = 0;
register char *p;
+ char *frcpt = NULL;
char *orcpt = NULL;
- bool nomore = FALSE;
+ bool nomore = false;
+ bool bogus = false;
MODE_T qsafe;
char qf[MAXPATHLEN];
char buf[MAXLINE];
@@ -1904,33 +3696,37 @@ readqf(e)
** Read and process the file.
*/
- (void) strlcpy(qf, queuename(e, 'q'), sizeof qf);
- qfp = fopen(qf, "r+");
+ (void) sm_strlcpy(qf, queuename(e, ANYQFL_LETTER), sizeof qf);
+ qfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDWR, NULL);
if (qfp == NULL)
{
int save_errno = errno;
if (tTd(40, 8))
- dprintf("readqf(%s): fopen failure (%s)\n",
- qf, errstring(errno));
+ sm_dprintf("readqf(%s): sm_io_open failure (%s)\n",
+ qf, sm_errstring(errno));
errno = save_errno;
if (errno != ENOENT
)
syserr("readqf: no control file %s", qf);
- return FALSE;
+ RELEASE_QUEUE;
+ return false;
}
- if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
+ if (!lockfile(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), qf, NULL,
+ LOCK_EX|LOCK_NB))
{
/* being processed by another queuer */
if (Verbose)
- printf("%s: locked\n", e->e_id);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s: locked\n", e->e_id);
if (tTd(40, 8))
- dprintf("%s: locked\n", e->e_id);
+ sm_dprintf("%s: locked\n", e->e_id);
if (LogLevel > 19)
sm_syslog(LOG_DEBUG, e->e_id, "locked");
- (void) fclose(qfp);
- return FALSE;
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
/*
@@ -1952,35 +3748,38 @@ readqf(e)
*/
if (stat(qf, &stf) < 0 ||
- fstat(fileno(qfp), &st) < 0)
+ fstat(sm_io_getinfo(qfp, SM_IO_WHAT_FD, NULL), &st) < 0)
{
/* must have been being processed by someone else */
if (tTd(40, 8))
- dprintf("readqf(%s): [f]stat failure (%s)\n",
- qf, errstring(errno));
- (void) fclose(qfp);
- return FALSE;
+ sm_dprintf("readqf(%s): [f]stat failure (%s)\n",
+ qf, sm_errstring(errno));
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
if (st.st_nlink != stf.st_nlink ||
st.st_dev != stf.st_dev ||
- st.st_ino != stf.st_ino ||
-# if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
+ ST_INODE(st) != ST_INODE(stf) ||
+#if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
st.st_gen != stf.st_gen ||
-# endif /* HAS_ST_GEN && 0 */
+#endif /* HAS_ST_GEN && 0 */
st.st_uid != stf.st_uid ||
st.st_gid != stf.st_gid ||
st.st_size != stf.st_size)
{
/* changed after opened */
if (Verbose)
- printf("%s: changed\n", e->e_id);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s: changed\n", e->e_id);
if (tTd(40, 8))
- dprintf("%s: changed\n", e->e_id);
+ sm_dprintf("%s: changed\n", e->e_id);
if (LogLevel > 19)
sm_syslog(LOG_DEBUG, e->e_id, "changed");
- (void) fclose(qfp);
- return FALSE;
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
/*
@@ -1988,39 +3787,78 @@ readqf(e)
*/
qsafe = S_IWOTH|S_IWGRP;
-#if _FFR_QUEUE_FILE_MODE
if (bitset(S_IWGRP, QueueFileMode))
qsafe &= ~S_IWGRP;
-#endif /* _FFR_QUEUE_FILE_MODE */
- if ((st.st_uid != geteuid() &&
- st.st_uid != TrustedUid &&
- geteuid() != RealUid) ||
- bitset(qsafe, st.st_mode))
+ bogus = st.st_uid != geteuid() &&
+ st.st_uid != TrustedUid &&
+ geteuid() != RealUid;
+
+ /*
+ ** If this qf file results from a set-group-ID binary, then
+ ** we check whether the directory is group-writable,
+ ** the queue file mode contains the group-writable bit, and
+ ** the groups are the same.
+ ** Notice: this requires that the set-group-ID binary is used to
+ ** run the queue!
+ */
+
+ if (bogus && st.st_gid == getegid() && UseMSP)
+ {
+ char delim;
+ struct stat dst;
+
+ bp = SM_LAST_DIR_DELIM(qf);
+ if (bp == NULL)
+ delim = '\0';
+ else
+ {
+ delim = *bp;
+ *bp = '\0';
+ }
+ if (stat(delim == '\0' ? "." : qf, &dst) < 0)
+ syserr("readqf: cannot stat directory %s",
+ delim == '\0' ? "." : qf);
+ else
+ {
+ bogus = !(bitset(S_IWGRP, QueueFileMode) &&
+ bitset(S_IWGRP, dst.st_mode) &&
+ dst.st_gid == st.st_gid);
+ }
+ if (delim != '\0')
+ *bp = delim;
+ }
+ if (!bogus)
+ bogus = bitset(qsafe, st.st_mode);
+ if (bogus)
{
if (LogLevel > 0)
{
sm_syslog(LOG_ALERT, e->e_id,
- "bogus queue file, uid=%d, mode=%o",
- st.st_uid, st.st_mode);
+ "bogus queue file, uid=%d, gid=%d, mode=%o",
+ st.st_uid, st.st_gid, st.st_mode);
}
if (tTd(40, 8))
- dprintf("readqf(%s): bogus file\n", qf);
- loseqfile(e, "bogus file uid in mqueue");
- (void) fclose(qfp);
- return FALSE;
+ sm_dprintf("readqf(%s): bogus file\n", qf);
+ e->e_flags |= EF_INQUEUE;
+ if (!openonly)
+ loseqfile(e, "bogus file uid/gid in mqueue");
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
if (st.st_size == 0)
{
/* must be a bogus file -- if also old, just remove it */
- if (st.st_ctime + 10 * 60 < curtime())
+ if (!openonly && st.st_ctime + 10 * 60 < curtime())
{
- (void) xunlink(queuename(e, 'd'));
- (void) xunlink(queuename(e, 'q'));
+ (void) xunlink(queuename(e, DATAFL_LETTER));
+ (void) xunlink(queuename(e, ANYQFL_LETTER));
}
- (void) fclose(qfp);
- return FALSE;
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
if (st.st_nlink == 0)
@@ -2030,151 +3868,203 @@ readqf(e)
** unlinked. Just assume it is zero length.
*/
- (void) fclose(qfp);
- return FALSE;
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
+#if _FFR_TRUSTED_QF
+ /*
+ ** If we don't own the file mark it as unsafe.
+ ** However, allow TrustedUser to own it as well
+ ** in case TrustedUser manipulates the queue.
+ */
+
+ if (st.st_uid != geteuid() && st.st_uid != TrustedUid)
+ e->e_flags |= EF_UNSAFE;
+#else /* _FFR_TRUSTED_QF */
+ /* If we don't own the file mark it as unsafe */
+ if (st.st_uid != geteuid())
+ e->e_flags |= EF_UNSAFE;
+#endif /* _FFR_TRUSTED_QF */
+
/* good file -- save this lock */
e->e_lockfp = qfp;
+ /* Just wanted the open file */
+ if (openonly)
+ return true;
+
/* do basic system initialization */
initsys(e);
- define('i', e->e_id, e);
+ macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
LineNumber = 0;
e->e_flags |= EF_GLOBALERRS;
- OpMode = MD_QUEUERUN;
+ set_op_mode(MD_QUEUERUN);
ctladdr = NULL;
+#if _FFR_QUARANTINE
+ e->e_qfletter = queue_letter(e, ANYQFL_LETTER);
+#endif /* _FFR_QUARANTINE */
+ e->e_dfqgrp = e->e_qgrp;
+ e->e_dfqdir = e->e_qdir;
+#if _FFR_QUEUE_MACRO
+ macdefine(&e->e_macro, A_TEMP, macid("{queue}"),
+ qid_printqueue(e->e_qgrp, e->e_qdir));
+#endif /* _FFR_QUEUE_MACRO */
e->e_dfino = -1;
e->e_msgsize = -1;
-# if _FFR_QUEUEDELAY
+#if _FFR_QUEUEDELAY
e->e_queuealg = QD_LINEAR;
e->e_queuedelay = (time_t) 0;
-# endif /* _FFR_QUEUEDELAY */
+#endif /* _FFR_QUEUEDELAY */
while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
{
- u_long qflags;
+ unsigned long qflags;
ADDRESS *q;
- int mid;
+ int r;
time_t now;
auto char *ep;
if (tTd(40, 4))
- dprintf("+++++ %s\n", bp);
+ sm_dprintf("+++++ %s\n", bp);
if (nomore)
{
/* hack attack */
- syserr("SECURITY ALERT: extra data in qf: %s", bp);
- (void) fclose(qfp);
+ hackattack:
+ syserr("SECURITY ALERT: extra or bogus data in queue file: %s",
+ bp);
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+
+ /* the file is already on disk */
+ e->e_flags |= EF_INQUEUE;
loseqfile(e, "bogus queue line");
- return FALSE;
+ RELEASE_QUEUE;
+ return false;
}
switch (bp[0])
{
- case 'V': /* queue file version number */
- qfver = atoi(&bp[1]);
- if (qfver <= QF_VERSION)
- break;
- syserr("Version number in qf (%d) greater than max (%d)",
- qfver, QF_VERSION);
- (void) fclose(qfp);
- loseqfile(e, "unsupported qf file version");
- return FALSE;
+ case 'A': /* AUTH= parameter */
+ if (!xtextok(&bp[1]))
+ goto hackattack;
+ e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ break;
+
+ case 'B': /* body type */
+ r = check_bodytype(&bp[1]);
+ if (!BODYTYPE_VALID(r))
+ goto hackattack;
+ e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ break;
case 'C': /* specify controlling user */
- ctladdr = setctluser(&bp[1], qfver);
+ ctladdr = setctluser(&bp[1], qfver, e);
break;
- case 'Q': /* original recipient */
- orcpt = newstr(&bp[1]);
+ case 'D': /* data file name */
+ /* obsolete -- ignore */
break;
- case 'R': /* specify recipient */
- p = bp;
- qflags = 0;
- if (qfver >= 1)
+ case 'd': /* data file directory name */
{
- /* get flag bits */
- while (*++p != '\0' && *p != ':')
+ int qgrp, qdir;
+
+#if _FFR_MSP_PARANOIA
+ /* forbid queue groups in MSP? */
+ if (UseMSP)
+ goto hackattack;
+#endif /* _FFR_MSP_PARANOIA */
+ for (qgrp = 0;
+ qgrp < NumQueue && Queue[qgrp] != NULL;
+ ++qgrp)
{
- switch (*p)
+ for (qdir = 0;
+ qdir < Queue[qgrp]->qg_numqueues;
+ ++qdir)
{
- case 'N':
- qflags |= QHASNOTIFY;
- break;
-
- case 'S':
- qflags |= QPINGONSUCCESS;
- break;
-
- case 'F':
- qflags |= QPINGONFAILURE;
- break;
-
- case 'D':
- qflags |= QPINGONDELAY;
- break;
-
- case 'P':
- qflags |= QPRIMARY;
- break;
-
- case 'A':
- if (ctladdr != NULL)
- ctladdr->q_flags |= QALIAS;
- break;
+ if (strcmp(&bp[1],
+ Queue[qgrp]->qg_qpaths[qdir].qp_name)
+ == 0)
+ {
+ e->e_dfqgrp = qgrp;
+ e->e_dfqdir = qdir;
+ goto done;
+ }
}
}
+ loseqfile(e, "bogus queue file directory");
+ RELEASE_QUEUE;
+ return false;
+ done:
+ break;
}
- else
- qflags |= QPRIMARY;
- q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
- if (q != NULL)
- {
- q->q_alias = ctladdr;
- if (qfver >= 1)
- q->q_flags &= ~Q_PINGFLAGS;
- q->q_flags |= qflags;
- q->q_orcpt = orcpt;
- (void) recipient(q, &e->e_sendqueue, 0, e);
- }
- orcpt = NULL;
- break;
case 'E': /* specify error recipient */
/* no longer used */
break;
- case 'H': /* header */
- (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
- hdrsize += strlen(&bp[1]);
- break;
+ case 'F': /* flag bits */
+ if (strncmp(bp, "From ", 5) == 0)
+ {
+ /* we are being spoofed! */
+ syserr("SECURITY ALERT: bogus qf line %s", bp);
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ loseqfile(e, "bogus queue line");
+ RELEASE_QUEUE;
+ return false;
+ }
+ for (p = &bp[1]; *p != '\0'; p++)
+ {
+ switch (*p)
+ {
+ case '8': /* has 8 bit data */
+ e->e_flags |= EF_HAS8BIT;
+ break;
- case 'L': /* Solaris Content-Length: */
- case 'M': /* message */
- /* ignore this; we want a new message next time */
- break;
+ case 'b': /* delete Bcc: header */
+ e->e_flags |= EF_DELETE_BCC;
+ break;
- case 'S': /* sender */
- setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
- break;
+ case 'd': /* envelope has DSN RET= */
+ e->e_flags |= EF_RET_PARAM;
+ break;
- case 'B': /* body type */
- e->e_bodytype = newstr(&bp[1]);
+ case 'n': /* don't return body */
+ e->e_flags |= EF_NO_BODY_RETN;
+ break;
+
+ case 'r': /* response */
+ e->e_flags |= EF_RESPONSE;
+ break;
+
+ case 's': /* split */
+ e->e_flags |= EF_SPLIT;
+ break;
+
+ case 'w': /* warning sent */
+ e->e_flags |= EF_WARNING;
+ break;
+ }
+ }
break;
-# if _FFR_SAVE_CHARSET
- case 'X': /* character set */
- e->e_charset = newstr(&bp[1]);
+#if _FFR_QUEUEDELAY
+ case 'G': /* queue delay algorithm */
+ e->e_queuealg = atoi(&buf[1]);
break;
-# endif /* _FFR_SAVE_CHARSET */
+#endif /* _FFR_QUEUEDELAY */
- case 'D': /* data file name */
- /* obsolete -- ignore */
+#if _FFR_QUARANTINE
+ case 'q': /* quarantine reason */
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
break;
+#endif /* _FFR_QUARANTINE */
- case 'T': /* init time */
- e->e_ctime = atol(&bp[1]);
+ case 'H': /* header */
+ (void) chompheader(&bp[1], CHHDR_QUEUE, NULL, e);
+ hdrsize += strlen(&bp[1]);
break;
case 'I': /* data file's inode number */
@@ -2185,14 +4075,10 @@ readqf(e)
e->e_dtime = atol(&buf[1]);
break;
-# if _FFR_QUEUEDELAY
- case 'G': /* queue delay algorithm */
- e->e_queuealg = atoi(&buf[1]);
- break;
- case 'Y': /* current delay */
- e->e_queuedelay = (time_t) atol(&buf[1]);
+ case 'L': /* Solaris Content-Length: */
+ case 'M': /* message */
+ /* ignore this; we want a new message next time */
break;
-# endif /* _FFR_QUEUEDELAY */
case 'N': /* number of delivery attempts */
e->e_ntries = atoi(&buf[1]);
@@ -2204,12 +4090,14 @@ readqf(e)
{
char *howlong;
- howlong = pintvl(now - e->e_dtime, TRUE);
+ howlong = pintvl(now - e->e_dtime, true);
if (Verbose)
- printf("%s: too young (%s)\n",
- e->e_id, howlong);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s: too young (%s)\n",
+ e->e_id, howlong);
if (tTd(40, 8))
- dprintf("%s: too young (%s)\n",
+ sm_dprintf("%s: too young (%s)\n",
e->e_id, howlong);
if (LogLevel > 19)
sm_syslog(LOG_DEBUG, e->e_id,
@@ -2217,11 +4105,13 @@ readqf(e)
howlong);
e->e_id = NULL;
unlockqueue(e);
- return FALSE;
+ RELEASE_QUEUE;
+ return false;
}
- define(macid("{ntries}", NULL), newstr(&buf[1]), e);
+ macdefine(&e->e_macro, A_TEMP,
+ macid("{ntries}"), &buf[1]);
-# if NAMED_BIND
+#if NAMED_BIND
/* adjust BIND parameters immediately */
if (e->e_ntries == 0)
{
@@ -2233,108 +4123,151 @@ readqf(e)
_res.retry = TimeOuts.res_retry[RES_TO_NORMAL];
_res.retrans = TimeOuts.res_retrans[RES_TO_NORMAL];
}
-# endif /* NAMED_BIND */
+#endif /* NAMED_BIND */
break;
case 'P': /* message priority */
e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
break;
- case 'F': /* flag bits */
- if (strncmp(bp, "From ", 5) == 0)
- {
- /* we are being spoofed! */
- syserr("SECURITY ALERT: bogus qf line %s", bp);
- (void) fclose(qfp);
- loseqfile(e, "bogus queue line");
- return FALSE;
- }
- for (p = &bp[1]; *p != '\0'; p++)
+ case 'Q': /* original recipient */
+ orcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ break;
+
+ case 'r': /* original recipient */
+ frcpt = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ break;
+
+ case 'R': /* specify recipient */
+ p = bp;
+ qflags = 0;
+ if (qfver >= 1)
{
- switch (*p)
+ /* get flag bits */
+ while (*++p != '\0' && *p != ':')
{
- case 'w': /* warning sent */
- e->e_flags |= EF_WARNING;
- break;
+ switch (*p)
+ {
+ case 'N':
+ qflags |= QHASNOTIFY;
+ break;
- case 'r': /* response */
- e->e_flags |= EF_RESPONSE;
- break;
+ case 'S':
+ qflags |= QPINGONSUCCESS;
+ break;
- case '8': /* has 8 bit data */
- e->e_flags |= EF_HAS8BIT;
- break;
+ case 'F':
+ qflags |= QPINGONFAILURE;
+ break;
- case 'b': /* delete Bcc: header */
- e->e_flags |= EF_DELETE_BCC;
- break;
+ case 'D':
+ qflags |= QPINGONDELAY;
+ break;
- case 'd': /* envelope has DSN RET= */
- e->e_flags |= EF_RET_PARAM;
- break;
+ case 'P':
+ qflags |= QPRIMARY;
+ break;
- case 'n': /* don't return body */
- e->e_flags |= EF_NO_BODY_RETN;
- break;
+ case 'A':
+ if (ctladdr != NULL)
+ ctladdr->q_flags |= QALIAS;
+ break;
+
+ default: /* ignore or complain? */
+ break;
+ }
}
}
+ else
+ qflags |= QPRIMARY;
+ q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e,
+ true);
+ if (q != NULL)
+ {
+ q->q_alias = ctladdr;
+ if (qfver >= 1)
+ q->q_flags &= ~Q_PINGFLAGS;
+ q->q_flags |= qflags;
+ q->q_finalrcpt = frcpt;
+ q->q_orcpt = orcpt;
+ (void) recipient(q, &e->e_sendqueue, 0, e);
+ }
+ frcpt = NULL;
+ orcpt = NULL;
break;
- case 'Z': /* original envelope id from ESMTP */
- e->e_envid = newstr(&bp[1]);
- define(macid("{dsn_envid}", NULL), newstr(&bp[1]), e);
+ case 'S': /* sender */
+ setsender(sm_rpool_strdup_x(e->e_rpool, &bp[1]),
+ e, NULL, '\0', true);
break;
- case 'A': /* AUTH= parameter */
- e->e_auth_param = newstr(&bp[1]);
+ case 'T': /* init time */
+ e->e_ctime = atol(&bp[1]);
+ break;
+
+ case 'V': /* queue file version number */
+ qfver = atoi(&bp[1]);
+ if (queuedelay_qfver_unsupported(qfver))
+ syserr("queue file version %d not supported: %s",
+ qfver,
+ "sendmail not compiled with _FFR_QUEUEDELAY");
+ if (qfver <= QF_VERSION)
+ break;
+ syserr("Version number in queue file (%d) greater than max (%d)",
+ qfver, QF_VERSION);
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ loseqfile(e, "unsupported queue file version");
+ RELEASE_QUEUE;
+ return false;
+ /* NOTREACHED */
+ break;
+
+#if _FFR_QUEUEDELAY
+ case 'Y': /* current delay */
+ e->e_queuedelay = (time_t) atol(&buf[1]);
+ break;
+#endif /* _FFR_QUEUEDELAY */
+
+ case 'Z': /* original envelope id from ESMTP */
+ e->e_envid = sm_rpool_strdup_x(e->e_rpool, &bp[1]);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_envid}"), e->e_envid);
break;
+ case '!': /* deliver by */
+
+ /* format: flag (1 char) space long-integer */
+ e->e_dlvr_flag = buf[1];
+ e->e_deliver_by = strtol(&buf[3], NULL, 10);
+
case '$': /* define macro */
{
char *p;
- mid = macid(&bp[1], &ep);
- if (mid == 0)
+ /* XXX elimate p? */
+ r = macid_parse(&bp[1], &ep);
+ if (r == 0)
break;
-
- p = newstr(ep);
- define(mid, p, e);
-
- /*
- ** HACK ALERT: Unfortunately, 8.10 and
- ** 8.11 reused the ${if_addr} and
- ** ${if_family} macros for both the incoming
- ** interface address/family (getrequests())
- ** and the outgoing interface address/family
- ** (makeconnection()). In order for D_BINDIF
- ** to work properly, have to preserve the
- ** incoming information in the queue file for
- ** later delivery attempts. The original
- ** information is stored in the envelope
- ** in readqf() so it can be stored in
- ** queueup_macros(). This should be fixed
- ** in 8.12.
- */
-
- if (strcmp(macname(mid), "if_addr") == 0)
- e->e_if_macros[EIF_ADDR] = p;
+ p = sm_rpool_strdup_x(e->e_rpool, ep);
+ macdefine(&e->e_macro, A_PERM, r, p);
}
break;
case '.': /* terminate file */
- nomore = TRUE;
+ nomore = true;
break;
default:
syserr("readqf: %s: line %d: bad line \"%s\"",
qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
- (void) fclose(qfp);
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
loseqfile(e, "unrecognized line");
- return FALSE;
+ RELEASE_QUEUE;
+ return false;
}
if (bp != buf)
- sm_free(bp);
+ sm_free(bp); /* XXX */
}
/*
@@ -2345,25 +4278,38 @@ readqf(e)
if (LineNumber == 0)
{
errno = 0;
- e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
- return TRUE;
+ e->e_flags |= EF_CLRQUEUE|EF_FATALERRS|EF_RESPONSE;
+ RELEASE_QUEUE;
+ return true;
+ }
+
+ /* Check to make sure we have a complete queue file read */
+ if (!nomore)
+ {
+ syserr("readqf: %s: incomplete queue file read", qf);
+ (void) sm_io_close(qfp, SM_TIME_DEFAULT);
+ RELEASE_QUEUE;
+ return false;
}
/* possibly set ${dsn_ret} macro */
if (bitset(EF_RET_PARAM, e->e_flags))
{
if (bitset(EF_NO_BODY_RETN, e->e_flags))
- define(macid("{dsn_ret}", NULL), "hdrs", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_ret}"), "hdrs");
else
- define(macid("{dsn_ret}", NULL), "full", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_ret}"), "full");
}
/*
** Arrange to read the data file.
*/
- p = queuename(e, 'd');
- e->e_dfp = fopen(p, "r");
+ p = queuename(e, DATAFL_LETTER);
+ e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, p, SM_IO_RDONLY,
+ NULL);
if (e->e_dfp == NULL)
{
syserr("readqf: cannot open %s", p);
@@ -2371,17 +4317,19 @@ readqf(e)
else
{
e->e_flags |= EF_HAS_DF;
- if (fstat(fileno(e->e_dfp), &st) >= 0)
+ if (fstat(sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL), &st)
+ >= 0)
{
e->e_msgsize = st.st_size + hdrsize;
e->e_dfdev = st.st_dev;
- e->e_dfino = st.st_ino;
+ e->e_dfino = ST_INODE(st);
}
}
- return TRUE;
+ RELEASE_QUEUE;
+ return true;
}
- /*
+/*
** PRTSTR -- print a string, "unprintable" characters are shown as \oct
**
** Parameters:
@@ -2389,7 +4337,7 @@ readqf(e)
** ml -- maximum length of output
**
** Returns:
-** none.
+** number of entries
**
** Side Effects:
** Prints a string on stdout.
@@ -2400,7 +4348,7 @@ prtstr(s, ml)
char *s;
int ml;
{
- char c;
+ int c;
if (s == NULL)
return;
@@ -2410,20 +4358,104 @@ prtstr(s, ml)
{
if (ml-- > 0)
{
- putchar(c);
- putchar(c);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
}
}
else if (isascii(c) && isprint(c))
- putchar(c);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
else
{
if ((ml -= 3) > 0)
- printf("\\%03o", c);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\\%03o", c & 0xFF);
}
}
}
- /*
+/*
+** PRINTNQE -- print out number of entries in the mail queue
+**
+** Parameters:
+** out -- output file pointer.
+** prefix -- string to output in front of each line.
+**
+** Returns:
+** none.
+*/
+
+void
+printnqe(out, prefix)
+ SM_FILE_T *out;
+ char *prefix;
+{
+#if SM_CONF_SHM
+ int i, k = 0, nrequests = 0;
+ bool unknown = false;
+
+ if (ShmId == SM_SHM_NO_ID)
+ {
+ if (prefix == NULL)
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "Data unavailable: shared memory not updated\n");
+ else
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%sNOTCONFIGURED:-1\r\n", prefix);
+ return;
+ }
+ for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
+ {
+ int j;
+
+ k++;
+ for (j = 0; j < Queue[i]->qg_numqueues; j++)
+ {
+ int n;
+
+ if (StopRequest)
+ stop_sendmail();
+
+ n = QSHM_ENTRIES(Queue[i]->qg_qpaths[j].qp_idx);
+ if (prefix != NULL)
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%s%s:%d\r\n",
+ prefix, qid_printqueue(i, j), n);
+ else if (n < 0)
+ {
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%s: unknown number of entries\n",
+ qid_printqueue(i, j));
+ unknown = true;
+ }
+ else if (n == 0)
+ {
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%s is empty\n",
+ qid_printqueue(i, j));
+ }
+ else if (n > 0)
+ {
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%s: entries=%d\n",
+ qid_printqueue(i, j), n);
+ nrequests += n;
+ k++;
+ }
+ }
+ }
+ if (prefix == NULL && k > 1)
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "\t\tTotal requests: %d%s\n",
+ nrequests, unknown ? " (about)" : "");
+#else /* SM_CONF_SHM */
+ if (prefix == NULL)
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "Data unavailable without shared memory support\n");
+ else
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%sNOTAVAILABLE:-1\r\n", prefix);
+#endif /* SM_CONF_SHM */
+}
+/*
** PRINTQUEUE -- print out a representation of the mail queue
**
** Parameters:
@@ -2439,54 +4471,69 @@ prtstr(s, ml)
void
printqueue()
{
- int i, nrequests = 0;
+ int i, k = 0, nrequests = 0;
- for (i = 0; i < NumQueues; i++)
+ for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
{
- if (StopRequest)
- stop_sendmail();
- nrequests += print_single_queue(i);
+ int j;
+
+ k++;
+ for (j = 0; j < Queue[i]->qg_numqueues; j++)
+ {
+ if (StopRequest)
+ stop_sendmail();
+ nrequests += print_single_queue(i, j);
+ k++;
+ }
}
- if (NumQueues > 1)
- printf("\t\tTotal Requests: %d\n", nrequests);
+ if (k > 1)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\t\tTotal requests: %d\n",
+ nrequests);
}
- /*
+/*
** PRINT_SINGLE_QUEUE -- print out a representation of a single mail queue
**
** Parameters:
-** queuedir -- queue directory
+** qgrp -- the index of the queue group.
+** qdir -- the queue directory.
**
** Returns:
-** number of entries
+** number of requests in mail queue.
**
** Side Effects:
** Prints a listing of the mail queue on the standard output.
*/
-static int
-print_single_queue(queuedir)
- int queuedir;
+int
+print_single_queue(qgrp, qdir)
+ int qgrp;
+ int qdir;
{
register WORK *w;
- FILE *f;
+ SM_FILE_T *f;
int nrequests;
char qd[MAXPATHLEN];
char qddf[MAXPATHLEN];
char buf[MAXLINE];
- if (queuedir == NOQDIR)
+ if (qdir == NOQDIR)
{
- (void) strlcpy(qd, ".", sizeof qd);
- (void) strlcpy(qddf, ".", sizeof qddf);
+ (void) sm_strlcpy(qd, ".", sizeof qd);
+ (void) sm_strlcpy(qddf, ".", sizeof qddf);
}
else
{
- (void) snprintf(qd, sizeof qd, "%s%s",
- QPaths[queuedir].qp_name,
- (bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
- (void) snprintf(qddf, sizeof qddf, "%s%s",
- QPaths[queuedir].qp_name,
- (bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
+ (void) sm_strlcpyn(qd, sizeof qd, 2,
+ Queue[qgrp]->qg_qpaths[qdir].qp_name,
+ (bitset(QP_SUBQF,
+ Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
+ ? "/qf" : ""));
+ (void) sm_strlcpyn(qddf, sizeof qddf, 2,
+ Queue[qgrp]->qg_qpaths[qdir].qp_name,
+ (bitset(QP_SUBDF,
+ Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
+ ? "/df" : ""));
}
/*
@@ -2496,17 +4543,18 @@ print_single_queue(queuedir)
if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
{
struct stat st;
-# ifdef NGROUPS_MAX
+#ifdef NGROUPS_MAX
int n;
extern GIDSET_T InitialGidSet[NGROUPS_MAX];
-# endif /* NGROUPS_MAX */
+#endif /* NGROUPS_MAX */
if (stat(qd, &st) < 0)
{
- syserr("Cannot stat %s", qid_printqueue(queuedir));
+ syserr("Cannot stat %s",
+ qid_printqueue(qgrp, qdir));
return 0;
}
-# ifdef NGROUPS_MAX
+#ifdef NGROUPS_MAX
n = NGROUPS_MAX;
while (--n >= 0)
{
@@ -2514,9 +4562,9 @@ print_single_queue(queuedir)
break;
}
if (n < 0 && RealGid != st.st_gid)
-# else /* NGROUPS_MAX */
+#else /* NGROUPS_MAX */
if (RealGid != st.st_gid)
-# endif /* NGROUPS_MAX */
+#endif /* NGROUPS_MAX */
{
usrerr("510 You are not permitted to see the queue");
setstat(EX_NOPERM);
@@ -2528,7 +4576,8 @@ print_single_queue(queuedir)
** Read and order the queue.
*/
- nrequests = orderq(queuedir, TRUE);
+ nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
+ (void) sortq(Queue[qgrp]->qg_maxlist);
/*
** Print the work list that we have read.
@@ -2537,20 +4586,25 @@ print_single_queue(queuedir)
/* first see if there is anything */
if (nrequests <= 0)
{
- printf("%s is empty\n", qid_printqueue(queuedir));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s is empty\n",
+ qid_printqueue(qgrp, qdir));
return 0;
}
- CurrentLA = sm_getla(NULL); /* get load average */
+ sm_getla(); /* get load average */
- printf("\t\t%s (%d request%s", qid_printqueue(queuedir), nrequests,
- nrequests == 1 ? "" : "s");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\t\t%s (%d request%s",
+ qid_printqueue(qgrp, qdir),
+ nrequests, nrequests == 1 ? "" : "s");
if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
- printf(", only %d printed", MaxQueueRun);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ ", only %d printed", MaxQueueRun);
if (Verbose)
- printf(")\n----Q-ID---- --Size-- -Priority- ---Q-Time--- ---------Sender/Recipient--------\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ ")\n-----Q-ID----- --Size-- -Priority- ---Q-Time--- --------Sender/Recipient--------\n");
else
- printf(")\n----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ ")\n-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------\n");
for (w = WorkQ; w != NULL; w = w->w_next)
{
struct stat st;
@@ -2558,6 +4612,9 @@ print_single_queue(queuedir)
long dfsize;
int flags = 0;
int qfver;
+#if _FFR_QUARANTINE
+ char quarmsg[MAXLINE];
+#endif /* _FFR_QUARANTINE */
char statmsg[MAXLINE];
char bodytype[MAXNAME + 1];
char qf[MAXPATHLEN];
@@ -2565,34 +4622,80 @@ print_single_queue(queuedir)
if (StopRequest)
stop_sendmail();
- printf("%12s", w->w_name + 2);
- (void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name);
- f = fopen(qf, "r");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%13s",
+ w->w_name + 2);
+ (void) sm_strlcpyn(qf, sizeof qf, 3, qd, "/", w->w_name);
+ f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, qf, SM_IO_RDONLY,
+ NULL);
if (f == NULL)
{
- printf(" (job completed)\n");
+ if (errno == EPERM)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " (permission denied)\n");
+ else if (errno == ENOENT)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " (job completed)\n");
+ else
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " (%s)\n",
+ sm_errstring(errno));
errno = 0;
continue;
}
- w->w_name[0] = 'd';
- (void) snprintf(qf, sizeof qf, "%s/%s", qddf, w->w_name);
+ w->w_name[0] = DATAFL_LETTER;
+ (void) sm_strlcpyn(qf, sizeof qf, 3, qddf, "/", w->w_name);
if (stat(qf, &st) >= 0)
dfsize = st.st_size;
else
+ {
+ ENVELOPE e;
+
+ /*
+ ** Maybe the df file can't be statted because
+ ** it is in a different directory than the qf file.
+ ** In order to find out, we must read the qf file.
+ */
+
+ newenvelope(&e, &BlankEnvelope, sm_rpool_new_x(NULL));
+ e.e_id = w->w_name + 2;
+ e.e_qgrp = qgrp;
+ e.e_qdir = qdir;
dfsize = -1;
+ if (readqf(&e, false))
+ {
+ char *df = queuename(&e, DATAFL_LETTER);
+ if (stat(df, &st) >= 0)
+ dfsize = st.st_size;
+ }
+ if (e.e_lockfp != NULL)
+ {
+ (void) sm_io_close(e.e_lockfp, SM_TIME_DEFAULT);
+ e.e_lockfp = NULL;
+ }
+ clearenvelope(&e, false, e.e_rpool);
+ sm_rpool_free(e.e_rpool);
+ }
if (w->w_lock)
- printf("*");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "*");
+#if _FFR_QUARANTINE
+ else if (QueueMode == QM_LOST)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "?");
+#endif /* _FFR_QUARANTINE */
else if (w->w_tooyoung)
- printf("-");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "-");
else if (shouldqueue(w->w_pri, w->w_ctime))
- printf("X");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "X");
else
- printf(" ");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " ");
+
errno = 0;
+#if _FFR_QUARANTINE
+ quarmsg[0] = '\0';
+#endif /* _FFR_QUARANTINE */
statmsg[0] = bodytype[0] = '\0';
qfver = 0;
- while (fgets(buf, sizeof buf, f) != NULL)
+ while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
register int i;
register char *p;
@@ -2600,7 +4703,7 @@ print_single_queue(queuedir)
if (StopRequest)
stop_sendmail();
- fixcrlf(buf, TRUE);
+ fixcrlf(buf, true);
switch (buf[0])
{
case 'V': /* queue file version */
@@ -2614,6 +4717,15 @@ print_single_queue(queuedir)
statmsg[i] = '\0';
break;
+#if _FFR_QUARANTINE
+ case 'q': /* quarantine reason */
+ if ((i = strlen(&buf[1])) >= sizeof quarmsg)
+ i = sizeof quarmsg - 1;
+ memmove(quarmsg, &buf[1], i);
+ quarmsg[i] = '\0';
+ break;
+#endif /* _FFR_QUARANTINE */
+
case 'B': /* body type */
if ((i = strlen(&buf[1])) >= sizeof bodytype)
i = sizeof bodytype - 1;
@@ -2624,33 +4736,58 @@ print_single_queue(queuedir)
case 'S': /* sender name */
if (Verbose)
{
- printf("%8ld %10ld%c%.12s ",
- dfsize,
- w->w_pri,
- bitset(EF_WARNING, flags) ? '+' : ' ',
- ctime(&submittime) + 4);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%8ld %10ld%c%.12s ",
+ dfsize,
+ w->w_pri,
+ bitset(EF_WARNING, flags)
+ ? '+' : ' ',
+ ctime(&submittime) + 4);
prtstr(&buf[1], 78);
}
else
{
- printf("%8ld %.16s ", dfsize,
- ctime(&submittime));
- prtstr(&buf[1], 40);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%8ld %.16s ",
+ dfsize,
+ ctime(&submittime));
+ prtstr(&buf[1], 39);
}
+#if _FFR_QUARANTINE
+ if (quarmsg[0] != '\0')
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n QUARANTINE: %.*s",
+ Verbose ? 100 : 60,
+ quarmsg);
+ quarmsg[0] = '\0';
+ }
+#endif /* _FFR_QUARANTINE */
if (statmsg[0] != '\0' || bodytype[0] != '\0')
{
- printf("\n %10.10s", bodytype);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n %10.10s",
+ bodytype);
if (statmsg[0] != '\0')
- printf(" (%.*s)",
- Verbose ? 100 : 60,
- statmsg);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ " (%.*s)",
+ Verbose ? 100 : 60,
+ statmsg);
+ statmsg[0] = '\0';
}
break;
case 'C': /* controlling user */
if (Verbose)
- printf("\n\t\t\t\t (---%.74s---)",
- &buf[1]);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n\t\t\t\t\t\t(---%.64s---)",
+ &buf[1]);
break;
case 'R': /* recipient name */
@@ -2664,13 +4801,25 @@ print_single_queue(queuedir)
}
if (Verbose)
{
- printf("\n\t\t\t\t\t ");
- prtstr(p, 73);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n\t\t\t\t\t\t");
+ prtstr(p, 71);
}
else
{
- printf("\n\t\t\t\t ");
- prtstr(p, 40);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n\t\t\t\t\t ");
+ prtstr(p, 38);
+ }
+ if (Verbose && statmsg[0] != '\0')
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "\n\t\t (%.100s)",
+ statmsg);
+ statmsg[0] = '\0';
}
break;
@@ -2691,13 +4840,65 @@ print_single_queue(queuedir)
}
}
if (submittime == (time_t) 0)
- printf(" (no control file)");
- printf("\n");
- (void) fclose(f);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " (no control file)");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
+ (void) sm_io_close(f, SM_TIME_DEFAULT);
}
return nrequests;
}
- /*
+
+#if _FFR_QUARANTINE
+/*
+** QUEUE_LETTER -- get the proper queue letter for the current QueueMode.
+**
+** Parameters:
+** e -- envelope to build it in/from.
+** type -- the file type, used as the first character
+** of the file name.
+**
+** Returns:
+** the letter to use
+*/
+
+static char
+queue_letter(e, type)
+ ENVELOPE *e;
+ int type;
+{
+ /* Change type according to QueueMode */
+ if (type == ANYQFL_LETTER)
+ {
+ if (e->e_quarmsg != NULL)
+ type = QUARQF_LETTER;
+ else
+ {
+ switch (QueueMode)
+ {
+ case QM_NORMAL:
+ type = NORMQF_LETTER;
+ break;
+
+ case QM_QUARANTINE:
+ type = QUARQF_LETTER;
+ break;
+
+ case QM_LOST:
+ type = LOSEQF_LETTER;
+ break;
+
+ default:
+ /* should never happen */
+ abort();
+ /* NOTREACHED */
+ }
+ }
+ }
+ return type;
+}
+#endif /* _FFR_QUARANTINE */
+
+/*
** QUEUENAME -- build a file name in the queue directory for this envelope.
**
** Parameters:
@@ -2719,60 +4920,121 @@ queuename(e, type)
register ENVELOPE *e;
int type;
{
- char *sub = "";
+ int qd, qg;
+ char *sub = "/";
+ char pref[3];
static char buf[MAXPATHLEN];
/* Assign an ID if needed */
if (e->e_id == NULL)
assign_queueid(e);
- /* Assign a queue directory if needed */
- if (e->e_queuedir == NOQDIR)
- setnewqueue(e);
+#if _FFR_QUARANTINE
+ type = queue_letter(e, type);
+#endif /* _FFR_QUARANTINE */
+
+ /* begin of filename */
+ pref[0] = (char) type;
+ pref[1] = 'f';
+ pref[2] = '\0';
+
+ /* Assign a queue group/directory if needed */
+ if (type == XSCRPT_LETTER)
+ {
+ /*
+ ** We don't want to call setnewqueue() if we are fetching
+ ** the pathname of the transcript file, because setnewqueue
+ ** chooses a queue, and sometimes we need to write to the
+ ** transcript file before we have gathered enough information
+ ** to choose a queue.
+ */
+
+ if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
+ {
+ if (e->e_qgrp != NOQGRP && e->e_qdir != NOQDIR)
+ {
+ e->e_xfqgrp = e->e_qgrp;
+ e->e_xfqdir = e->e_qdir;
+ }
+ else
+ {
+ e->e_xfqgrp = 0;
+ if (Queue[e->e_xfqgrp]->qg_numqueues <= 1)
+ e->e_xfqdir = 0;
+ else
+ {
+ e->e_xfqdir = get_rand_mod(
+ Queue[e->e_xfqgrp]->qg_numqueues);
+ }
+ }
+ }
+ qd = e->e_xfqdir;
+ qg = e->e_xfqgrp;
+ }
+ else
+ {
+ if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
+ setnewqueue(e);
+ if (type == DATAFL_LETTER)
+ {
+ qd = e->e_dfqdir;
+ qg = e->e_dfqgrp;
+ }
+ else
+ {
+ qd = e->e_qdir;
+ qg = e->e_qgrp;
+ }
+ }
- if (e->e_queuedir == NOQDIR)
- (void) snprintf(buf, sizeof buf, "%cf%s",
- type, e->e_id);
+ if (e->e_qdir == NOQDIR)
+ (void) sm_strlcpyn(buf, sizeof buf, 2, pref, e->e_id);
else
{
switch (type)
{
- case 'd':
- if (bitset(QP_SUBDF, QPaths[e->e_queuedir].qp_subdirs))
- sub = "/df";
+ case DATAFL_LETTER:
+ if (bitset(QP_SUBDF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
+ sub = "/df/";
break;
+#if _FFR_QUARANTINE
+ case QUARQF_LETTER:
+#endif /* _FFR_QUARANTINE */
case TEMPQF_LETTER:
- case 't':
+ case NEWQFL_LETTER:
case LOSEQF_LETTER:
- case 'q':
- if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs))
- sub = "/qf";
+ case NORMQF_LETTER:
+ if (bitset(QP_SUBQF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
+ sub = "/qf/";
break;
- case 'x':
- if (bitset(QP_SUBXF, QPaths[e->e_queuedir].qp_subdirs))
- sub = "/xf";
+ case XSCRPT_LETTER:
+ if (bitset(QP_SUBXF, Queue[qg]->qg_qpaths[qd].qp_subdirs))
+ sub = "/xf/";
break;
+
+ default:
+ sm_abort("queuename: bad queue file type %d", type);
}
- (void) snprintf(buf, sizeof buf, "%s%s/%cf%s",
- QPaths[e->e_queuedir].qp_name,
- sub, type, e->e_id);
+ (void) sm_strlcpyn(buf, sizeof buf, 4,
+ Queue[qg]->qg_qpaths[qd].qp_name,
+ sub, pref, e->e_id);
}
if (tTd(7, 2))
- dprintf("queuename: %s\n", buf);
+ sm_dprintf("queuename: %s\n", buf);
return buf;
}
- /*
+/*
** ASSIGN_QUEUEID -- assign a queue ID for this envelope.
**
** Assigns an id code if one does not already exist.
** This code assumes that nothing will remain in the queue for
** longer than 60 years. It is critical that files with the given
-** name not already exist in the queue.
-** Also initializes e_queuedir to NOQDIR.
+** name do not already exist in the queue.
+** [No longer initializes e_qdir to NOQDIR.]
**
** Parameters:
** e -- envelope to set it in.
@@ -2783,22 +5045,26 @@ queuename(e, type)
static const char QueueIdChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
# define QIC_LEN 60
+# define queuenextid() CurrentPid
+
void
assign_queueid(e)
register ENVELOPE *e;
{
- pid_t pid = getpid();
- static char cX = 0;
+ pid_t pid = queuenextid();
+ static int cX = 0;
static long random_offset;
struct tm *tm;
char idbuf[MAXQFNAME - 2];
+ int seq;
if (e->e_id != NULL)
return;
/* see if we need to get a new base time/pid */
- if (cX >= QIC_LEN || LastQueueTime == 0 || LastQueuePid != pid)
+ if (cX >= QIC_LEN * QIC_LEN || LastQueueTime == 0 ||
+ LastQueuePid != pid)
{
time_t then = LastQueueTime;
@@ -2811,12 +5077,22 @@ assign_queueid(e)
{
(void) sleep(1);
}
- LastQueuePid = getpid();
+ LastQueuePid = queuenextid();
cX = 0;
}
+
+ /*
+ ** Generate a new sequence number between 0 and QIC_LEN*QIC_LEN-1.
+ ** This lets us generate up to QIC_LEN*QIC_LEN unique queue ids
+ ** per second, per process. With envelope splitting,
+ ** a single message can consume many queue ids.
+ */
+
+ seq = (int)((cX + random_offset) % (QIC_LEN * QIC_LEN));
+ ++cX;
if (tTd(7, 50))
- dprintf("assign_queueid: random_offset = %ld (%d)\n",
- random_offset, (int)(cX + random_offset) % QIC_LEN);
+ sm_dprintf("assign_queueid: random_offset = %ld (%d)\n",
+ random_offset, seq);
tm = gmtime(&LastQueueTime);
idbuf[0] = QueueIdChars[tm->tm_year % QIC_LEN];
@@ -2825,19 +5101,29 @@ assign_queueid(e)
idbuf[3] = QueueIdChars[tm->tm_hour];
idbuf[4] = QueueIdChars[tm->tm_min];
idbuf[5] = QueueIdChars[tm->tm_sec];
- idbuf[6] = QueueIdChars[((int)cX++ + random_offset) % QIC_LEN];
- (void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d",
- (int) LastQueuePid);
- e->e_id = newstr(idbuf);
- define('i', e->e_id, e);
- e->e_queuedir = NOQDIR;
+ idbuf[6] = QueueIdChars[seq / QIC_LEN];
+ idbuf[7] = QueueIdChars[seq % QIC_LEN];
+ (void) sm_snprintf(&idbuf[8], sizeof idbuf - 8, "%06d",
+ (int) LastQueuePid);
+ e->e_id = sm_rpool_strdup_x(e->e_rpool, idbuf);
+ macdefine(&e->e_macro, A_PERM, 'i', e->e_id);
+#if 0
+ /* XXX: inherited from MainEnvelope */
+ e->e_qgrp = NOQGRP; /* too early to do anything else */
+ e->e_qdir = NOQDIR;
+ e->e_xfqgrp = NOQGRP;
+#endif /* 0 */
+#if _FFR_QUARANTINE
+ /* New ID means it's not on disk yet */
+ e->e_qfletter = '\0';
+#endif /* _FFR_QUARANTINE */
if (tTd(7, 1))
- dprintf("assign_queueid: assigned id %s, e=%lx\n",
- e->e_id, (u_long) e);
+ sm_dprintf("assign_queueid: assigned id %s, e=%p\n",
+ e->e_id, e);
if (LogLevel > 93)
sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
}
- /*
+/*
** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
**
** Make sure one PID can't be used by two processes in any one second.
@@ -2852,19 +5138,20 @@ assign_queueid(e)
** Returns:
** none
*/
+
void
sync_queue_time()
{
-# if FAST_PID_RECYCLE
+#if FAST_PID_RECYCLE
if (OpMode != MD_TEST &&
OpMode != MD_VERIFY &&
LastQueueTime > 0 &&
- LastQueuePid == getpid() &&
+ LastQueuePid == CurrentPid &&
curtime() == LastQueueTime)
(void) sleep(1);
-# endif /* FAST_PID_RECYCLE */
+#endif /* FAST_PID_RECYCLE */
}
- /*
+/*
** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
**
** Parameters:
@@ -2882,13 +5169,13 @@ unlockqueue(e)
ENVELOPE *e;
{
if (tTd(51, 4))
- dprintf("unlockqueue(%s)\n",
+ sm_dprintf("unlockqueue(%s)\n",
e->e_id == NULL ? "NOQUEUE" : e->e_id);
/* if there is a lock file in the envelope, close it */
if (e->e_lockfp != NULL)
- (void) fclose(e->e_lockfp);
+ (void) sm_io_close(e->e_lockfp, SM_TIME_DEFAULT);
e->e_lockfp = NULL;
/* don't create a queue id if we don't already have one */
@@ -2899,10 +5186,9 @@ unlockqueue(e)
if (LogLevel > 87)
sm_syslog(LOG_DEBUG, e->e_id, "unlock");
if (!tTd(51, 104))
- xunlink(queuename(e, 'x'));
-
+ (void) xunlink(queuename(e, XSCRPT_LETTER));
}
- /*
+/*
** SETCTLUSER -- create a controlling address
**
** Create a fake "address" given only a local login name; this is
@@ -2910,19 +5196,20 @@ unlockqueue(e)
**
** Parameters:
** user -- the user name of the controlling user.
-** qfver -- the version stamp of this qf file.
+** qfver -- the version stamp of this queue file.
+** e -- envelope
**
** Returns:
-** An address descriptor for the controlling user.
+** An address descriptor for the controlling user,
+** using storage allocated from e->e_rpool.
**
-** Side Effects:
-** none.
*/
static ADDRESS *
-setctluser(user, qfver)
+setctluser(user, qfver, e)
char *user;
int qfver;
+ ENVELOPE *e;
{
register ADDRESS *a;
struct passwd *pw;
@@ -2939,23 +5226,18 @@ setctluser(user, qfver)
** Set up addr fields for controlling user.
*/
- a = (ADDRESS *) xalloc(sizeof *a);
+ a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
memset((char *) a, '\0', sizeof *a);
- if (*user == '\0')
- {
- p = NULL;
- a->q_user = newstr(DefUser);
- }
- else if (*user == ':')
+ if (*user == ':')
{
p = &user[1];
- a->q_user = newstr(p);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, p);
}
else
{
p = strtok(user, ":");
- a->q_user = newstr(user);
+ a->q_user = sm_rpool_strdup_x(e->e_rpool, user);
if (qfver >= 2)
{
if ((p = strtok(NULL, ":")) != NULL)
@@ -2980,7 +5262,7 @@ setctluser(user, qfver)
else if (strcmp(pw->pw_dir, "/") == 0)
a->q_home = "";
else
- a->q_home = newstr(pw->pw_dir);
+ a->q_home = sm_rpool_strdup_x(e->e_rpool, pw->pw_dir);
a->q_uid = pw->pw_uid;
a->q_gid = pw->pw_gid;
a->q_flags |= QGOODUID;
@@ -2990,13 +5272,13 @@ setctluser(user, qfver)
a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
a->q_mailer = LocalMailer;
if (p == NULL)
- a->q_paddr = newstr(a->q_user);
+ a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
else
- a->q_paddr = newstr(p);
+ a->q_paddr = sm_rpool_strdup_x(e->e_rpool, p);
return a;
}
- /*
-** LOSEQFILE -- save the qf as Qf and try to let someone know
+/*
+** LOSEQFILE -- rename queue file with LOSEQF_LETTER & try to let someone know
**
** Parameters:
** e -- the envelope (e->e_id will be used).
@@ -3011,23 +5293,63 @@ loseqfile(e, why)
register ENVELOPE *e;
char *why;
{
+ bool loseit = true;
char *p;
char buf[MAXPATHLEN];
if (e == NULL || e->e_id == NULL)
return;
- p = queuename(e, 'q');
- if (strlen(p) >= (SIZE_T) sizeof buf)
+ p = queuename(e, ANYQFL_LETTER);
+ if (sm_strlcpy(buf, p, sizeof buf) >= sizeof buf)
return;
- (void) strlcpy(buf, p, sizeof buf);
- p = queuename(e, LOSEQF_LETTER);
- if (rename(buf, p) < 0)
- syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
- else if (LogLevel > 0)
- sm_syslog(LOG_ALERT, e->e_id,
- "Losing %s: %s", buf, why);
+ if (!bitset(EF_INQUEUE, e->e_flags))
+ queueup(e, false, true);
+#if _FFR_QUARANTINE
+ else if (QueueMode == QM_LOST)
+ loseit = false;
+#endif /* _FFR_QUARANTINE */
+
+ /* if already lost, no need to re-lose */
+ if (loseit)
+ {
+ p = queuename(e, LOSEQF_LETTER);
+ if (rename(buf, p) < 0)
+ syserr("cannot rename(%s, %s), uid=%d",
+ buf, p, geteuid());
+ else if (LogLevel > 0)
+ sm_syslog(LOG_ALERT, e->e_id,
+ "Losing %s: %s", buf, why);
+ }
+ if (e->e_dfp != NULL)
+ {
+ (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
+ e->e_dfp = NULL;
+ }
+ e->e_flags &= ~EF_HAS_DF;
+}
+/*
+** NAME2QID -- translate a queue group name to a queue group id
+**
+** Parameters:
+** queuename -- name of queue group.
+**
+** Returns:
+** queue group id if found.
+** NOQGRP otherwise.
+*/
+
+int
+name2qid(queuename)
+ char *queuename;
+{
+ register STAB *s;
+
+ s = stab(queuename, ST_QUEUE, ST_FIND);
+ if (s == NULL)
+ return NOQGRP;
+ return s->s_quegrp->qg_index;
}
- /*
+/*
** QID_PRINTNAME -- create externally printable version of queue id
**
** Parameters:
@@ -3052,100 +5374,225 @@ qid_printname(e)
else
id = e->e_id;
- if (e->e_queuedir == NOQDIR)
+ if (e->e_qdir == NOQDIR)
return id;
- (void) snprintf(idbuf, sizeof idbuf, "%.32s/%s",
- QPaths[e->e_queuedir].qp_name, id);
+ (void) sm_snprintf(idbuf, sizeof idbuf, "%.32s/%s",
+ Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_name,
+ id);
return idbuf;
}
- /*
-** QID_PRINTQUEUE -- create full version of queue directory for df files
+/*
+** QID_PRINTQUEUE -- create full version of queue directory for data files
**
** Parameters:
-** queuedir -- the short version of the queue directory
+** qgrp -- index in queue group.
+** qdir -- the short version of the queue directory
**
** Returns:
-** the full pathname to the queue (static)
+** the full pathname to the queue (might point to a static var)
*/
char *
-qid_printqueue(queuedir)
- int queuedir;
+qid_printqueue(qgrp, qdir)
+ int qgrp;
+ int qdir;
{
char *subdir;
static char dir[MAXPATHLEN];
- if (queuedir == NOQDIR)
- return QueueDir;
+ if (qdir == NOQDIR)
+ return Queue[qgrp]->qg_qdir;
- if (strcmp(QPaths[queuedir].qp_name, ".") == 0)
+ if (strcmp(Queue[qgrp]->qg_qpaths[qdir].qp_name, ".") == 0)
subdir = NULL;
else
- subdir = QPaths[queuedir].qp_name;
+ subdir = Queue[qgrp]->qg_qpaths[qdir].qp_name;
- (void) snprintf(dir, sizeof dir, "%s%s%s%s", QueueDir,
+ (void) sm_strlcpyn(dir, sizeof dir, 4,
+ Queue[qgrp]->qg_qdir,
subdir == NULL ? "" : "/",
subdir == NULL ? "" : subdir,
- (bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
+ (bitset(QP_SUBDF,
+ Queue[qgrp]->qg_qpaths[qdir].qp_subdirs)
+ ? "/df" : ""));
return dir;
}
- /*
-** SETNEWQUEUE -- Sets a new queue directory
+
+/*
+** PICKQDIR -- Pick a queue directory from a queue group
+**
+** Parameters:
+** qg -- queue group
+** fsize -- file size in bytes
+** e -- envelope, or NULL
**
-** Assign a queue directory to an envelope and store the directory
-** in e->e_queuedir. The queue is chosen at random.
+** Result:
+** NOQDIR if no queue directory in qg has enough free space to
+** hold a file of size 'fsize', otherwise the index of
+** a randomly selected queue directory which resides on a
+** file system with enough disk space.
+** XXX This could be extended to select a queuedir with
+** a few (the fewest?) number of entries. That data
+** is available if shared memory is used.
+**
+** Side Effects:
+** If the request fails and e != NULL then sm_syslog is called.
+*/
+
+int
+pickqdir(qg, fsize, e)
+ QUEUEGRP *qg;
+ long fsize;
+ ENVELOPE *e;
+{
+ int qdir;
+ int i;
+ long avail = 0;
+
+ /* Pick a random directory, as a starting point. */
+ if (qg->qg_numqueues <= 1)
+ qdir = 0;
+ else
+ qdir = get_rand_mod(qg->qg_numqueues);
+
+ if (MinBlocksFree <= 0 && fsize <= 0)
+ return qdir;
+
+ /*
+ ** Now iterate over the queue directories,
+ ** looking for a directory with enough space for this message.
+ */
+
+ i = qdir;
+ do
+ {
+ QPATHS *qp = &qg->qg_qpaths[i];
+ long needed = 0;
+ long fsavail = 0;
+
+ if (fsize > 0)
+ needed += fsize / FILE_SYS_BLKSIZE(qp->qp_fsysidx)
+ + ((fsize % FILE_SYS_BLKSIZE(qp->qp_fsysidx)
+ > 0) ? 1 : 0);
+ if (MinBlocksFree > 0)
+ needed += MinBlocksFree;
+ fsavail = FILE_SYS_AVAIL(qp->qp_fsysidx);
+#if SM_CONF_SHM
+ if (fsavail <= 0)
+ {
+ long blksize;
+
+ /*
+ ** might be not correctly updated,
+ ** let's try to get the info directly.
+ */
+
+ fsavail = freediskspace(FILE_SYS_NAME(qp->qp_fsysidx),
+ &blksize);
+ if (fsavail < 0)
+ fsavail = 0;
+ }
+#endif /* SM_CONF_SHM */
+ if (needed <= fsavail)
+ return i;
+ if (avail < fsavail)
+ avail = fsavail;
+
+ if (qg->qg_numqueues > 0)
+ i = (i + 1) % qg->qg_numqueues;
+ } while (i != qdir);
+
+ if (e != NULL && LogLevel > 0)
+ sm_syslog(LOG_ALERT, e->e_id,
+ "low on space (%s needs %ld bytes + %ld blocks in %s), max avail: %ld",
+ CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
+ fsize, MinBlocksFree,
+ qg->qg_qdir, avail);
+ return NOQDIR;
+}
+/*
+** SETNEWQUEUE -- Sets a new queue group and directory
**
-** This routine may be improved in the future to allow for more
-** elaborate queueing schemes. Suggestions and code contributions
-** are welcome.
+** Assign a queue group and directory to an envelope and store the
+** directory in e->e_qdir.
**
** Parameters:
** e -- envelope to assign a queue for.
**
** Returns:
-** none.
+** true if successful
+** false otherwise
+**
+** Side Effects:
+** On success, e->e_qgrp and e->e_qdir are non-negative.
+** On failure (not enough disk space),
+** e->qgrp = NOQGRP, e->e_qdir = NOQDIR
+** and usrerr() is invoked (which could raise an exception).
*/
-void
+bool
setnewqueue(e)
ENVELOPE *e;
{
- int idx;
-
if (tTd(41, 20))
- dprintf("setnewqueue: called\n");
+ sm_dprintf("setnewqueue: called\n");
+
+ /* not set somewhere else */
+ if (e->e_qgrp == NOQGRP)
+ {
+ /*
+ ** Use the queue group of the first recipient, as set by
+ ** the "queuegroup" rule set. If that is not defined, then
+ ** use the queue group of the mailer of the first recipient.
+ ** If that is not defined either, then use the default
+ ** queue group.
+ */
+
+ if (e->e_sendqueue == NULL)
+ e->e_qgrp = 0;
+ else if (e->e_sendqueue->q_qgrp >= 0)
+ e->e_qgrp = e->e_sendqueue->q_qgrp;
+ else if (e->e_sendqueue->q_mailer != NULL &&
+ ISVALIDQGRP(e->e_sendqueue->q_mailer->m_qgrp))
+ e->e_qgrp = e->e_sendqueue->q_mailer->m_qgrp;
+ else
+ e->e_qgrp = 0;
+ e->e_dfqgrp = e->e_qgrp;
+ }
- if (e->e_queuedir != NOQDIR)
+ if (ISVALIDQDIR(e->e_qdir) && ISVALIDQDIR(e->e_dfqdir))
{
if (tTd(41, 20))
- dprintf("setnewqueue: e_queuedir already assigned (%s)\n",
- qid_printqueue(e->e_queuedir));
- return;
+ sm_dprintf("setnewqueue: e_qdir already assigned (%s)\n",
+ qid_printqueue(e->e_qgrp, e->e_qdir));
+ return true;
}
- if (NumQueues <= 1)
- idx = 0;
- else
+ filesys_update();
+ e->e_qdir = pickqdir(Queue[e->e_qgrp], e->e_msgsize, e);
+ if (e->e_qdir == NOQDIR)
{
-#if RANDOMSHIFT
- /* lower bits are not random "enough", select others */
- idx = (get_random() >> RANDOMSHIFT) % NumQueues;
-#else /* RANDOMSHIFT */
- idx = get_random() % NumQueues;
-#endif /* RANDOMSHIFT */
- if (tTd(41, 15))
- dprintf("setnewqueue: get_random() %% %d = %d\n",
- NumQueues, idx);
+ e->e_qgrp = NOQGRP;
+ if (!bitset(EF_FATALERRS, e->e_flags))
+ usrerr("452 4.4.5 Insufficient disk space; try again later");
+ e->e_flags |= EF_FATALERRS;
+ return false;
}
- e->e_queuedir = idx;
if (tTd(41, 3))
- dprintf("setnewqueue: Assigned queue directory %s\n",
- qid_printqueue(e->e_queuedir));
-}
+ sm_dprintf("setnewqueue: Assigned queue directory %s\n",
+ qid_printqueue(e->e_qgrp, e->e_qdir));
- /*
+ if (e->e_xfqgrp == NOQGRP || e->e_xfqdir == NOQDIR)
+ {
+ e->e_xfqgrp = e->e_qgrp;
+ e->e_xfqdir = e->e_qdir;
+ }
+ e->e_dfqdir = e->e_qdir;
+ return true;
+}
+/*
** CHKQDIR -- check a queue directory
**
** Parameters:
@@ -3167,52 +5614,53 @@ chkqdir(name, sff)
/* skip over . and .. directories */
if (name[0] == '.' &&
(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
- return FALSE;
-# if HASLSTAT
+ return false;
+#if HASLSTAT
if (lstat(name, &statb) < 0)
-# else /* HASLSTAT */
+#else /* HASLSTAT */
if (stat(name, &statb) < 0)
-# endif /* HASLSTAT */
+#endif /* HASLSTAT */
{
if (tTd(41, 2))
- dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
- name, errstring(errno));
- return FALSE;
+ sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
+ name, sm_errstring(errno));
+ return false;
}
-# if HASLSTAT
+#if HASLSTAT
if (S_ISLNK(statb.st_mode))
{
/*
** For a symlink we need to make sure the
** target is a directory
*/
+
if (stat(name, &statb) < 0)
{
if (tTd(41, 2))
- dprintf("multiqueue_cache: stat(\"%s\"): %s\n",
- name, errstring(errno));
- return FALSE;
+ sm_dprintf("chkqdir: stat(\"%s\"): %s\n",
+ name, sm_errstring(errno));
+ return false;
}
}
-# endif /* HASLSTAT */
+#endif /* HASLSTAT */
if (!S_ISDIR(statb.st_mode))
{
if (tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": Not a directory\n",
+ sm_dprintf("chkqdir: \"%s\": Not a directory\n",
name);
- return FALSE;
+ return false;
}
/* Print a warning if unsafe (but still use it) */
+ /* XXX do this only if we want the warning? */
i = safedirpath(name, RunAsUid, RunAsGid, NULL, sff, 0, 0);
if (i != 0 && tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
- name, errstring(i));
- return TRUE;
+ sm_dprintf("chkqdir: \"%s\": Not safe: %s\n",
+ name, sm_errstring(i));
+ return true;
}
-
- /*
+/*
** MULTIQUEUE_CACHE -- cache a list of paths to queues.
**
** Each potential queue is checked as the cache is built.
@@ -3221,206 +5669,1234 @@ chkqdir(name, sff)
** (although code for that is not ready yet).
**
** Parameters:
-** none
+** basedir -- base of all queue directories.
+** blen -- strlen(basedir).
+** qg -- queue group.
+** qn -- number of queue directories already cached.
+** phash -- pointer to hash value over queue dirs.
+#if SM_CONF_SHM
+** only used if shared memory is active.
+#endif * SM_CONF_SHM *
**
** Returns:
-** none
+** new number of queue directories.
*/
-void
-multiqueue_cache()
+#define INITIAL_SLOTS 20
+#define ADD_SLOTS 10
+
+static int
+multiqueue_cache(basedir, blen, qg, qn, phash)
+ char *basedir;
+ int blen;
+ QUEUEGRP *qg;
+ int qn;
+ unsigned int *phash;
{
- register DIR *dp;
- register struct dirent *d;
char *cp;
int i, len;
int slotsleft = 0;
long sff = SFF_ANYFILE;
char qpath[MAXPATHLEN];
char subdir[MAXPATHLEN];
+ char prefix[MAXPATHLEN]; /* dir relative to basedir */
if (tTd(41, 20))
- dprintf("multiqueue_cache: called\n");
+ sm_dprintf("multiqueue_cache: called\n");
- if (NumQueues != 0 && QPaths != NULL)
+ /* Initialize to current directory */
+ prefix[0] = '.';
+ prefix[1] = '\0';
+ if (qg->qg_numqueues != 0 && qg->qg_qpaths != NULL)
{
- for (i = 0; i < NumQueues; i++)
+ for (i = 0; i < qg->qg_numqueues; i++)
{
- if (QPaths[i].qp_name != NULL)
- sm_free(QPaths[i].qp_name);
+ if (qg->qg_qpaths[i].qp_name != NULL)
+ (void) sm_free(qg->qg_qpaths[i].qp_name); /* XXX */
}
- sm_free((char *)QPaths);
- QPaths = NULL;
- NumQueues = 0;
+ (void) sm_free((char *) qg->qg_qpaths); /* XXX */
+ qg->qg_qpaths = NULL;
+ qg->qg_numqueues = 0;
}
/* If running as root, allow safedirpath() checks to use privs */
if (RunAsUid == 0)
sff |= SFF_ROOTOK;
- (void) snprintf(qpath, sizeof qpath, "%s", QueueDir);
- len = strlen(qpath) - 1;
- cp = &qpath[len];
+ if (!SM_IS_DIR_START(qg->qg_qdir))
+ {
+ /*
+ ** XXX we could add basedir, but then we have to realloc()
+ ** the string... Maybe another time.
+ */
+
+ syserr("QueuePath %s not absolute", qg->qg_qdir);
+ ExitStat = EX_CONFIG;
+ return qn;
+ }
+
+ /* qpath: directory of current workgroup */
+ len = sm_strlcpy(qpath, qg->qg_qdir, sizeof qpath);
+ if (len >= sizeof qpath)
+ {
+ syserr("QueuePath %.256s too long (%d max)",
+ qg->qg_qdir, (int) sizeof qpath);
+ ExitStat = EX_CONFIG;
+ return qn;
+ }
+
+ /* begin of qpath must be same as basedir */
+ if (strncmp(basedir, qpath, blen) != 0 &&
+ (strncmp(basedir, qpath, blen - 1) != 0 || len != blen - 1))
+ {
+ syserr("QueuePath %s not subpath of QueueDirectory %s",
+ qpath, basedir);
+ ExitStat = EX_CONFIG;
+ return qn;
+ }
+
+ /* Do we have a nested subdirectory? */
+ if (blen < len && SM_FIRST_DIR_DELIM(qg->qg_qdir + blen) != NULL)
+ {
+
+ /* Copy subdirectory into prefix for later use */
+ if (sm_strlcpy(prefix, qg->qg_qdir + blen, sizeof prefix) >=
+ sizeof prefix)
+ {
+ syserr("QueuePath %.256s too long (%d max)",
+ qg->qg_qdir, (int) sizeof qpath);
+ ExitStat = EX_CONFIG;
+ return qn;
+ }
+ cp = SM_LAST_DIR_DELIM(prefix);
+ SM_ASSERT(cp != NULL);
+ *cp = '\0'; /* cut off trailing / */
+ }
+
+ /* This is guaranteed by the basedir check above */
+ SM_ASSERT(len >= blen - 1);
+ cp = &qpath[len - 1];
if (*cp == '*')
{
- *cp = '\0';
- if ((cp = strrchr(qpath, '/')) == NULL)
+ register DIR *dp;
+ register struct dirent *d;
+ int off;
+ char *delim;
+ char relpath[MAXPATHLEN];
+
+ *cp = '\0'; /* Overwrite wildcard */
+ if ((cp = SM_LAST_DIR_DELIM(qpath)) == NULL)
{
syserr("QueueDirectory: can not wildcard relative path");
if (tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": Can not wildcard relative path.\n",
+ sm_dprintf("multiqueue_cache: \"%s*\": Can not wildcard relative path.\n",
qpath);
ExitStat = EX_CONFIG;
- return;
+ return qn;
}
if (cp == qpath)
{
/*
** Special case of top level wildcard, like /foo*
+ ** Change to //foo*
*/
- (void) snprintf(qpath + 1, sizeof qpath - 1,
- "%s", qpath);
+ (void) sm_strlcpy(qpath + 1, qpath, sizeof qpath - 1);
++cp;
}
- *(cp++) = '\0';
- len = strlen(cp);
+ delim = cp;
+ *(cp++) = '\0'; /* Replace / with \0 */
+ len = strlen(cp); /* Last component of queue directory */
+
+ /*
+ ** Path relative to basedir, with trailing /
+ ** It will be modified below to specify the subdirectories
+ ** so they can be opened without chdir().
+ */
+
+ off = sm_strlcpyn(relpath, sizeof relpath, 2, prefix, "/");
+ SM_ASSERT(off < sizeof relpath);
if (tTd(41, 2))
- dprintf("multiqueue_cache: prefix=\"%s\"\n", cp);
+ sm_dprintf("multiqueue_cache: prefix=\"%s%s\"\n",
+ relpath, cp);
- QueueDir = newstr(qpath);
+ /* It is always basedir: we don't need to store it per group */
+ /* XXX: optimize this! -> one more global? */
+ qg->qg_qdir = newstr(basedir);
+ qg->qg_qdir[blen - 1] = '\0'; /* cut off trailing / */
/*
** XXX Should probably wrap this whole loop in a timeout
** in case some wag decides to NFS mount the queues.
*/
- /* test path to get warning messages */
- i= safedirpath(QueueDir, RunAsUid, RunAsGid, NULL, sff, 0, 0);
- if (i != 0 && tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
- QueueDir, errstring(i));
-
- if (chdir(QueueDir) < 0)
+ /* Test path to get warning messages. */
+ if (qn == 0)
{
- syserr("can not chdir(%s)", QueueDir);
- if (tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": %s\n",
- qpath, errstring(errno));
- ExitStat = EX_CONFIG;
- return;
+ /* XXX qg_runasuid and qg_runasgid for specials? */
+ i = safedirpath(basedir, RunAsUid, RunAsGid, NULL,
+ sff, 0, 0);
+ if (i != 0 && tTd(41, 2))
+ sm_dprintf("multiqueue_cache: \"%s\": Not safe: %s\n",
+ basedir, sm_errstring(i));
}
- if ((dp = opendir(".")) == NULL)
+ if ((dp = opendir(prefix)) == NULL)
{
- syserr("can not opendir(%s)", QueueDir);
+ syserr("can not opendir(%s/%s)", qg->qg_qdir, prefix);
if (tTd(41, 2))
- dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
- QueueDir, errstring(errno));
+ sm_dprintf("multiqueue_cache: opendir(\"%s/%s\"): %s\n",
+ qg->qg_qdir, prefix,
+ sm_errstring(errno));
ExitStat = EX_CONFIG;
- return;
+ return qn;
}
while ((d = readdir(dp)) != NULL)
{
- if (strncmp(d->d_name, cp, len) != 0)
+ i = strlen(d->d_name);
+ if (i < len || strncmp(d->d_name, cp, len) != 0)
{
if (tTd(41, 5))
- dprintf("multiqueue_cache: \"%s\", skipped\n",
+ sm_dprintf("multiqueue_cache: \"%s\", skipped\n",
d->d_name);
continue;
}
- if (!chkqdir(d->d_name, sff))
+
+ /* Create relative pathname: prefix + local directory */
+ i = sizeof(relpath) - off;
+ if (sm_strlcpy(relpath + off, d->d_name, i) >= i)
+ continue; /* way too long */
+
+ if (!chkqdir(relpath, sff))
continue;
- if (QPaths == NULL)
+ if (qg->qg_qpaths == NULL)
{
- slotsleft = 20;
- QPaths = (QPATHS *)xalloc((sizeof *QPaths) *
- slotsleft);
- NumQueues = 0;
+ slotsleft = INITIAL_SLOTS;
+ qg->qg_qpaths = (QPATHS *)xalloc((sizeof *qg->qg_qpaths) *
+ slotsleft);
+ qg->qg_numqueues = 0;
}
else if (slotsleft < 1)
{
- QPaths = (QPATHS *)xrealloc((char *)QPaths,
- (sizeof *QPaths) *
- (NumQueues + 10));
- if (QPaths == NULL)
+ qg->qg_qpaths = (QPATHS *)sm_realloc((char *)qg->qg_qpaths,
+ (sizeof *qg->qg_qpaths) *
+ (qg->qg_numqueues +
+ ADD_SLOTS));
+ if (qg->qg_qpaths == NULL)
{
(void) closedir(dp);
- return;
+ return qn;
}
- slotsleft += 10;
+ slotsleft += ADD_SLOTS;
}
/* check subdirs */
- QPaths[NumQueues].qp_subdirs = QP_NOSUB;
- (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
- qpath, d->d_name, "qf");
- if (chkqdir(subdir, sff))
- QPaths[NumQueues].qp_subdirs |= QP_SUBQF;
-
- (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
- qpath, d->d_name, "df");
- if (chkqdir(subdir, sff))
- QPaths[NumQueues].qp_subdirs |= QP_SUBDF;
-
- (void) snprintf(subdir, sizeof subdir, "%s/%s/%s",
- qpath, d->d_name, "xf");
- if (chkqdir(subdir, sff))
- QPaths[NumQueues].qp_subdirs |= QP_SUBXF;
+ qg->qg_qpaths[qg->qg_numqueues].qp_subdirs = QP_NOSUB;
+
+#define CHKRSUBDIR(name, flag) \
+ (void) sm_strlcpyn(subdir, sizeof subdir, 3, relpath, "/", name); \
+ if (chkqdir(subdir, sff)) \
+ qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \
+ else
+
+
+ CHKRSUBDIR("qf", QP_SUBQF);
+ CHKRSUBDIR("df", QP_SUBDF);
+ CHKRSUBDIR("xf", QP_SUBXF);
/* assert(strlen(d->d_name) < MAXPATHLEN - 14) */
/* maybe even - 17 (subdirs) */
- QPaths[NumQueues].qp_name = newstr(d->d_name);
+
+ if (prefix[0] != '.')
+ qg->qg_qpaths[qg->qg_numqueues].qp_name =
+ newstr(relpath);
+ else
+ qg->qg_qpaths[qg->qg_numqueues].qp_name =
+ newstr(d->d_name);
+
if (tTd(41, 2))
- dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
- NumQueues, d->d_name,
- QPaths[NumQueues].qp_subdirs);
- NumQueues++;
+ sm_dprintf("multiqueue_cache: %d: \"%s\" cached (%x).\n",
+ qg->qg_numqueues, relpath,
+ qg->qg_qpaths[qg->qg_numqueues].qp_subdirs);
+#if SM_CONF_SHM
+ qg->qg_qpaths[qg->qg_numqueues].qp_idx = qn;
+ *phash = hash_q(relpath, *phash);
+#endif /* SM_CONF_SHM */
+ qg->qg_numqueues++;
+ ++qn;
slotsleft--;
}
(void) closedir(dp);
+
+ /* undo damage */
+ *delim = '/';
}
- if (NumQueues == 0)
+ if (qg->qg_numqueues == 0)
{
- if (*cp != '*' && tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": No wildcard suffix character\n",
- QueueDir);
- QPaths = (QPATHS *)xalloc(sizeof *QPaths);
- QPaths[0].qp_name = newstr(".");
- QPaths[0].qp_subdirs = QP_NOSUB;
- NumQueues = 1;
+ qg->qg_qpaths = (QPATHS *) xalloc(sizeof *qg->qg_qpaths);
/* test path to get warning messages */
- (void) safedirpath(QueueDir, RunAsUid, RunAsGid,
- NULL, sff, 0, 0);
- if (chdir(QueueDir) < 0)
+ i = safedirpath(qpath, RunAsUid, RunAsGid, NULL, sff, 0, 0);
+ if (i == ENOENT)
{
- syserr("can not chdir(%s)", QueueDir);
+ syserr("can not opendir(%s)", qpath);
if (tTd(41, 2))
- dprintf("multiqueue_cache: \"%s\": %s\n",
- QueueDir, errstring(errno));
+ sm_dprintf("multiqueue_cache: opendir(\"%s\"): %s\n",
+ qpath, sm_errstring(i));
ExitStat = EX_CONFIG;
+ return qn;
}
+ qg->qg_qpaths[0].qp_subdirs = QP_NOSUB;
+ qg->qg_numqueues = 1;
+
/* check subdirs */
- (void) snprintf(subdir, sizeof subdir, "%s/qf", QueueDir);
- if (chkqdir(subdir, sff))
- QPaths[0].qp_subdirs |= QP_SUBQF;
+#define CHKSUBDIR(name, flag) \
+ (void) sm_strlcpyn(subdir, sizeof subdir, 3, qg->qg_qdir, "/", name); \
+ if (chkqdir(subdir, sff)) \
+ qg->qg_qpaths[0].qp_subdirs |= flag; \
+ else
- (void) snprintf(subdir, sizeof subdir, "%s/df", QueueDir);
- if (chkqdir(subdir, sff))
- QPaths[0].qp_subdirs |= QP_SUBDF;
+ CHKSUBDIR("qf", QP_SUBQF);
+ CHKSUBDIR("df", QP_SUBDF);
+ CHKSUBDIR("xf", QP_SUBXF);
- (void) snprintf(subdir, sizeof subdir, "%s/xf", QueueDir);
- if (chkqdir(subdir, sff))
- QPaths[0].qp_subdirs |= QP_SUBXF;
+ if (qg->qg_qdir[blen - 1] != '\0' &&
+ qg->qg_qdir[blen] != '\0')
+ {
+ /*
+ ** Copy the last component into qpaths and
+ ** cut off qdir
+ */
+
+ qg->qg_qpaths[0].qp_name = newstr(qg->qg_qdir + blen);
+ qg->qg_qdir[blen - 1] = '\0';
+ }
+ else
+ qg->qg_qpaths[0].qp_name = newstr(".");
+
+#if SM_CONF_SHM
+ qg->qg_qpaths[0].qp_idx = qn;
+ *phash = hash_q(qg->qg_qpaths[0].qp_name, *phash);
+#endif /* SM_CONF_SHM */
+ ++qn;
+ }
+ return qn;
+}
+
+/*
+** FILESYS_FIND -- find entry in FileSys table, or add new one
+**
+** Given the pathname of a directory, determine the file system
+** in which that directory resides, and return a pointer to the
+** entry in the FileSys table that describes the file system.
+** A new entry is added if necessary (and requested).
+** If the directory does not exist, -1 is returned.
+**
+** Parameters:
+** path -- pathname of directory
+** add -- add to structure if not found.
+**
+** Returns:
+** >=0: found: index in file system table
+** <0: some error, i.e.,
+** FSF_TOO_MANY: too many filesystems (-> syserr())
+** FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
+** FSF_NOT_FOUND: not in list
+*/
+
+static short filesys_find __P((char *, bool));
+
+#define FSF_NOT_FOUND (-1)
+#define FSF_STAT_FAIL (-2)
+#define FSF_TOO_MANY (-3)
+
+static short
+filesys_find(path, add)
+ char *path;
+ bool add;
+{
+ struct stat st;
+ short i;
+
+ if (stat(path, &st) < 0)
+ {
+ syserr("cannot stat queue directory %s", path);
+ return FSF_STAT_FAIL;
+ }
+ for (i = 0; i < NumFileSys; ++i)
+ {
+ if (FILE_SYS_DEV(i) == st.st_dev)
+ return i;
+ }
+ if (i >= MAXFILESYS)
+ {
+ syserr("too many queue file systems (%d max)", MAXFILESYS);
+ return FSF_TOO_MANY;
}
+ if (!add)
+ return FSF_NOT_FOUND;
+
+ ++NumFileSys;
+ FILE_SYS_NAME(i) = path;
+ FILE_SYS_DEV(i) = st.st_dev;
+ FILE_SYS_AVAIL(i) = 0;
+ FILE_SYS_BLKSIZE(i) = 1024; /* avoid divide by zero */
+ return i;
}
-# if 0
- /*
+/*
+** FILESYS_SETUP -- set up mapping from queue directories to file systems
+**
+** This data structure is used to efficiently check the amount of
+** free space available in a set of queue directories.
+**
+** Parameters:
+** add -- initialize structure if necessary.
+**
+** Returns:
+** 0: success
+** <0: some error, i.e.,
+** FSF_NOT_FOUND: not in list
+** FSF_STAT_FAIL: can't stat() filesystem (-> syserr())
+** FSF_TOO_MANY: too many filesystems (-> syserr())
+*/
+
+static int filesys_setup __P((bool));
+
+static int
+filesys_setup(add)
+ bool add;
+{
+ int i, j;
+ short fs;
+ int ret;
+
+ ret = 0;
+ for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
+ {
+ for (j = 0; j < Queue[i]->qg_numqueues; ++j)
+ {
+ QPATHS *qp = &Queue[i]->qg_qpaths[j];
+
+ fs = filesys_find(qp->qp_name, add);
+ if (fs >= 0)
+ qp->qp_fsysidx = fs;
+ else
+ qp->qp_fsysidx = 0;
+ if (fs < ret)
+ ret = fs;
+ }
+ }
+ return ret;
+}
+
+/*
+** FILESYS_UPDATE -- update amount of free space on all file systems
+**
+** The FileSys table is used to cache the amount of free space
+** available on all queue directory file systems.
+** This function updates the cached information if it has expired.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Updates FileSys table.
+*/
+
+void
+filesys_update()
+{
+ int i;
+ long avail, blksize;
+ time_t now;
+ static time_t nextupdate = 0;
+
+#if SM_CONF_SHM
+ /* only the daemon updates this structure */
+ if (ShmId != SM_SHM_NO_ID && DaemonPid != CurrentPid)
+ return;
+#endif /* SM_CONF_SHM */
+ now = curtime();
+ if (now < nextupdate)
+ return;
+ nextupdate = now + FILESYS_UPDATE_INTERVAL;
+ for (i = 0; i < NumFileSys; ++i)
+ {
+ FILESYS *fs = &FILE_SYS(i);
+
+ avail = freediskspace(FILE_SYS_NAME(i), &blksize);
+ if (avail < 0 || blksize <= 0)
+ {
+ if (LogLevel > 5)
+ sm_syslog(LOG_ERR, NOQID,
+ "filesys_update failed: %s, fs=%s, avail=%ld, blocksize=%ld",
+ sm_errstring(errno),
+ FILE_SYS_NAME(i), avail, blksize);
+ fs->fs_avail = 0;
+ fs->fs_blksize = 1024; /* avoid divide by zero */
+ nextupdate = now + 2; /* let's do this soon again */
+ }
+ else
+ {
+ fs->fs_avail = avail;
+ fs->fs_blksize = blksize;
+ }
+ }
+}
+
+#if _FFR_ANY_FREE_FS
+/*
+** FILESYS_FREE -- check whether there is at least one fs with enough space.
+**
+** Parameters:
+** fsize -- file size in bytes
+**
+** Returns:
+** true iff there is one fs with more than fsize bytes free.
+*/
+
+bool
+filesys_free(fsize)
+ long fsize;
+{
+ int i;
+
+ if (fsize <= 0)
+ return true;
+ for (i = 0; i < NumFileSys; ++i)
+ {
+ long needed = 0;
+
+ if (FILE_SYS_AVAIL(i) < 0 || FILE_SYS_BLKSIZE(i) <= 0)
+ continue;
+ needed += fsize / FILE_SYS_BLKSIZE(i)
+ + ((fsize % FILE_SYS_BLKSIZE(i)
+ > 0) ? 1 : 0)
+ + MinBlocksFree;
+ if (needed <= FILE_SYS_AVAIL(i))
+ return true;
+ }
+ return false;
+}
+#endif /* _FFR_ANY_FREE_FS */
+
+#if _FFR_CONTROL_MSTAT
+/*
+** DISK_STATUS -- show amount of free space in queue directories
+**
+** Parameters:
+** out -- output file pointer.
+** prefix -- string to output in front of each line.
+**
+** Returns:
+** none.
+*/
+
+void
+disk_status(out, prefix)
+ SM_FILE_T *out;
+ char *prefix;
+{
+ int i;
+ long avail, blksize;
+ long free;
+
+ for (i = 0; i < NumFileSys; ++i)
+ {
+ avail = freediskspace(FILE_SYS_NAME(i), &blksize);
+ if (avail >= 0 && blksize > 0)
+ {
+ free = (long)((double) avail *
+ ((double) blksize / 1024));
+ }
+ else
+ free = -1;
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT,
+ "%s%d/%s/%ld\r\n",
+ prefix, i,
+ FILE_SYS_NAME(i),
+ free);
+ }
+}
+#endif /* _FFR_CONTROL_MSTAT */
+
+#if SM_CONF_SHM
+/*
+** UPD_QS -- update information about queue when adding/deleting an entry
+**
+** Parameters:
+** e -- envelope.
+** delete -- delete/add entry.
+** avail -- update the space available as well.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Modifies available space in filesystem.
+** Changes number of entries in queue directory.
+*/
+
+void
+upd_qs(e, delete, avail)
+ ENVELOPE *e;
+ bool delete;
+ bool avail;
+{
+ short fidx;
+ int idx;
+ long s;
+
+ if (ShmId == SM_SHM_NO_ID || e == NULL)
+ return;
+ if (e->e_qgrp == NOQGRP || e->e_qdir == NOQDIR)
+ return;
+ idx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_idx;
+
+ /* XXX in theory this needs to be protected with a mutex */
+ if (QSHM_ENTRIES(idx) >= 0)
+ {
+ if (delete)
+ --QSHM_ENTRIES(idx);
+ else
+ ++QSHM_ENTRIES(idx);
+ }
+
+ fidx = Queue[e->e_qgrp]->qg_qpaths[e->e_qdir].qp_fsysidx;
+ if (fidx < 0)
+ return;
+
+ /* update available space also? (might be loseqfile) */
+ if (!avail)
+ return;
+
+ /* convert size to blocks; this causes rounding errors */
+ s = e->e_msgsize / FILE_SYS_BLKSIZE(fidx);
+ if (s == 0)
+ return;
+
+ /* XXX in theory this needs to be protected with a mutex */
+ if (delete)
+ FILE_SYS_AVAIL(fidx) += s;
+ else
+ FILE_SYS_AVAIL(fidx) -= s;
+
+}
+/*
+** INIT_SHM -- initialize shared memory structure
+**
+** Initialize or attach to shared memory segment.
+** Currently it is not a fatal error if this doesn't work.
+** However, it causes us to have a "fallback" storage location
+** for everything that is supposed to be in the shared memory,
+** which makes the code slightly ugly.
+**
+** Parameters:
+** qn -- number of queue directories.
+** owner -- owner of shared memory.
+** hash -- identifies data that is stored in shared memory.
+**
+** Returns:
+** none.
+*/
+
+static void init_shm __P((int, bool, unsigned int));
+
+static void
+init_shm(qn, owner, hash)
+ int qn;
+ bool owner;
+ unsigned int hash;
+{
+ int i;
+
+ PtrFileSys = &FileSys[0];
+ PNumFileSys = &Numfilesys;
+
+ /* This allows us to disable shared memory at runtime. */
+ if (ShmKey != 0)
+ {
+ int count;
+ int save_errno;
+ size_t shms;
+
+ count = 0;
+ shms = SM_T_SIZE + qn * sizeof(QUEUE_SHM_T);
+ for (;;)
+ {
+ /* XXX: maybe allow read access for group? */
+ Pshm = sm_shmstart(ShmKey, shms, SHM_R|SHM_W, &ShmId,
+ owner);
+ save_errno = errno;
+ if (Pshm != NULL || save_errno != EEXIST)
+ break;
+ if (++count >= 3)
+ break;
+ sleep(count);
+ }
+ if (Pshm != NULL)
+ {
+ int *p;
+
+ p = (int *) Pshm;
+ if (owner)
+ {
+ *p = (int) shms;
+ *((pid_t *) SHM_OFF_PID(Pshm)) = CurrentPid;
+ p = (int *) SHM_OFF_TAG(Pshm);
+ *p = hash;
+ }
+ else
+ {
+ if (*p != (int) shms)
+ {
+ save_errno = EINVAL;
+ cleanup_shm(false);
+ goto error;
+ }
+ p = (int *) SHM_OFF_TAG(Pshm);
+ if (*p != (int) hash)
+ {
+ save_errno = EINVAL;
+ cleanup_shm(false);
+ goto error;
+ }
+
+ /*
+ ** XXX how to check the pid?
+ ** Read it from the pid-file? That does
+ ** not need to exist.
+ ** We could disable shm if we can't confirm
+ ** that it is the right one.
+ */
+ }
+
+ PtrFileSys = (FILESYS *) OFF_FILE_SYS(Pshm);
+ PNumFileSys = (int *) OFF_NUM_FILE_SYS(Pshm);
+ QShm = (QUEUE_SHM_T *) OFF_QUEUE_SHM(Pshm);
+ PRSATmpCnt = (int *) OFF_RSA_TMP_CNT(Pshm);
+ *PRSATmpCnt = 0;
+ if (owner)
+ {
+ /* initialize values in shared memory */
+ NumFileSys = 0;
+ for (i = 0; i < qn; i++)
+ QShm[i].qs_entries = -1;
+ }
+ return;
+ }
+ error:
+ if (LogLevel > (owner ? 8 : 11))
+ {
+ sm_syslog(owner ? LOG_ERR : LOG_NOTICE, NOQID,
+ "can't %s shared memory, key=%ld: %s",
+ owner ? "initialize" : "attach to",
+ (long) ShmKey, sm_errstring(save_errno));
+ }
+ }
+}
+#endif /* SM_CONF_SHM */
+
+/*
+** SETUP_QUEUES -- setup all queue groups
+**
+** Parameters:
+** owner -- owner of shared memory.
+**
+** Returns:
+** none.
+**
+#if SM_CONF_SHM
+** Side Effects:
+** attaches shared memory.
+#endif * SM_CONF_SHM *
+*/
+
+void
+setup_queues(owner)
+ bool owner;
+{
+ int i, qn, len;
+ unsigned int hashval;
+ char basedir[MAXPATHLEN];
+ struct stat st;
+
+ /*
+ ** Determine basedir for all queue directories.
+ ** All queue directories must be (first level) subdirectories
+ ** of the basedir. The basedir is the QueueDir
+ ** without wildcards, but with trailing /
+ */
+
+ hashval = 0;
+ errno = 0;
+ len = sm_strlcpy(basedir, QueueDir, sizeof basedir);
+ if (len >= sizeof basedir)
+ {
+ syserr("QueueDirectory: path too long: %d, max %d",
+ len, (int) sizeof basedir);
+ ExitStat = EX_CONFIG;
+ return;
+ }
+ SM_ASSERT(len > 0);
+ if (basedir[len - 1] == '*')
+ {
+ char *cp;
+
+ cp = SM_LAST_DIR_DELIM(basedir);
+ if (cp == NULL)
+ {
+ syserr("QueueDirectory: can not wildcard relative path \"%s\"",
+ QueueDir);
+ if (tTd(41, 2))
+ sm_dprintf("setup_queues: \"%s\": Can not wildcard relative path.\n",
+ QueueDir);
+ ExitStat = EX_CONFIG;
+ return;
+ }
+
+ /* cut off wildcard pattern */
+ *++cp = '\0';
+ len = cp - basedir;
+ }
+ else if (!SM_IS_DIR_DELIM(basedir[len - 1]))
+ {
+ /* append trailing slash since it is a directory */
+ basedir[len] = '/';
+ basedir[++len] = '\0';
+ }
+
+ /* len counts up to the last directory delimiter */
+ SM_ASSERT(basedir[len - 1] == '/');
+
+ if (chdir(basedir) < 0)
+ {
+ int save_errno = errno;
+
+ syserr("can not chdir(%s)", basedir);
+ if (save_errno == EACCES)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Program mode requires special privileges, e.g., root or TrustedUser.\n");
+ if (tTd(41, 2))
+ sm_dprintf("setup_queues: \"%s\": %s\n",
+ basedir, sm_errstring(errno));
+ ExitStat = EX_CONFIG;
+ return;
+ }
+#if SM_CONF_SHM
+ hashval = hash_q(basedir, hashval);
+#endif /* SM_CONF_SHM */
+
+ /* initialize map for queue runs */
+ clrbitmap(DoQueueRun);
+
+
+ if (UseMSP && OpMode != MD_TEST)
+ {
+ long sff = SFF_CREAT;
+
+ if (stat(".", &st) < 0)
+ {
+ syserr("can not stat(%s)", basedir);
+ if (tTd(41, 2))
+ sm_dprintf("setup_queues: \"%s\": %s\n",
+ basedir, sm_errstring(errno));
+ ExitStat = EX_CONFIG;
+ return;
+ }
+ if (RunAsUid == 0)
+ sff |= SFF_ROOTOK;
+
+ /*
+ ** Check queue directory permissions.
+ ** Can we write to a group writable queue directory?
+ */
+
+ if (bitset(S_IWGRP, QueueFileMode) &&
+ bitset(S_IWGRP, st.st_mode) &&
+ safefile(" ", RunAsUid, RunAsGid, RunAsUserName, sff,
+ QueueFileMode, NULL) != 0)
+ {
+ syserr("can not write to queue directory %s (RunAsGid=%d, required=%d)",
+ basedir, (int) RunAsGid, (int) st.st_gid);
+ }
+ if (bitset(S_IWOTH|S_IXOTH, st.st_mode))
+ {
+#if _FFR_MSP_PARANOIA
+ syserr("dangerous permissions=%o on queue directory %s",
+ (int) st.st_mode, basedir);
+#else /* _FFR_MSP_PARANOIA */
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, NOQID,
+ "dangerous permissions=%o on queue directory %s",
+ (int) st.st_mode, basedir);
+#endif /* _FFR_MSP_PARANOIA */
+ }
+#if _FFR_MSP_PARANOIA
+ if (NumQueue > 1)
+ syserr("can not use multiple queues for MSP");
+#endif /* _FFR_MSP_PARANOIA */
+ }
+
+ /* initial number of queue directories */
+ qn = 0;
+ for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
+ qn = multiqueue_cache(basedir, len, Queue[i], qn, &hashval);
+
+#if SM_CONF_SHM
+ init_shm(qn, owner, hashval);
+ i = filesys_setup(owner || ShmId == SM_SHM_NO_ID);
+ if (i == FSF_NOT_FOUND)
+ {
+ /*
+ ** We didn't get the right filesystem data
+ ** This may happen if we don't have the right shared memory.
+ ** So let's do this without shared memory.
+ */
+
+ SM_ASSERT(!owner);
+ cleanup_shm(false); /* release shared memory */
+ i = filesys_setup(false);
+ if (i < 0)
+ syserr("filesys_setup failed twice, result=%d", i);
+ else if (LogLevel > 8)
+ sm_syslog(LOG_WARNING, NOQID,
+ "shared memory does not contain expected data, ignored");
+ }
+#else /* SM_CONF_SHM */
+ i = filesys_setup(true);
+#endif /* SM_CONF_SHM */
+ if (i < 0)
+ ExitStat = EX_CONFIG;
+}
+
+#if SM_CONF_SHM
+/*
+** CLEANUP_SHM -- do some cleanup work for shared memory etc
+**
+** Parameters:
+** owner -- owner of shared memory?
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** detaches shared memory.
+*/
+
+void
+cleanup_shm(owner)
+ bool owner;
+{
+ if (ShmId != SM_SHM_NO_ID)
+ {
+ if (sm_shmstop(Pshm, ShmId, owner) < 0 && LogLevel > 8)
+ sm_syslog(LOG_INFO, NOQID, "sh_shmstop failed=%s",
+ sm_errstring(errno));
+ Pshm = NULL;
+ ShmId = SM_SHM_NO_ID;
+ }
+}
+#endif /* SM_CONF_SHM */
+
+/*
+** CLEANUP_QUEUES -- do some cleanup work for queues
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+*/
+
+void
+cleanup_queues()
+{
+ sync_queue_time();
+}
+/*
+** SET_DEF_QUEUEVAL -- set default values for a queue group.
+**
+** Parameters:
+** qg -- queue group
+** all -- set all values (true for default group)?
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sets default values for the queue group.
+*/
+
+void
+set_def_queueval(qg, all)
+ QUEUEGRP *qg;
+ bool all;
+{
+ if (bitnset(QD_DEFINED, qg->qg_flags))
+ return;
+ if (all)
+ qg->qg_qdir = QueueDir;
+#if 0
+ qg->qg_sortorder = QueueSortOrder;
+#endif /* 0 */
+ qg->qg_maxqrun = all ? MaxRunnersPerQueue : -1;
+ qg->qg_nice = NiceQueueRun;
+}
+/*
+** MAKEQUEUE -- define a new queue.
+**
+** Parameters:
+** line -- description of queue. This is in labeled fields.
+** The fields are:
+** F -- the flags associated with the queue
+** I -- the interval between running the queue
+** J -- the maximum # of jobs in work list
+** [M -- the maximum # of jobs in a queue run]
+** N -- the niceness at which to run
+** P -- the path to the queue
+** S -- the queue sorting order
+** R -- number of parallel queue runners
+** r -- max recipients per envelope
+** The first word is the canonical name of the queue.
+** qdef -- this is a 'Q' definition from .cf
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** enters the queue into the queue table.
+*/
+
+void
+makequeue(line, qdef)
+ char *line;
+ bool qdef;
+{
+ register char *p;
+ register QUEUEGRP *qg;
+ register STAB *s;
+ int i;
+ char fcode;
+
+ /* allocate a queue and set up defaults */
+ qg = (QUEUEGRP *) xalloc(sizeof *qg);
+ memset((char *) qg, '\0', sizeof *qg);
+
+ if (line[0] == '\0')
+ {
+ syserr("name required for queue");
+ return;
+ }
+
+ /* collect the queue name */
+ for (p = line;
+ *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
+ p++)
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+ qg->qg_name = newstr(line);
+
+ /* set default values, can be overridden below */
+ set_def_queueval(qg, false);
+
+ /* now scan through and assign info from the fields */
+ while (*p != '\0')
+ {
+ auto char *delimptr;
+
+ while (*p != '\0' &&
+ (*p == ',' || (isascii(*p) && isspace(*p))))
+ p++;
+
+ /* p now points to field code */
+ fcode = *p;
+ while (*p != '\0' && *p != '=' && *p != ',')
+ p++;
+ if (*p++ != '=')
+ {
+ syserr("queue %s: `=' expected", qg->qg_name);
+ return;
+ }
+ while (isascii(*p) && isspace(*p))
+ p++;
+
+ /* p now points to the field body */
+ p = munchstring(p, &delimptr, ',');
+
+ /* install the field into the queue struct */
+ switch (fcode)
+ {
+ case 'P': /* pathname */
+ if (*p == '\0')
+ syserr("queue %s: empty path name",
+ qg->qg_name);
+ else
+ qg->qg_qdir = newstr(p);
+ break;
+
+ case 'F': /* flags */
+ for (; *p != '\0'; p++)
+ if (!(isascii(*p) && isspace(*p)))
+ setbitn(*p, qg->qg_flags);
+ break;
+
+ /*
+ ** Do we need two intervals here:
+ ** One for persistent queue runners,
+ ** one for "normal" queue runs?
+ */
+
+ case 'I': /* interval between running the queue */
+ qg->qg_queueintvl = convtime(p, 'm');
+ break;
+
+ case 'N': /* run niceness */
+ qg->qg_nice = atoi(p);
+ break;
+
+ case 'R': /* maximum # of runners for the group */
+ i = atoi(p);
+
+ /* can't have more runners than allowed total */
+ if (MaxQueueChildren > 0 && i > MaxQueueChildren)
+ {
+ qg->qg_maxqrun = MaxQueueChildren;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Q=%s: R=%d exceeds MaxQueueChildren=%d, set to MaxQueueChildren\n",
+ qg->qg_name, i,
+ MaxQueueChildren);
+ }
+ else
+ qg->qg_maxqrun = i;
+ break;
+
+ case 'J': /* maximum # of jobs in work list */
+ qg->qg_maxlist = atoi(p);
+ break;
+
+ case 'r': /* max recipients per envelope */
+ qg->qg_maxrcpt = atoi(p);
+ break;
+
+#if 0
+ case 'S': /* queue sorting order */
+ switch (*p)
+ {
+ case 'h': /* Host first */
+ case 'H':
+ qg->qg_sortorder = QSO_BYHOST;
+ break;
+
+ case 'p': /* Priority order */
+ case 'P':
+ qg->qg_sortorder = QSO_BYPRIORITY;
+ break;
+
+ case 't': /* Submission time */
+ case 'T':
+ qg->qg_sortorder = QSO_BYTIME;
+ break;
+
+ case 'f': /* File name */
+ case 'F':
+ qg->qg_sortorder = QSO_BYFILENAME;
+ break;
+
+ case 'm': /* Modification time */
+ case 'M':
+ qgrp->qg_sortorder = QSO_BYMODTIME;
+ break;
+
+ default:
+ syserr("Invalid queue sort order \"%s\"", p);
+ }
+ break;
+#endif /* 0 */
+
+ default:
+ syserr("Q%s: unknown queue equate %c=",
+ qg->qg_name, fcode);
+ break;
+ }
+
+ p = delimptr;
+ }
+
+#if !HASNICE
+ if (qg->qg_nice != NiceQueueRun)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Q%s: Warning: N= set on system that doesn't support nice()\n",
+ qg->qg_name);
+ }
+#endif /* !HASNICE */
+
+ /* do some rationality checking */
+ if (NumQueue >= MAXQUEUEGROUPS)
+ {
+ syserr("too many queue groups defined (%d max)",
+ MAXQUEUEGROUPS);
+ return;
+ }
+
+ if (qg->qg_qdir == NULL)
+ {
+ if (QueueDir == NULL || *QueueDir == '\0')
+ {
+ syserr("QueueDir must be defined before queue groups");
+ return;
+ }
+ qg->qg_qdir = newstr(QueueDir);
+ }
+
+ if (qg->qg_maxqrun > 1 && !bitnset(QD_FORK, qg->qg_flags))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Q=%s: R=%d: multiple queue runners specified\n\tbut flag '%c' is not set\n",
+ qg->qg_name, qg->qg_maxqrun, QD_FORK);
+ }
+
+ /* enter the queue into the symbol table */
+ if (tTd(37, 8))
+ sm_syslog(LOG_INFO, NOQID,
+ "Adding %s to stab, path: %s", qg->qg_name,
+ qg->qg_qdir);
+ s = stab(qg->qg_name, ST_QUEUE, ST_ENTER);
+ if (s->s_quegrp != NULL)
+ {
+ i = s->s_quegrp->qg_index;
+
+ /* XXX what about the pointers inside this struct? */
+ sm_free(s->s_quegrp); /* XXX */
+ }
+ else
+ i = NumQueue++;
+ Queue[i] = s->s_quegrp = qg;
+ qg->qg_index = i;
+
+ /* set default value for max queue runners */
+ if (qg->qg_maxqrun < 0)
+ {
+ if (MaxRunnersPerQueue > 0)
+ qg->qg_maxqrun = MaxRunnersPerQueue;
+ else
+ qg->qg_maxqrun = 1;
+ }
+ if (qdef)
+ setbitn(QD_DEFINED, qg->qg_flags);
+}
+#if 0
+/*
** HASHFQN -- calculate a hash value for a fully qualified host name
**
** Arguments:
@@ -3441,7 +6917,6 @@ hashfqn(fqn, buckets)
{
register char *p;
register int h = 0, hash, cnt;
-# define WATERINC (1000)
if (fqn == NULL)
return -1;
@@ -3465,10 +6940,10 @@ hashfqn(fqn, buckets)
return hash;
}
-# endif /* 0 */
+#endif /* 0 */
-# if _FFR_QUEUEDELAY
- /*
+#if _FFR_QUEUEDELAY
+/*
** QUEUEDELAY -- compute queue delay time
**
** Parameters:
@@ -3503,5 +6978,1330 @@ queuedelay(e)
qd = MinQueueAge;
return qd;
}
-# endif /* _FFR_QUEUEDELAY */
-#endif /* QUEUE */
+#endif /* _FFR_QUEUEDELAY */
+
+/*
+** A structure for sorting Queue according to maxqrun without
+** screwing up Queue itself.
+*/
+
+struct sortqgrp
+{
+ int sg_idx; /* original index */
+ int sg_maxqrun; /* max queue runners */
+};
+typedef struct sortqgrp SORTQGRP_T;
+static int cmpidx __P((const void *, const void *));
+
+static int
+cmpidx(a, b)
+ const void *a;
+ const void *b;
+{
+ /* The sort is highest to lowest, so the comparison is reversed */
+ if (((SORTQGRP_T *)a)->sg_maxqrun < ((SORTQGRP_T *)b)->sg_maxqrun)
+ return 1;
+ else if (((SORTQGRP_T *)a)->sg_maxqrun > ((SORTQGRP_T *)b)->sg_maxqrun)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+** MAKEWORKGROUP -- balance queue groups into work groups per MaxQueueChildren
+**
+** Take the now defined queue groups and assign them to work groups.
+** This is done to balance out the number of concurrently active
+** queue runners such that MaxQueueChildren is not exceeded. This may
+** result in more than one queue group per work group. In such a case
+** the number of running queue groups in that work group will have no
+** more than the work group maximum number of runners (a "fair" portion
+** of MaxQueueRunners). All queue groups within a work group will get a
+** chance at running.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** nothing.
+**
+** Side Effects:
+** Sets up WorkGrp structure.
+*/
+
+void
+makeworkgroups()
+{
+ int i, j, total_runners = 0;
+ int dir;
+ SORTQGRP_T si[MAXQUEUEGROUPS + 1];
+
+ if (NumQueue == 1 && strcmp(Queue[0]->qg_name, "mqueue") == 0)
+ {
+ /*
+ ** There is only the "mqueue" queue group (a default)
+ ** containing all of the queues. We want to provide to
+ ** this queue group the maximum allowable queue runners.
+ ** To match older behavior (8.10/8.11) we'll try for
+ ** 1 runner per queue capping it at MaxQueueChildren.
+ ** So if there are N queues, then there will be N runners
+ ** for the "mqueue" queue group (where N is kept less than
+ ** MaxQueueChildren).
+ */
+
+ NumWorkGroups = 1;
+ WorkGrp[0].wg_numqgrp = 1;
+ WorkGrp[0].wg_qgs = (QUEUEGRP **) xalloc(sizeof(QUEUEGRP *));
+ WorkGrp[0].wg_qgs[0] = Queue[0];
+ if (MaxQueueChildren > 0 &&
+ Queue[0]->qg_numqueues > MaxQueueChildren)
+ WorkGrp[0].wg_runners = MaxQueueChildren;
+ else
+ WorkGrp[0].wg_runners = Queue[0]->qg_numqueues;
+
+ Queue[0]->qg_wgrp = 0;
+
+ /* can't have more runners than allowed total */
+ if (MaxQueueChildren > 0 &&
+ Queue[0]->qg_maxqrun > MaxQueueChildren)
+ Queue[0]->qg_maxqrun = MaxQueueChildren;
+ WorkGrp[0].wg_maxact = Queue[0]->qg_maxqrun;
+ WorkGrp[0].wg_lowqintvl = Queue[0]->qg_queueintvl;
+ return;
+ }
+
+ for (i = 0; i < NumQueue; i++)
+ {
+ si[i].sg_maxqrun = Queue[i]->qg_maxqrun;
+ si[i].sg_idx = i;
+ }
+ qsort(si, NumQueue, sizeof(si[0]), cmpidx);
+
+ NumWorkGroups = 0;
+ for (i = 0; i < NumQueue; i++)
+ {
+ total_runners += si[i].sg_maxqrun;
+ if (MaxQueueChildren <= 0 || total_runners <= MaxQueueChildren)
+ NumWorkGroups++;
+ else
+ break;
+ }
+
+ if (NumWorkGroups < 1)
+ NumWorkGroups = 1; /* gotta have one at least */
+ else if (NumWorkGroups > MAXWORKGROUPS)
+ NumWorkGroups = MAXWORKGROUPS; /* the limit */
+
+ /*
+ ** We now know the number of work groups to pack the queue groups
+ ** into. The queue groups in 'Queue' are sorted from highest
+ ** to lowest for the number of runners per queue group.
+ ** We put the queue groups with the largest number of runners
+ ** into work groups first. Then the smaller ones are fitted in
+ ** where it looks best.
+ */
+
+ j = 0;
+ dir = 1;
+ for (i = 0; i < NumQueue; i++)
+ {
+ /* a to-and-fro packing scheme, continue from last position */
+ if (j >= NumWorkGroups)
+ {
+ dir = -1;
+ j = NumWorkGroups - 1;
+ }
+ else if (j < 0)
+ {
+ j = 0;
+ dir = 1;
+ }
+
+ WorkGrp[j].wg_qgs = (QUEUEGRP **)sm_realloc(WorkGrp[j].wg_qgs,
+ sizeof(QUEUEGRP *) *
+ (WorkGrp[j].wg_numqgrp + 1));
+ if (WorkGrp[j].wg_qgs == NULL)
+ {
+ syserr("@cannot allocate memory for work queues, need %d bytes",
+ (int) (sizeof(QUEUEGRP *) *
+ (WorkGrp[j].wg_numqgrp + 1)));
+ }
+
+ WorkGrp[j].wg_qgs[WorkGrp[j].wg_numqgrp] = Queue[si[i].sg_idx];
+ WorkGrp[j].wg_numqgrp++;
+ WorkGrp[j].wg_runners += Queue[i]->qg_maxqrun;
+ Queue[si[i].sg_idx]->qg_wgrp = j;
+
+ if (WorkGrp[j].wg_maxact == 0)
+ {
+ /* can't have more runners than allowed total */
+ if (MaxQueueChildren > 0 &&
+ Queue[i]->qg_maxqrun > MaxQueueChildren)
+ Queue[i]->qg_maxqrun = MaxQueueChildren;
+ WorkGrp[j].wg_maxact = Queue[i]->qg_maxqrun;
+ }
+
+ /*
+ ** XXX: must wg_lowqintvl be the GCD?
+ ** qg1: 2m, qg2: 3m, minimum: 2m, when do queue runs for
+ ** qg2 occur?
+ */
+
+ /* keep track of the lowest interval for a persistent runner */
+ if (Queue[si[i].sg_idx]->qg_queueintvl > 0 &&
+ WorkGrp[j].wg_lowqintvl < Queue[si[i].sg_idx]->qg_queueintvl)
+ WorkGrp[j].wg_lowqintvl = Queue[si[i].sg_idx]->qg_queueintvl;
+ j += dir;
+ }
+ if (tTd(41, 9))
+ {
+ for (i = 0; i < NumWorkGroups; i++)
+ {
+ sm_dprintf("Workgroup[%d]=", i);
+ for (j = 0; j < WorkGrp[i].wg_numqgrp; j++)
+ {
+ sm_dprintf("%s, ",
+ WorkGrp[i].wg_qgs[j]->qg_name);
+ }
+ sm_dprintf("\n");
+ }
+ }
+}
+
+/*
+** DUP_DF -- duplicate envelope data file
+**
+** Copy the data file from the 'old' envelope to the 'new' envelope
+** in the most efficient way possible.
+**
+** Create a hard link from the 'old' data file to the 'new' data file.
+** If the old and new queue directories are on different file systems,
+** then the new data file link is created in the old queue directory,
+** and the new queue file will contain a 'd' record pointing to the
+** directory containing the new data file.
+**
+** Parameters:
+** old -- old envelope.
+** new -- new envelope.
+**
+** Results:
+** Returns true on success, false on failure.
+**
+** Side Effects:
+** On success, the new data file is created.
+** On fatal failure, EF_FATALERRS is set in old->e_flags.
+*/
+
+static bool dup_df __P((ENVELOPE *, ENVELOPE *));
+
+static bool
+dup_df(old, new)
+ ENVELOPE *old;
+ ENVELOPE *new;
+{
+ int ofs, nfs, r;
+ char opath[MAXPATHLEN];
+ char npath[MAXPATHLEN];
+
+ SM_REQUIRE(bitset(EF_HAS_DF, old->e_flags));
+ SM_REQUIRE(ISVALIDQGRP(old->e_qgrp) && ISVALIDQDIR(old->e_qdir));
+ SM_REQUIRE(ISVALIDQGRP(new->e_qgrp) && ISVALIDQDIR(new->e_qdir));
+
+ (void) sm_strlcpy(opath, queuename(old, DATAFL_LETTER), sizeof opath);
+ (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
+
+ if (old->e_dfp != NULL)
+ {
+ r = sm_io_setinfo(old->e_dfp, SM_BF_COMMIT, NULL);
+ if (r < 0 && errno != EINVAL)
+ {
+ syserr("@can't commit %s", opath);
+ old->e_flags |= EF_FATALERRS;
+ return false;
+ }
+ }
+
+ /*
+ ** Attempt to create a hard link, if we think both old and new
+ ** are on the same file system, otherwise copy the file.
+ **
+ ** Don't waste time attempting a hard link unless old and new
+ ** are on the same file system.
+ */
+
+ ofs = Queue[old->e_qgrp]->qg_qpaths[old->e_qdir].qp_fsysidx;
+ nfs = Queue[new->e_qgrp]->qg_qpaths[new->e_qdir].qp_fsysidx;
+ if (FILE_SYS_DEV(ofs) == FILE_SYS_DEV(nfs))
+ {
+ if (link(opath, npath) == 0)
+ {
+ new->e_flags |= EF_HAS_DF;
+ SYNC_DIR(npath, true);
+ return true;
+ }
+ goto error;
+ }
+
+ /*
+ ** Can't link across queue directories, so try to create a hard
+ ** link in the same queue directory as the old df file.
+ ** The qf file will refer to the new df file using a 'd' record.
+ */
+
+ new->e_dfqgrp = old->e_dfqgrp;
+ new->e_dfqdir = old->e_dfqdir;
+ (void) sm_strlcpy(npath, queuename(new, DATAFL_LETTER), sizeof npath);
+ if (link(opath, npath) == 0)
+ {
+ new->e_flags |= EF_HAS_DF;
+ SYNC_DIR(npath, true);
+ return true;
+ }
+
+ error:
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, old->e_id,
+ "dup_df: can't link %s to %s, error=%s, envelope splitting failed",
+ opath, npath, sm_errstring(errno));
+ return false;
+}
+
+/*
+** SPLIT_ENV -- Allocate a new envelope based on a given envelope.
+**
+** Parameters:
+** e -- envelope.
+** sendqueue -- sendqueue for new envelope.
+** qgrp -- index of queue group.
+** qdir -- queue directory.
+**
+** Results:
+** new envelope.
+**
+*/
+
+static ENVELOPE *split_env __P((ENVELOPE *, ADDRESS *, int, int));
+
+static ENVELOPE *
+split_env(e, sendqueue, qgrp, qdir)
+ ENVELOPE *e;
+ ADDRESS *sendqueue;
+ int qgrp;
+ int qdir;
+{
+ ENVELOPE *ee;
+
+ ee = (ENVELOPE *) sm_rpool_malloc_x(e->e_rpool, sizeof *ee);
+ STRUCTCOPY(*e, *ee);
+ ee->e_message = NULL; /* XXX use original message? */
+ ee->e_id = NULL;
+ assign_queueid(ee);
+ ee->e_sendqueue = sendqueue;
+ ee->e_flags &= ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS
+ |EF_SENDRECEIPT|EF_RET_PARAM|EF_HAS_DF);
+ ee->e_flags |= EF_NORECEIPT; /* XXX really? */
+ ee->e_from.q_state = QS_SENDER;
+ ee->e_dfp = NULL;
+ ee->e_lockfp = NULL;
+ if (e->e_xfp != NULL)
+ ee->e_xfp = sm_io_dup(e->e_xfp);
+ ee->e_qgrp = ee->e_dfqgrp = qgrp;
+ ee->e_qdir = ee->e_dfqdir = qdir;
+ ee->e_errormode = EM_MAIL;
+ ee->e_statmsg = NULL;
+#if _FFR_QUARANTINE
+ if (e->e_quarmsg != NULL)
+ ee->e_quarmsg = sm_rpool_strdup_x(ee->e_rpool,
+ e->e_quarmsg);
+#endif /* _FFR_QUARANTINE */
+
+ /*
+ ** XXX Not sure if this copying is necessary.
+ ** sendall() does this copying, but I don't know if that is
+ ** because of the storage management discipline we were using
+ ** before rpools were introduced, or if it is because these lists
+ ** can be modified later.
+ */
+
+ ee->e_header = copyheader(e->e_header, ee->e_rpool);
+ ee->e_errorqueue = copyqueue(e->e_errorqueue, ee->e_rpool);
+
+ return ee;
+}
+
+/* return values from split functions, check also below! */
+#define SM_SPLIT_FAIL (0)
+#define SM_SPLIT_NONE (1)
+#define SM_SPLIT_NEW(n) (1 + (n))
+
+/*
+** SPLIT_ACROSS_QUEUE_GROUPS
+**
+** This function splits an envelope across multiple queue groups
+** based on the queue group of each recipient.
+**
+** Parameters:
+** e -- envelope.
+**
+** Results:
+** SM_SPLIT_FAIL on failure
+** SM_SPLIT_NONE if no splitting occurred,
+** or 1 + the number of additional envelopes created.
+**
+** Side Effects:
+** On success, e->e_sibling points to a list of zero or more
+** additional envelopes, and the associated data files exist
+** on disk. But the queue files are not created.
+**
+** On failure, e->e_sibling is not changed.
+** The order of recipients in e->e_sendqueue is permuted.
+** Abandoned data files for additional envelopes that failed
+** to be created may exist on disk.
+*/
+
+static int q_qgrp_compare __P((const void *, const void *));
+static int e_filesys_compare __P((const void *, const void *));
+
+static int
+q_qgrp_compare(p1, p2)
+ const void *p1;
+ const void *p2;
+{
+ ADDRESS **pq1 = (ADDRESS **) p1;
+ ADDRESS **pq2 = (ADDRESS **) p2;
+
+ return (*pq1)->q_qgrp - (*pq2)->q_qgrp;
+}
+
+static int
+e_filesys_compare(p1, p2)
+ const void *p1;
+ const void *p2;
+{
+ ENVELOPE **pe1 = (ENVELOPE **) p1;
+ ENVELOPE **pe2 = (ENVELOPE **) p2;
+ int fs1, fs2;
+
+ fs1 = Queue[(*pe1)->e_qgrp]->qg_qpaths[(*pe1)->e_qdir].qp_fsysidx;
+ fs2 = Queue[(*pe2)->e_qgrp]->qg_qpaths[(*pe2)->e_qdir].qp_fsysidx;
+ if (FILE_SYS_DEV(fs1) < FILE_SYS_DEV(fs2))
+ return -1;
+ if (FILE_SYS_DEV(fs1) > FILE_SYS_DEV(fs2))
+ return 1;
+ return 0;
+}
+
+static int
+split_across_queue_groups(e)
+ ENVELOPE *e;
+{
+ int naddrs, nsplits, i;
+ char **pvp;
+ ADDRESS *q, **addrs;
+ ENVELOPE *ee, *es;
+ ENVELOPE *splits[MAXQUEUEGROUPS];
+ char pvpbuf[PSBUFSIZE];
+
+ SM_REQUIRE(ISVALIDQGRP(e->e_qgrp));
+
+ /* Count addresses and assign queue groups. */
+ naddrs = 0;
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (QS_IS_DEAD(q->q_state))
+ continue;
+ ++naddrs;
+
+ /* bad addresses and those already sent stay put */
+ if (QS_IS_BADADDR(q->q_state) ||
+ QS_IS_SENT(q->q_state))
+ q->q_qgrp = e->e_qgrp;
+ else if (!ISVALIDQGRP(q->q_qgrp))
+ {
+ /* call ruleset which should return a queue group */
+ i = rscap(RS_QUEUEGROUP, q->q_user, NULL, e, &pvp,
+ pvpbuf, sizeof(pvpbuf));
+ if (i == EX_OK &&
+ pvp != NULL && pvp[0] != NULL &&
+ (pvp[0][0] & 0377) == CANONNET &&
+ pvp[1] != NULL && pvp[1][0] != '\0')
+ {
+ i = name2qid(pvp[1]);
+ if (ISVALIDQGRP(i))
+ {
+ q->q_qgrp = i;
+ if (tTd(20, 4))
+ sm_syslog(LOG_INFO, NOQID,
+ "queue group name %s -> %d",
+ pvp[1], i);
+ continue;
+ }
+ else if (LogLevel > 10)
+ sm_syslog(LOG_INFO, NOQID,
+ "can't find queue group name %s, selection ignored",
+ pvp[1]);
+ }
+ if (q->q_mailer != NULL &&
+ ISVALIDQGRP(q->q_mailer->m_qgrp))
+ q->q_qgrp = q->q_mailer->m_qgrp;
+ else
+ q->q_qgrp = 0;
+ }
+ }
+
+ /* only one address? nothing to split. */
+ if (naddrs <= 1)
+ return SM_SPLIT_NONE;
+
+ /* sort the addresses by queue group */
+ addrs = sm_rpool_malloc_x(e->e_rpool, naddrs * sizeof(ADDRESS *));
+ for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (QS_IS_DEAD(q->q_state))
+ continue;
+ addrs[i++] = q;
+ }
+ qsort(addrs, naddrs, sizeof(ADDRESS *), q_qgrp_compare);
+
+ /* split into multiple envelopes, by queue group */
+ nsplits = 0;
+ es = NULL;
+ e->e_sendqueue = NULL;
+ for (i = 0; i < naddrs; ++i)
+ {
+ if (i == naddrs - 1 || addrs[i]->q_qgrp != addrs[i + 1]->q_qgrp)
+ addrs[i]->q_next = NULL;
+ else
+ addrs[i]->q_next = addrs[i + 1];
+
+ /* same queue group as original envelope? */
+ if (addrs[i]->q_qgrp == e->e_qgrp)
+ {
+ if (e->e_sendqueue == NULL)
+ e->e_sendqueue = addrs[i];
+ continue;
+ }
+
+ /* different queue group than original envelope */
+ if (es == NULL || addrs[i]->q_qgrp != es->e_qgrp)
+ {
+ ee = split_env(e, addrs[i], addrs[i]->q_qgrp, NOQDIR);
+ es = ee;
+ splits[nsplits++] = ee;
+ }
+ }
+
+ /* no splits? return right now. */
+ if (nsplits <= 0)
+ return SM_SPLIT_NONE;
+
+ /* assign a queue directory to each additional envelope */
+ for (i = 0; i < nsplits; ++i)
+ {
+ es = splits[i];
+#if 0
+ es->e_qdir = pickqdir(Queue[es->e_qgrp], es->e_msgsize, es);
+#endif /* 0 */
+ if (!setnewqueue(es))
+ goto failure;
+ }
+
+ /* sort the additional envelopes by queue file system */
+ qsort(splits, nsplits, sizeof(ENVELOPE *), e_filesys_compare);
+
+ /* create data files for each additional envelope */
+ if (!dup_df(e, splits[0]))
+ {
+ i = 0;
+ goto failure;
+ }
+ for (i = 1; i < nsplits; ++i)
+ {
+ /* copy or link to the previous data file */
+ if (!dup_df(splits[i - 1], splits[i]))
+ goto failure;
+ }
+
+ /* success: prepend the new envelopes to the e->e_sibling list */
+ for (i = 0; i < nsplits; ++i)
+ {
+ es = splits[i];
+ es->e_sibling = e->e_sibling;
+ e->e_sibling = es;
+ }
+ return SM_SPLIT_NEW(nsplits);
+
+ /* failure: clean up */
+ failure:
+ if (i > 0)
+ {
+ int j;
+
+ for (j = 0; j < i; j++)
+ (void) unlink(queuename(splits[j], DATAFL_LETTER));
+ }
+ e->e_sendqueue = addrs[0];
+ for (i = 0; i < naddrs - 1; ++i)
+ addrs[i]->q_next = addrs[i + 1];
+ addrs[naddrs - 1]->q_next = NULL;
+ return SM_SPLIT_FAIL;
+}
+
+/*
+** SPLIT_WITHIN_QUEUE
+**
+** Split an envelope with multiple recipients into several
+** envelopes within the same queue directory, if the number of
+** recipients exceeds the limit for the queue group.
+**
+** Parameters:
+** e -- envelope.
+**
+** Results:
+** SM_SPLIT_FAIL on failure
+** SM_SPLIT_NONE if no splitting occurred,
+** or 1 + the number of additional envelopes created.
+*/
+
+#define SPLIT_LOG_LEVEL 8
+
+static int split_within_queue __P((ENVELOPE *));
+
+static int
+split_within_queue(e)
+ ENVELOPE *e;
+{
+ int maxrcpt, nrcpt, ndead, nsplit, i;
+ int j, l;
+ char *lsplits;
+ ADDRESS *q, **addrs;
+ ENVELOPE *ee, *firstsibling;
+
+ if (!ISVALIDQGRP(e->e_qgrp) || bitset(EF_SPLIT, e->e_flags))
+ return SM_SPLIT_NONE;
+
+ /* don't bother if there is no recipient limit */
+ maxrcpt = Queue[e->e_qgrp]->qg_maxrcpt;
+ if (maxrcpt <= 0)
+ return SM_SPLIT_NONE;
+
+ /* count recipients */
+ nrcpt = 0;
+ for (q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (QS_IS_DEAD(q->q_state))
+ continue;
+ ++nrcpt;
+ }
+ if (nrcpt <= maxrcpt)
+ return SM_SPLIT_NONE;
+
+ /*
+ ** Preserve the recipient list
+ ** so that we can restore it in case of error.
+ ** (But we discard dead addresses.)
+ */
+
+ addrs = sm_rpool_malloc_x(e->e_rpool, nrcpt * sizeof(ADDRESS *));
+ for (i = 0, q = e->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (QS_IS_DEAD(q->q_state))
+ continue;
+ addrs[i++] = q;
+ }
+
+ /*
+ ** Partition the recipient list so that bad and sent addresses
+ ** come first. These will go with the original envelope, and
+ ** do not count towards the maxrcpt limit.
+ ** addrs[] does not contain QS_IS_DEAD() addresses.
+ */
+
+ ndead = 0;
+ for (i = 0; i < nrcpt; ++i)
+ {
+ if (QS_IS_BADADDR(addrs[i]->q_state) ||
+ QS_IS_SENT(addrs[i]->q_state) ||
+ QS_IS_DEAD(addrs[i]->q_state)) /* for paranoia's sake */
+ {
+ if (i > ndead)
+ {
+ ADDRESS *tmp = addrs[i];
+
+ addrs[i] = addrs[ndead];
+ addrs[ndead] = tmp;
+ }
+ ++ndead;
+ }
+ }
+
+ /* Check if no splitting required. */
+ if (nrcpt - ndead <= maxrcpt)
+ return SM_SPLIT_NONE;
+
+ /* fix links */
+ for (i = 0; i < nrcpt - 1; ++i)
+ addrs[i]->q_next = addrs[i + 1];
+ addrs[nrcpt - 1]->q_next = NULL;
+ e->e_sendqueue = addrs[0];
+
+ /* prepare buffer for logging */
+ if (LogLevel > SPLIT_LOG_LEVEL)
+ {
+ l = MAXLINE;
+ lsplits = sm_malloc(l);
+ if (lsplits != NULL)
+ *lsplits = '\0';
+ j = 0;
+ }
+ else
+ {
+ /* get rid of stupid compiler warnings */
+ lsplits = NULL;
+ j = l = 0;
+ }
+
+ /* split the envelope */
+ firstsibling = e->e_sibling;
+ i = maxrcpt + ndead;
+ nsplit = 0;
+ for (;;)
+ {
+ addrs[i - 1]->q_next = NULL;
+ ee = split_env(e, addrs[i], e->e_qgrp, e->e_qdir);
+ if (!dup_df(e, ee))
+ {
+
+ ee = firstsibling;
+ while (ee != NULL)
+ {
+ (void) unlink(queuename(ee, DATAFL_LETTER));
+ ee = ee->e_sibling;
+ }
+
+ /* Error. Restore e's sibling & recipient lists. */
+ e->e_sibling = firstsibling;
+ for (i = 0; i < nrcpt - 1; ++i)
+ addrs[i]->q_next = addrs[i + 1];
+ return SM_SPLIT_FAIL;
+ }
+
+ /* prepend the new envelope to e->e_sibling */
+ ee->e_sibling = e->e_sibling;
+ e->e_sibling = ee;
+ ++nsplit;
+ if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
+ {
+ if (j >= l - strlen(ee->e_id) - 3)
+ {
+ char *p;
+
+ l += MAXLINE;
+ p = sm_realloc(lsplits, l);
+ if (p == NULL)
+ {
+ /* let's try to get this done */
+ sm_free(lsplits);
+ lsplits = NULL;
+ }
+ else
+ lsplits = p;
+ }
+ if (lsplits != NULL)
+ {
+ if (j == 0)
+ j += sm_strlcat(lsplits + j,
+ ee->e_id,
+ l - j);
+ else
+ j += sm_strlcat2(lsplits + j,
+ "; ",
+ ee->e_id,
+ l - j);
+ SM_ASSERT(j < l);
+ }
+ }
+ if (nrcpt - i <= maxrcpt)
+ break;
+ i += maxrcpt;
+ }
+ if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && nsplit > 0)
+ {
+ sm_syslog(LOG_NOTICE, e->e_id,
+ "split: maxrcpts=%d, rcpts=%d, count=%d, id%s=%s",
+ maxrcpt, nrcpt - ndead, nsplit,
+ nsplit > 1 ? "s" : "", lsplits);
+ sm_free(lsplits);
+ }
+ return SM_SPLIT_NEW(nsplit);
+}
+/*
+** SPLIT_BY_RECIPIENT
+**
+** Split an envelope with multiple recipients into multiple
+** envelopes as required by the sendmail configuration.
+**
+** Parameters:
+** e -- envelope.
+**
+** Results:
+** Returns true on success, false on failure.
+**
+** Side Effects:
+** see split_across_queue_groups(), split_within_queue(e)
+*/
+
+bool
+split_by_recipient(e)
+ ENVELOPE *e;
+{
+ int split, n, i, j, l;
+ char *lsplits;
+ ENVELOPE *ee, *next, *firstsibling;
+
+ if (OpMode == SM_VERIFY || !ISVALIDQGRP(e->e_qgrp) ||
+ bitset(EF_SPLIT, e->e_flags))
+ return true;
+ n = split_across_queue_groups(e);
+ if (n == SM_SPLIT_FAIL)
+ return false;
+ firstsibling = ee = e->e_sibling;
+ if (n > 1 && LogLevel > SPLIT_LOG_LEVEL)
+ {
+ l = MAXLINE;
+ lsplits = sm_malloc(l);
+ if (lsplits != NULL)
+ *lsplits = '\0';
+ j = 0;
+ }
+ else
+ {
+ /* get rid of stupid compiler warnings */
+ lsplits = NULL;
+ j = l = 0;
+ }
+ for (i = 1; i < n; ++i)
+ {
+ next = ee->e_sibling;
+ if (split_within_queue(ee) == SM_SPLIT_FAIL)
+ {
+ e->e_sibling = firstsibling;
+ return false;
+ }
+ ee->e_flags |= EF_SPLIT;
+ if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL)
+ {
+ if (j >= l - strlen(ee->e_id) - 3)
+ {
+ char *p;
+
+ l += MAXLINE;
+ p = sm_realloc(lsplits, l);
+ if (p == NULL)
+ {
+ /* let's try to get this done */
+ sm_free(lsplits);
+ lsplits = NULL;
+ }
+ else
+ lsplits = p;
+ }
+ if (lsplits != NULL)
+ {
+ if (j == 0)
+ j += sm_strlcat(lsplits + j,
+ ee->e_id, l - j);
+ else
+ j += sm_strlcat2(lsplits + j, "; ",
+ ee->e_id, l - j);
+ SM_ASSERT(j < l);
+ }
+ }
+ ee = next;
+ }
+ if (LogLevel > SPLIT_LOG_LEVEL && lsplits != NULL && n > 1)
+ {
+ sm_syslog(LOG_NOTICE, e->e_id, "split: count=%d, id%s=%s",
+ n - 1, n > 2 ? "s" : "", lsplits);
+ sm_free(lsplits);
+ }
+ split = split_within_queue(e) != SM_SPLIT_FAIL;
+ if (split)
+ e->e_flags |= EF_SPLIT;
+ return split;
+}
+
+#if _FFR_QUARANTINE
+/*
+** QUARANTINE_QUEUE_ITEM -- {un,}quarantine a single envelope
+**
+** Add/remove quarantine reason and requeue appropriately.
+**
+** Parameters:
+** qgrp -- queue group for the item
+** qdir -- queue directory in the given queue group
+** e -- envelope information for the item
+** reason -- quarantine reason, NULL means unquarantine.
+**
+** Results:
+** true if item changed, false otherwise
+**
+** Side Effects:
+** Changes quarantine tag in queue file and renames it.
+*/
+
+static bool
+quarantine_queue_item(qgrp, qdir, e, reason)
+ int qgrp;
+ int qdir;
+ ENVELOPE *e;
+ char *reason;
+{
+ bool dirty = false;
+ bool failing = false;
+ bool foundq = false;
+ bool finished = false;
+ int fd;
+ int flags;
+ int oldtype;
+ int newtype;
+ int save_errno;
+ MODE_T oldumask = 0;
+ SM_FILE_T *oldqfp, *tempqfp;
+ char *bp;
+ char oldqf[MAXPATHLEN];
+ char tempqf[MAXPATHLEN];
+ char newqf[MAXPATHLEN];
+ char buf[MAXLINE];
+
+ oldtype = queue_letter(e, ANYQFL_LETTER);
+ (void) sm_strlcpy(oldqf, queuename(e, ANYQFL_LETTER), sizeof oldqf);
+ (void) sm_strlcpy(tempqf, queuename(e, NEWQFL_LETTER), sizeof tempqf);
+
+ /*
+ ** Instead of duplicating all the open
+ ** and lock code here, tell readqf() to
+ ** do that work and return the open
+ ** file pointer in e_lockfp. Note that
+ ** we must release the locks properly when
+ ** we are done.
+ */
+
+ if (!readqf(e, true))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s\n", qid_printname(e));
+ return false;
+ }
+ oldqfp = e->e_lockfp;
+
+ /* open the new queue file */
+ flags = O_CREAT|O_WRONLY|O_EXCL;
+ if (bitset(S_IWGRP, QueueFileMode))
+ oldumask = umask(002);
+ fd = open(tempqf, flags, QueueFileMode);
+ if (bitset(S_IWGRP, QueueFileMode))
+ (void) umask(oldumask);
+ RELEASE_QUEUE;
+
+ if (fd < 0)
+ {
+ save_errno = errno;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Could not open %s: %s\n",
+ qid_printname(e), tempqf,
+ sm_errstring(save_errno));
+ (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
+ return false;
+ }
+ if (!lockfile(fd, tempqf, NULL, LOCK_EX|LOCK_NB))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Could not lock %s\n",
+ qid_printname(e), tempqf);
+ (void) close(fd);
+ (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
+ return false;
+ }
+
+ tempqfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &fd,
+ SM_IO_WRONLY, NULL);
+ if (tempqfp == NULL)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Could not lock %s\n",
+ qid_printname(e), tempqf);
+ (void) close(fd);
+ (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
+ return false;
+ }
+
+ /* Copy the data over, changing the quarantine reason */
+ while ((bp = fgetfolded(buf, sizeof buf, oldqfp)) != NULL)
+ {
+ if (tTd(40, 4))
+ sm_dprintf("+++++ %s\n", bp);
+ switch (bp[0])
+ {
+ case 'q': /* quarantine reason */
+ foundq = true;
+ if (reason == NULL)
+ {
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s: Removed quarantine of \"%s\"\n",
+ e->e_id, &bp[1]);
+ }
+ sm_syslog(LOG_INFO, e->e_id, "unquarantine");
+ dirty = true;
+ continue;
+ }
+ else if (strcmp(reason, &bp[1]) == 0)
+ {
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s: Already quarantined with \"%s\"\n",
+ e->e_id, reason);
+ }
+ (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
+ "q%s\n", reason);
+ }
+ else
+ {
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s: Quarantine changed from \"%s\" to \"%s\"\n",
+ e->e_id, &bp[1],
+ reason);
+ }
+ (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
+ "q%s\n", reason);
+ sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
+ reason);
+ dirty = true;
+ }
+ break;
+
+ case 'R':
+ /*
+ ** If we are quarantining an unquarantined item,
+ ** need to put in a new 'q' line before it's
+ ** too late.
+ */
+
+ if (!foundq && reason != NULL)
+ {
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s: Quarantined with \"%s\"\n",
+ e->e_id, reason);
+ }
+ (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
+ "q%s\n", reason);
+ sm_syslog(LOG_INFO, e->e_id, "quarantine=%s",
+ reason);
+ foundq = true;
+ dirty = true;
+ }
+
+ /* Copy the line to the new file */
+ (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
+ "%s\n", bp);
+ break;
+
+ case '.':
+ finished = true;
+ /* FALLTHROUGH */
+
+ default:
+ /* Copy the line to the new file */
+ (void) sm_io_fprintf(tempqfp, SM_TIME_DEFAULT,
+ "%s\n", bp);
+ break;
+ }
+ }
+
+ /* Make sure we read the whole old file */
+ errno = sm_io_error(tempqfp);
+ if (errno != 0 && errno != SM_IO_EOF)
+ {
+ save_errno = errno;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Error reading %s: %s\n",
+ qid_printname(e), oldqf,
+ sm_errstring(save_errno));
+ failing = true;
+ }
+
+ if (!failing && !finished)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Incomplete file: %s\n",
+ qid_printname(e), oldqf);
+ failing = true;
+ }
+
+ /* Check if we actually changed anything or we can just bail now */
+ if (!dirty)
+ {
+ /* pretend we failed, even though we technically didn't */
+ failing = true;
+ }
+
+ /* Make sure we wrote things out safely */
+ if (!failing &&
+ (sm_io_flush(tempqfp, SM_TIME_DEFAULT) != 0 ||
+ ((SuperSafe == SAFE_REALLY || SuperSafe == SAFE_INTERACTIVE) &&
+ fsync(sm_io_getinfo(tempqfp, SM_IO_WHAT_FD, NULL)) < 0) ||
+ ((errno = sm_io_error(tempqfp)) != 0)))
+ {
+ save_errno = errno;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Skipping %s: Error writing %s: %s\n",
+ qid_printname(e), tempqf,
+ sm_errstring(save_errno));
+ failing = true;
+ }
+
+
+ /* Figure out the new filename */
+ newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
+ if (oldtype == newtype)
+ {
+ /* going to rename tempqf to oldqf */
+ (void) sm_strlcpy(newqf, oldqf, sizeof newqf);
+ }
+ else
+ {
+ /* going to rename tempqf to new name based on newtype */
+ (void) sm_strlcpy(newqf, queuename(e, newtype), sizeof newqf);
+ }
+
+ save_errno = 0;
+
+ /* rename tempqf to newqf */
+ if (!failing &&
+ rename(tempqf, newqf) < 0)
+ save_errno = (errno == 0) ? EINVAL : errno;
+
+ /* Check rename() success */
+ if (!failing && save_errno != 0)
+ {
+ sm_syslog(LOG_DEBUG, e->e_id,
+ "quarantine_queue_item: rename(%s, %s): %s",
+ tempqf, newqf, sm_errstring(save_errno));
+
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Error renaming %s to %s: %s\n",
+ tempqf, newqf,
+ sm_errstring(save_errno));
+ if (oldtype == newtype)
+ {
+ /*
+ ** Bail here since we don't know the state of
+ ** the filesystem and may need to keep tempqf
+ ** for the user to rescue us.
+ */
+
+ RELEASE_QUEUE;
+ errno = save_errno;
+ syserr("!452 Error renaming control file %s", tempqf);
+ /* NOTREACHED */
+ }
+ else
+ {
+ /* remove new file (if rename() half completed) */
+ if (xunlink(newqf) < 0)
+ {
+ save_errno = errno;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Error removing %s: %s\n",
+ newqf,
+ sm_errstring(save_errno));
+ }
+
+ /* tempqf removed below */
+ failing = true;
+ }
+
+ }
+
+ /* If changing file types, need to remove old type */
+ if (!failing && oldtype != newtype)
+ {
+ if (xunlink(oldqf) < 0)
+ {
+ save_errno = errno;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Error removing %s: %s\n",
+ oldqf, sm_errstring(save_errno));
+ }
+ }
+
+ /* see if anything above failed */
+ if (failing)
+ {
+ /* Something failed: remove new file, old file still there */
+ (void) xunlink(tempqf);
+ }
+
+ /*
+ ** fsync() after file operations to make sure metadata is
+ ** written to disk on filesystems in which renames are
+ ** not guaranteed. It's ok if they fail, mail won't be lost.
+ */
+
+ if (SuperSafe != SAFE_NO)
+ {
+ /* for soft-updates */
+ (void) fsync(sm_io_getinfo(tempqfp,
+ SM_IO_WHAT_FD, NULL));
+
+ if (!failing)
+ {
+ /* for soft-updates */
+ (void) fsync(sm_io_getinfo(oldqfp,
+ SM_IO_WHAT_FD, NULL));
+ }
+
+ /* for other odd filesystems */
+ SYNC_DIR(tempqf, false);
+ }
+
+ /* Close up shop */
+ RELEASE_QUEUE;
+ if (tempqfp != NULL)
+ (void) sm_io_close(tempqfp, SM_TIME_DEFAULT);
+ if (oldqfp != NULL)
+ (void) sm_io_close(oldqfp, SM_TIME_DEFAULT);
+
+ /* All went well */
+ return !failing;
+}
+
+/*
+** QUARANTINE_QUEUE -- {un,}quarantine matching items in the queue
+**
+** Read all matching queue items, add/remove quarantine
+** reason, and requeue appropriately.
+**
+** Parameters:
+** reason -- quarantine reason, "." means unquarantine.
+** qgrplimit -- limit to single queue group unless NOQGRP
+**
+** Results:
+** none.
+**
+** Side Effects:
+** Lots of changes to the queue.
+*/
+
+void
+quarantine_queue(reason, qgrplimit)
+ char *reason;
+ int qgrplimit;
+{
+ int changed = 0;
+ int qgrp;
+
+ /* Convert internal representation of unquarantine */
+ if (reason != NULL && reason[0] == '.' && reason[1] == '\0')
+ reason = NULL;
+
+ if (reason != NULL)
+ {
+ /* clean it */
+ reason = newstr(denlstring(reason, true, true));
+ }
+
+ for (qgrp = 0; qgrp < NumQueue && Queue[qgrp] != NULL; qgrp++)
+ {
+ int qdir;
+
+ if (qgrplimit != NOQGRP && qgrplimit != qgrp)
+ continue;
+
+ for (qdir = 0; qdir < Queue[qgrp]->qg_numqueues; qdir++)
+ {
+ int i;
+ int nrequests;
+
+ if (StopRequest)
+ stop_sendmail();
+
+ nrequests = gatherq(qgrp, qdir, true, NULL, NULL);
+
+ /* first see if there is anything */
+ if (nrequests <= 0)
+ {
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT, "%s: no matches\n",
+ qid_printqueue(qgrp, qdir));
+ }
+ continue;
+ }
+
+ if (Verbose)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT, "Processing %s:\n",
+ qid_printqueue(qgrp, qdir));
+ }
+
+ for (i = 0; i < WorkListCount; i++)
+ {
+ ENVELOPE e;
+
+ if (StopRequest)
+ stop_sendmail();
+
+ /* setup envelope */
+ clearenvelope(&e, true, sm_rpool_new_x(NULL));
+ e.e_id = WorkList[i].w_name + 2;
+ e.e_qgrp = qgrp;
+ e.e_qdir = qdir;
+
+ if (tTd(70, 101))
+ {
+ sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Would do %s\n", e.e_id);
+ changed++;
+ }
+ else if (quarantine_queue_item(qgrp, qdir,
+ &e, reason))
+ changed++;
+
+ /* clean up */
+ sm_rpool_free(e.e_rpool);
+ e.e_rpool = NULL;
+ }
+ if (WorkList != NULL)
+ sm_free(WorkList); /* XXX */
+ WorkList = NULL;
+ WorkListSize = 0;
+ WorkListCount = 0;
+ }
+ }
+ if (Verbose)
+ {
+ if (changed == 0)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "No changes\n");
+ else
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%d change%s\n",
+ changed,
+ changed == 1 ? "" : "s");
+ }
+}
+#endif /* _FFR_QUARANTINE */
diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c
index 73acff5..1f6a662 100644
--- a/contrib/sendmail/src/readcf.c
+++ b/contrib/sendmail/src/readcf.c
@@ -11,12 +11,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: readcf.c,v 8.382.4.43 2001/08/14 23:08:13 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: readcf.c,v 8.594 2001/12/14 00:43:17 gshapiro Exp $")
#if NETINET || NETINET6
# include <arpa/inet.h>
@@ -31,6 +28,7 @@ static void fileclass __P((int, char *, char *, bool, bool));
static char **makeargv __P((char *));
static void settimeout __P((char *, char *, bool));
static void toomany __P((int, int));
+static char *extrquotstr __P((char *, char **, char *, bool *));
/*
** READCF -- read configuration file.
@@ -57,7 +55,10 @@ static void toomany __P((int, int));
** Mn arg=val... Define mailer. n is the internal name.
** Args specify mailer parameters.
** Oxvalue Set option x to value.
+** O option value Set option (long name) to value.
** Pname=value Set precedence name to value.
+** Qn arg=val... Define queue groups. n is the internal name.
+** Args specify queue parameters.
** Vversioncode[/vendorcode]
** Version level/vendor name of
** configuration syntax.
@@ -68,8 +69,8 @@ static void toomany __P((int, int));
**
** Parameters:
** cfname -- configuration file name.
-** safe -- TRUE if this is the system config file;
-** FALSE otherwise.
+** safe -- true if this is the system config file;
+** false otherwise.
** e -- the main envelope.
**
** Returns:
@@ -85,7 +86,7 @@ readcf(cfname, safe, e)
bool safe;
register ENVELOPE *e;
{
- FILE *cf;
+ SM_FILE_T *cf;
int ruleset = -1;
char *q;
struct rewrite *rwp = NULL;
@@ -94,6 +95,7 @@ readcf(cfname, safe, e)
int nfuzzy;
char *file;
bool optional;
+ bool ok;
int mid;
register char *p;
long sff = SFF_OPENASROOT;
@@ -102,7 +104,7 @@ readcf(cfname, safe, e)
char exbuf[MAXLINE];
char pvpbuf[MAXLINE + MAXATOM];
static char *null_list[1] = { NULL };
- extern u_char TokTypeNoC[];
+ extern unsigned char TokTypeNoC[];
FileName = cfname;
LineNumber = 0;
@@ -113,33 +115,34 @@ readcf(cfname, safe, e)
if (cf == NULL)
{
syserr("cannot open");
- finis(FALSE, EX_OSFILE);
+ finis(false, true, EX_OSFILE);
}
- if (fstat(fileno(cf), &statb) < 0)
+ if (fstat(sm_io_getinfo(cf, SM_IO_WHAT_FD, NULL), &statb) < 0)
{
syserr("cannot fstat");
- finis(FALSE, EX_OSFILE);
+ finis(false, true, EX_OSFILE);
}
if (!S_ISREG(statb.st_mode))
{
syserr("not a plain file");
- finis(FALSE, EX_OSFILE);
+ finis(false, true, EX_OSFILE);
}
if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
{
if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
- fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
- FileName);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: WARNING: dangerous write permissions\n",
+ FileName);
if (LogLevel > 0)
sm_syslog(LOG_CRIT, NOQID,
"%s: WARNING: dangerous write permissions",
FileName);
}
-#ifdef XLA
+#if XLA
xla_zero();
#endif /* XLA */
@@ -148,7 +151,7 @@ readcf(cfname, safe, e)
if (bp[0] == '#')
{
if (bp != buf)
- sm_free(bp);
+ sm_free(bp); /* XXX */
continue;
}
@@ -202,7 +205,7 @@ readcf(cfname, safe, e)
{
register char **ap;
- rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
+ rwp->r_lhs = copyplist(rwp->r_lhs, true, NULL);
/* count the number of fuzzy matches in LHS */
for (ap = rwp->r_lhs; *ap != NULL; ap++)
@@ -288,7 +291,7 @@ readcf(cfname, safe, e)
{
register char **ap;
- rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
+ rwp->r_rhs = copyplist(rwp->r_rhs, true, NULL);
/* check no out-of-bounds replacements */
nfuzzy += '0';
@@ -326,6 +329,36 @@ readcf(cfname, safe, e)
case MATCHNCLASS:
botch = "$~";
break;
+
+#if 0
+/*
+** This doesn't work yet as there are maps defined *after* the cf
+** is read such as host, user, and alias. So for now, it's removed.
+** When it comes back, the RELEASE_NOTES entry will be:
+** Emit warnings for unknown maps when reading the .cf file. Based on
+** patch from Robert Harker of Harker Systems.
+*/
+
+ case LOOKUPBEGIN:
+ /*
+ ** Got a database lookup,
+ ** check if map is defined.
+ */
+
+ ep = *(ap + 1);
+ if ((*ep & 0377) != MACRODEXPAND &&
+ stab(ep, ST_MAP,
+ ST_FIND) == NULL)
+ {
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "Warning: %s: line %d: map %s not found\n",
+ FileName,
+ LineNumber,
+ ep);
+ }
+ break;
+#endif /* 0 */
}
if (botch != NULL)
syserr("Inappropriate use of %s on RHS",
@@ -349,22 +382,24 @@ readcf(cfname, safe, e)
if (rwp != NULL)
{
if (OpMode == MD_TEST)
- printf("WARNING: Ruleset %s has multiple definitions\n",
- &bp[1]);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "WARNING: Ruleset %s has multiple definitions\n",
+ &bp[1]);
if (tTd(37, 1))
- dprintf("WARNING: Ruleset %s has multiple definitions\n",
- &bp[1]);
+ sm_dprintf("WARNING: Ruleset %s has multiple definitions\n",
+ &bp[1]);
while (rwp->r_next != NULL)
rwp = rwp->r_next;
}
break;
case 'D': /* macro definition */
- mid = macid(&bp[1], &ep);
+ mid = macid_parse(&bp[1], &ep);
if (mid == 0)
break;
p = munchstring(ep, NULL, '\0');
- define(mid, newstr(p), e);
+ macdefine(&e->e_macro, A_TEMP, mid, p);
break;
case 'H': /* required header line */
@@ -375,7 +410,7 @@ readcf(cfname, safe, e)
case 'T': /* trusted user (set class `t') */
if (bp[0] == 'C')
{
- mid = macid(&bp[1], &ep);
+ mid = macid_parse(&bp[1], &ep);
if (mid == 0)
break;
expand(ep, exbuf, sizeof exbuf, e);
@@ -405,27 +440,40 @@ readcf(cfname, safe, e)
break;
case 'F': /* word class from file */
- mid = macid(&bp[1], &ep);
+ mid = macid_parse(&bp[1], &ep);
if (mid == 0)
break;
for (p = ep; isascii(*p) && isspace(*p); )
p++;
if (p[0] == '-' && p[1] == 'o')
{
- optional = TRUE;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ optional = true;
+ while (*p != '\0' &&
+ !(isascii(*p) && isspace(*p)))
p++;
while (isascii(*p) && isspace(*p))
p++;
+ file = p;
}
else
- optional = FALSE;
+ optional = false;
- file = p;
- q = p;
- while (*q != '\0' && !(isascii(*q) && isspace(*q)))
- q++;
- if (*file == '|')
+ if (*p == '@')
+ {
+ /* use entire spec */
+ file = p;
+ }
+ else
+ {
+ file = extrquotstr(p, &q, " ", &ok);
+ if (!ok)
+ {
+ syserr("illegal filename '%s'", p);
+ break;
+ }
+ }
+
+ if (*file == '|' || *file == '@')
p = "%s";
else
{
@@ -442,7 +490,7 @@ readcf(cfname, safe, e)
fileclass(mid, file, p, safe, optional);
break;
-#ifdef XLA
+#if XLA
case 'L': /* extended load average description */
xla_init(&bp[1]);
break;
@@ -463,7 +511,7 @@ readcf(cfname, safe, e)
break;
case 'O': /* set option */
- setoption(bp[1], &bp[2], safe, FALSE, e);
+ setoption(bp[1], &bp[2], safe, false, e);
break;
case 'P': /* set precedence */
@@ -482,6 +530,10 @@ readcf(cfname, safe, e)
NumPriorities++;
break;
+ case 'Q': /* define queue */
+ makequeue(&bp[1], true);
+ break;
+
case 'V': /* configuration syntax version */
for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
continue;
@@ -502,12 +554,15 @@ readcf(cfname, safe, e)
/* level 5 configs have short name in $w */
p = macvalue('w', e);
if (p != NULL && (p = strchr(p, '.')) != NULL)
+ {
*p = '\0';
- define('w', macvalue('w', e), e);
+ macdefine(&e->e_macro, A_TEMP, 'w',
+ macvalue('w', e));
+ }
}
if (ConfigLevel >= 6)
{
- ColonOkInAddr = FALSE;
+ ColonOkInAddr = false;
}
/*
@@ -539,25 +594,28 @@ readcf(cfname, safe, e)
setuserenv(&bp[1], p);
break;
-#if _FFR_MILTER
case 'X': /* mail filter */
+#if MILTER
milter_setup(&bp[1]);
+#else /* MILTER */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Filter usage ('X') requires Milter support (-DMILTER)\n");
+#endif /* MILTER */
break;
-#endif /* _FFR_MILTER */
default:
badline:
syserr("unknown configuration line \"%s\"", bp);
}
if (bp != buf)
- sm_free(bp);
+ sm_free(bp); /* XXX */
}
- if (ferror(cf))
+ if (sm_io_error(cf))
{
syserr("I/O read error");
- finis(FALSE, EX_OSFILE);
+ finis(false, true, EX_OSFILE);
}
- (void) fclose(cf);
+ (void) sm_io_close(cf, SM_TIME_DEFAULT);
FileName = NULL;
/* initialize host maps from local service tables */
@@ -573,35 +631,21 @@ readcf(cfname, safe, e)
short mapreturn[MAXMAPACTIONS];
nmaps = switch_map_find("hosts", maptype, mapreturn);
- UseNameServer = FALSE;
+ UseNameServer = false;
if (nmaps > 0 && nmaps <= MAXMAPSTACK)
{
register int mapno;
- for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
+ for (mapno = 0; mapno < nmaps && !UseNameServer;
+ mapno++)
{
if (strcmp(maptype[mapno], "dns") == 0)
- UseNameServer = TRUE;
- }
- }
-
-#ifdef HESIOD
- nmaps = switch_map_find("passwd", maptype, mapreturn);
- UseHesiod = FALSE;
- if (nmaps > 0 && nmaps <= MAXMAPSTACK)
- {
- register int mapno;
-
- for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
- {
- if (strcmp(maptype[mapno], "hesiod") == 0)
- UseHesiod = TRUE;
+ UseNameServer = true;
}
}
-#endif /* HESIOD */
}
}
- /*
+/*
** TRANSLATE_DOLLARS -- convert $x into internal form
**
** Actually does all appropriate pre-processing of a config line
@@ -627,7 +671,6 @@ translate_dollars(bp)
{
if (*p == '#' && p > bp && ConfigLevel >= 3)
{
- /* this is an on-line comment */
register char *e;
switch (*--p & 0377)
@@ -639,7 +682,7 @@ translate_dollars(bp)
case '\\':
/* it's backslash escaped */
- (void) strlcpy(p, p + 1, strlen(p));
+ (void) sm_strlcpy(p, p + 1, strlen(p));
break;
default:
@@ -648,7 +691,7 @@ translate_dollars(bp)
*p != '\n' && p > bp)
p--;
if ((e = strchr(++p, '\n')) != NULL)
- (void) strlcpy(p, e, strlen(p));
+ (void) sm_strlcpy(p, e, strlen(p));
else
*p-- = '\0';
break;
@@ -662,7 +705,7 @@ translate_dollars(bp)
if (p[1] == '$')
{
/* actual dollar sign.... */
- (void) strlcpy(p, p + 1, strlen(p));
+ (void) sm_strlcpy(p, p + 1, strlen(p));
continue;
}
@@ -674,16 +717,16 @@ translate_dollars(bp)
p++;
/* convert macro name to code */
- *p = macid(p, &ep);
+ *p = macid_parse(p, &ep);
if (ep != p + 1)
- (void) strlcpy(p + 1, ep, strlen(p + 1));
+ (void) sm_strlcpy(p + 1, ep, strlen(p + 1));
}
/* strip trailing white space from the line */
while (--p > bp && isascii(*p) && isspace(*p))
*p = '\0';
}
- /*
+/*
** TOOMANY -- signal too many of some option
**
** Parameters:
@@ -704,7 +747,7 @@ toomany(id, maxcnt)
{
syserr("too many %c lines, %d max", id, maxcnt);
}
- /*
+/*
** FILECLASS -- read members of a class from a file
**
** Parameters:
@@ -719,11 +762,41 @@ toomany(id, maxcnt)
** none
**
** Side Effects:
-**
** puts all lines in filename that match a scanf into
** the named class.
*/
+/*
+** Break up the match into words and add to class.
+*/
+
+static void
+parse_class_words(class, line)
+ int class;
+ char *line;
+{
+ while (line != NULL && *line != '\0')
+ {
+ register char *q;
+
+ /* strip leading spaces */
+ while (isascii(*line) && isspace(*line))
+ line++;
+ if (*line == '\0')
+ break;
+
+ /* find the end of the word */
+ q = line;
+ while (*line != '\0' && !(isascii(*line) && isspace(*line)))
+ line++;
+ if (*line != '\0')
+ *line++ = '\0';
+
+ /* enter the word in the symbol table */
+ setclass(class, q);
+ }
+}
+
static void
fileclass(class, filename, fmt, safe, optional)
int class;
@@ -732,34 +805,166 @@ fileclass(class, filename, fmt, safe, optional)
bool safe;
bool optional;
{
- FILE *f;
+ SM_FILE_T *f;
long sff;
pid_t pid;
register char *p;
char buf[MAXLINE];
if (tTd(37, 2))
- dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
+ sm_dprintf("fileclass(%s, fmt=%s)\n", filename, fmt);
+
+ if (*filename == '\0')
+ {
+ syserr("fileclass: missing file name");
+ return;
+ }
+ else if (!SM_IS_DIR_DELIM(*filename) && *filename != '|' &&
+ (p = strchr(filename, '@')) != NULL)
+ {
+ int status = 0;
+ char *key;
+ char *mn;
+ char *cl, *spec;
+ STAB *mapclass;
+ MAP map;
+
+ mn = newstr(macname(class));
+
+ key = filename;
+
+ /* skip past '@' */
+ *p++ = '\0';
+ cl = p;
+
+ if (strcmp(cl, "LDAP") == 0)
+ {
+ int n;
+ char *lc;
+ char jbuf[MAXHOSTNAMELEN];
+ char lcbuf[MAXLINE];
+
+ /* Get $j */
+ expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
+ if (jbuf[0] == '\0')
+ {
+ (void) sm_strlcpy(jbuf, "localhost",
+ sizeof jbuf);
+ }
+
+ /* impose the default schema */
+ lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
+ if (lc == NULL)
+ lc = "";
+ else
+ {
+ expand(lc, lcbuf, sizeof lcbuf, CurEnv);
+ lc = lcbuf;
+ }
+
+ cl = "ldap";
+ n = sm_snprintf(buf, sizeof buf,
+ "-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=%s)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))) -v sendmailMTAClassValue",
+ mn, lc, jbuf);
+ if (n >= sizeof buf)
+ {
+ syserr("fileclass: F{%s}: Default LDAP string too long",
+ mn);
+ sm_free(mn);
+ return;
+ }
+ spec = buf;
+ }
+ else
+ {
+ if ((spec = strchr(cl, ':')) == NULL)
+ {
+ syserr("fileclass: F{%s}: missing map class",
+ mn);
+ sm_free(mn);
+ return;
+ }
+ *spec++ ='\0';
+ }
+
+ /* set up map structure */
+ mapclass = stab(cl, ST_MAPCLASS, ST_FIND);
+ if (mapclass == NULL)
+ {
+ syserr("fileclass: F{%s}: class %s not available",
+ mn, cl);
+ sm_free(mn);
+ return;
+ }
+ memset(&map, '\0', sizeof map);
+ map.map_class = &mapclass->s_mapclass;
+ map.map_mname = mn;
+ map.map_mflags |= MF_FILECLASS;
+
+ /* parse map spec */
+ if (!map.map_class->map_parse(&map, spec))
+ {
+ /* map_parse() showed the error already */
+ sm_free(mn);
+ return;
+ }
+ map.map_mflags |= MF_VALID;
+
+ /* open map */
+ if (map.map_class->map_open(&map, O_RDONLY))
+ {
+ map.map_mflags |= MF_OPEN;
+ map.map_pid = getpid();
+ }
+ else
+ {
+ if (!optional &&
+ !bitset(MF_OPTIONAL, map.map_mflags))
+ syserr("fileclass: F{%s}: map open failed",
+ mn);
+ sm_free(mn);
+ return;
+ }
+
+ /* lookup */
+ p = (*map.map_class->map_lookup)(&map, key, NULL, &status);
+ if (status != EX_OK && status != EX_NOTFOUND)
+ {
+ if (!optional)
+ syserr("fileclass: F{%s}: map lookup failed",
+ mn);
+ p = NULL;
+ }
+
+ /* use the results */
+ if (p != NULL)
+ parse_class_words(class, p);
- if (filename[0] == '|')
+ /* close map */
+ map.map_mflags |= MF_CLOSING;
+ map.map_class->map_close(&map);
+ map.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
+ sm_free(mn);
+ return;
+ }
+ else if (filename[0] == '|')
{
auto int fd;
int i;
char *argv[MAXPV + 1];
i = 0;
- for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
- {
- if (i >= MAXPV)
- break;
+ for (p = strtok(&filename[1], " \t");
+ p != NULL && i < MAXPV;
+ p = strtok(NULL, " \t"))
argv[i++] = p;
- }
argv[i] = NULL;
pid = prog_open(argv, &fd, CurEnv);
if (pid < 0)
f = NULL;
else
- f = fdopen(fd, "r");
+ f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &fd, SM_IO_RDONLY, NULL);
}
else
{
@@ -772,6 +977,8 @@ fileclass(class, filename, fmt, safe, optional)
sff |= SFF_NOWLINK;
if (safe)
sff |= SFF_OPENASROOT;
+ else if (RealUid == 0)
+ sff |= SFF_ROOTOK;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
f = safefopen(filename, O_RDONLY, 0, sff);
@@ -783,7 +990,7 @@ fileclass(class, filename, fmt, safe, optional)
return;
}
- while (fgets(buf, sizeof buf, f) != NULL)
+ while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
#if SCANF
char wordbuf[MAXLINE + 1];
@@ -792,44 +999,27 @@ fileclass(class, filename, fmt, safe, optional)
if (buf[0] == '#')
continue;
#if SCANF
- if (sscanf(buf, fmt, wordbuf) != 1)
+ if (sm_io_sscanf(buf, fmt, wordbuf) != 1)
continue;
p = wordbuf;
#else /* SCANF */
p = buf;
#endif /* SCANF */
+ parse_class_words(class, p);
+
/*
- ** Break up the match into words.
+ ** If anything else is added here,
+ ** check if the '@' map case above
+ ** needs the code as well.
*/
-
- while (*p != '\0')
- {
- register char *q;
-
- /* strip leading spaces */
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
-
- /* find the end of the word */
- q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
-
- /* enter the word in the symbol table */
- setclass(class, q);
- }
}
- (void) fclose(f);
+ (void) sm_io_close(f, SM_TIME_DEFAULT);
if (pid > 0)
(void) waitfor(pid);
}
- /*
+/*
** MAKEMAILER -- define a new mailer.
**
** Parameters:
@@ -844,12 +1034,14 @@ fileclass(class, filename, fmt, safe, optional)
** M -- the maximum message size
** N -- the niceness at which to run
** P -- the path to the mailer
+** Q -- the queue group for the mailer
** R -- the recipient rewriting set
** S -- the sender rewriting set
** T -- the mailer type (for DSNs)
** U -- the uid to run as
** W -- the time to wait at the end
** m -- maximum messages per connection
+** r -- maximum number of recipients per message
** / -- new root directory
** The first word is the canonical name of the mailer.
**
@@ -870,14 +1062,17 @@ makemailer(line)
int i;
char fcode;
auto char *endp;
- extern int NextMailer;
+ static int nextmailer = 0; /* "free" index into Mailer struct */
/* allocate a mailer and set up defaults */
m = (struct mailer *) xalloc(sizeof *m);
memset((char *) m, '\0', sizeof *m);
+ errno = 0; /* avoid bogus error text */
/* collect the mailer name */
- for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
+ for (p = line;
+ *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
+ p++)
continue;
if (*p != '\0')
*p++ = '\0';
@@ -893,7 +1088,8 @@ makemailer(line)
{
auto char *delimptr;
- while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
+ while (*p != '\0' &&
+ (*p == ',' || (isascii(*p) && isspace(*p))))
p++;
/* p now points to field code */
@@ -915,16 +1111,24 @@ makemailer(line)
switch (fcode)
{
case 'P': /* pathname */
- if (*p == '\0')
- syserr("mailer %s: empty path name", m->m_name);
- else
+ if (*p != '\0') /* error is issued below */
m->m_mailer = newstr(p);
break;
case 'F': /* flags */
for (; *p != '\0'; p++)
+ {
if (!(isascii(*p) && isspace(*p)))
+ {
+#if _FFR_DEPRECATE_MAILER_FLAG_I
+ if (*p == M_INTERNAL)
+ sm_syslog(LOG_WARNING, NOQID,
+ "WARNING: mailer=%s, flag=%c deprecated",
+ m->m_name, *p);
+#endif /* _FFR_DEPRECATE_MAILER_FLAG_I */
setbitn(bitidx(*p), m->m_flags);
+ }
+ }
break;
case 'S': /* sender rewriting ruleset */
@@ -959,10 +1163,7 @@ makemailer(line)
break;
case 'A': /* argument vector */
- if (*p == '\0')
- syserr("mailer %s: null argument vector",
- m->m_name);
- else
+ if (*p != '\0') /* error is issued below */
m->m_argv = makeargv(p);
break;
@@ -974,11 +1175,9 @@ makemailer(line)
m->m_maxdeliveries = atoi(p);
break;
-#if _FFR_DYNAMIC_TOBUF
case 'r': /* max recipient per envelope */
m->m_maxrcpt = atoi(p);
break;
-#endif /* _FFR_DYNAMIC_TOBUF */
case 'L': /* maximum line length */
m->m_linelimit = atoi(p);
@@ -1005,6 +1204,20 @@ makemailer(line)
m->m_defcharset = newstr(p);
break;
+ case 'Q': /* queue for this mailer */
+ if (*p == '\0')
+ {
+ syserr("mailer %s: null queue", m->m_name);
+ break;
+ }
+ s = stab(p, ST_QUEUE, ST_FIND);
+ if (s == NULL)
+ syserr("mailer %s: unknown queue %s",
+ m->m_name, p);
+ else
+ m->m_qgrp = s->s_quegrp->qg_index;
+ break;
+
case 'T': /* MTA-Name/Address/Diagnostic types */
/* extract MTA name type; default to "dns" */
m->m_mtatype = newstr(p);
@@ -1133,6 +1346,24 @@ makemailer(line)
p = delimptr;
}
+#if !HASRRESVPORT
+ if (bitnset(M_SECURE_PORT, m->m_flags))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "M%s: Warning: F=%c set on system that doesn't support rresvport()\n",
+ m->m_name, M_SECURE_PORT);
+ }
+#endif /* !HASRRESVPORT */
+
+#if !HASNICE
+ if (m->m_nice != 0)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "M%s: Warning: N= set on system that doesn't support nice()\n",
+ m->m_name);
+ }
+#endif /* !HASNICE */
+
/* do some rationality checking */
if (m->m_argv == NULL)
{
@@ -1145,16 +1376,14 @@ makemailer(line)
return;
}
- if (NextMailer >= MAXMAILERS)
+ if (nextmailer >= MAXMAILERS)
{
syserr("too many mailers defined (%d max)", MAXMAILERS);
return;
}
-#if _FFR_DYNAMIC_TOBUF
if (m->m_maxrcpt <= 0)
m->m_maxrcpt = DEFAULT_MAX_RCPT;
-#endif /* _FFR_DYNAMIC_TOBUF */
/* do some heuristic cleanup for back compatibility */
if (bitnset(M_LIMITS, m->m_flags))
@@ -1167,21 +1396,11 @@ makemailer(line)
if (strcmp(m->m_mailer, "[TCP]") == 0)
{
-#if _FFR_REMOVE_TCP_MAILER_PATH
- syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n",
- m->m_name);
+ syserr("M%s: P=[TCP] must be replaced by P=[IPC]", m->m_name);
return;
-#else /* _FFR_REMOVE_TCP_MAILER_PATH */
- printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n",
- m->m_name);
-#endif /* _FFR_REMOVE_TCP_MAILER_PATH */
}
- if (strcmp(m->m_mailer, "[IPC]") == 0
-#if !_FFR_REMOVE_TCP_MAILER_PATH
- || strcmp(m->m_mailer, "[TCP]") == 0
-#endif /* !_FFR_REMOVE_TCP_MAILER_PATH */
- )
+ if (strcmp(m->m_mailer, "[IPC]") == 0)
{
/* Use the second argument for host or path to socket */
if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
@@ -1195,21 +1414,30 @@ makemailer(line)
#if NETUNIX
&& strcmp(m->m_argv[0], "FILE") != 0
#endif /* NETUNIX */
-#if !_FFR_DEPRECATE_IPC_MAILER_ARG
- && strcmp(m->m_argv[0], "IPC") != 0
-#endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */
)
{
- printf("M%s: Warning: first argument in %s mailer must be %s\n",
- m->m_name, m->m_mailer,
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "M%s: Warning: first argument in %s mailer must be %s\n",
+ m->m_name, m->m_mailer,
#if NETUNIX
- "TCP or FILE"
+ "TCP or FILE"
#else /* NETUNIX */
- "TCP"
+ "TCP"
#endif /* NETUNIX */
- );
+ );
+ }
+ if (m->m_mtatype == NULL)
+ m->m_mtatype = "dns";
+ if (m->m_addrtype == NULL)
+ m->m_addrtype = "rfc822";
+ if (m->m_diagtype == NULL)
+ {
+ if (m->m_argv[0] != NULL &&
+ strcmp(m->m_argv[0], "FILE") == 0)
+ m->m_diagtype = "x-unix";
+ else
+ m->m_diagtype = "smtp";
}
-
}
else if (strcmp(m->m_mailer, "[FILE]") == 0)
{
@@ -1231,23 +1459,6 @@ makemailer(line)
}
}
- if (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0)
- {
- if (m->m_mtatype == NULL)
- m->m_mtatype = "dns";
- if (m->m_addrtype == NULL)
- m->m_addrtype = "rfc822";
- if (m->m_diagtype == NULL)
- {
- if (m->m_argv[0] != NULL &&
- strcmp(m->m_argv[0], "FILE") == 0)
- m->m_diagtype = "x-unix";
- else
- m->m_diagtype = "smtp";
- }
- }
-
if (m->m_eol == NULL)
{
char **pp;
@@ -1274,16 +1485,16 @@ makemailer(line)
if (s->s_mailer != NULL)
{
i = s->s_mailer->m_mno;
- sm_free(s->s_mailer);
+ sm_free(s->s_mailer); /* XXX */
}
else
{
- i = NextMailer++;
+ i = nextmailer++;
}
Mailer[i] = s->s_mailer = m;
m->m_mno = i;
}
- /*
+/*
** MUNCHSTRING -- translate a string into internal form.
**
** Parameters:
@@ -1307,8 +1518,8 @@ munchstring(p, delimptr, delim)
int delim;
{
register char *q;
- bool backslash = FALSE;
- bool quotemode = FALSE;
+ bool backslash = false;
+ bool quotemode = false;
static char buf[MAXLINE];
for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
@@ -1316,7 +1527,7 @@ munchstring(p, delimptr, delim)
if (backslash)
{
/* everything is roughly literal */
- backslash = FALSE;
+ backslash = false;
switch (*p)
{
case 'r': /* carriage return */
@@ -1340,7 +1551,7 @@ munchstring(p, delimptr, delim)
else
{
if (*p == '\\')
- backslash = TRUE;
+ backslash = true;
else if (*p == '"')
quotemode = !quotemode;
else if (quotemode || *p != delim)
@@ -1355,7 +1566,67 @@ munchstring(p, delimptr, delim)
*q++ = '\0';
return buf;
}
- /*
+/*
+** EXTRQUOTSTR -- extract a (quoted) string.
+**
+** This routine deals with quoted (") strings and escaped
+** spaces (\\ ).
+**
+** Parameters:
+** p -- source string.
+** delimptr -- if non-NULL, set to the pointer of the
+** field delimiter character.
+** delimbuf -- delimiters for the field.
+** st -- if non-NULL, store the return value (whether the
+** string was correctly quoted) here.
+**
+** Returns:
+** the extracted string.
+**
+** Side Effects:
+** the returned string is a local static buffer.
+** it must be copied before the function is called again.
+*/
+
+static char *
+extrquotstr(p, delimptr, delimbuf, st)
+ register char *p;
+ char **delimptr;
+ char *delimbuf;
+ bool *st;
+{
+ register char *q;
+ bool backslash = false;
+ bool quotemode = false;
+ static char buf[MAXLINE];
+
+ for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
+ {
+ if (backslash)
+ {
+ backslash = false;
+ if (*p != ' ')
+ *q++ = '\\';
+ }
+ if (*p == '\\')
+ backslash = true;
+ else if (*p == '"')
+ quotemode = !quotemode;
+ else if (quotemode ||
+ strchr(delimbuf, (int) *p) == NULL)
+ *q++ = *p;
+ else
+ break;
+ }
+
+ if (delimptr != NULL)
+ *delimptr = p;
+ *q++ = '\0';
+ if (st != NULL)
+ *st = !(quotemode || backslash);
+ return buf;
+}
+/*
** MAKEARGV -- break up a string into words
**
** Parameters:
@@ -1396,7 +1667,7 @@ makeargv(p)
return avp;
}
- /*
+/*
** PRINTRULES -- print rewrite rules (for debugging)
**
** Parameters:
@@ -1419,18 +1690,21 @@ printrules()
{
if (RewriteRules[ruleset] == NULL)
continue;
- printf("\n----Rule Set %d:", ruleset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\n----Rule Set %d:", ruleset);
for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
{
- printf("\nLHS:");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\nLHS:");
printav(rwp->r_lhs);
- printf("RHS:");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "RHS:");
printav(rwp->r_rhs);
}
}
}
- /*
+/*
** PRINTMAILER -- print mailer structure (for debugging)
**
** Parameters:
@@ -1446,54 +1720,68 @@ printmailer(m)
{
int j;
- printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "mailer %d (%s): P=%s S=", m->m_mno, m->m_name,
+ m->m_mailer);
if (RuleSetNames[m->m_se_rwset] == NULL)
- printf("%d/", m->m_se_rwset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/",
+ m->m_se_rwset);
else
- printf("%s/", RuleSetNames[m->m_se_rwset]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/",
+ RuleSetNames[m->m_se_rwset]);
if (RuleSetNames[m->m_sh_rwset] == NULL)
- printf("%d R=", m->m_sh_rwset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d R=",
+ m->m_sh_rwset);
else
- printf("%s R=", RuleSetNames[m->m_sh_rwset]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s R=",
+ RuleSetNames[m->m_sh_rwset]);
if (RuleSetNames[m->m_re_rwset] == NULL)
- printf("%d/", m->m_re_rwset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d/",
+ m->m_re_rwset);
else
- printf("%s/", RuleSetNames[m->m_re_rwset]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s/",
+ RuleSetNames[m->m_re_rwset]);
if (RuleSetNames[m->m_rh_rwset] == NULL)
- printf("%d ", m->m_rh_rwset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%d ",
+ m->m_rh_rwset);
else
- printf("%s ", RuleSetNames[m->m_rh_rwset]);
- printf("M=%ld U=%d:%d F=", m->m_maxsize,
- (int) m->m_uid, (int) m->m_gid);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s ",
+ RuleSetNames[m->m_rh_rwset]);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "M=%ld U=%d:%d F=",
+ m->m_maxsize, (int) m->m_uid, (int) m->m_gid);
for (j = '\0'; j <= '\177'; j++)
if (bitnset(j, m->m_flags))
- (void) putchar(j);
- printf(" L=%d E=", m->m_linelimit);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, j);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " L=%d E=",
+ m->m_linelimit);
xputs(m->m_eol);
if (m->m_defcharset != NULL)
- printf(" C=%s", m->m_defcharset);
- printf(" T=%s/%s/%s",
- m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
- m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
- m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
-#if _FFR_DYNAMIC_TOBUF
- printf(" r=%d", m->m_maxrcpt);
-#endif /* _FFR_DYNAMIC_TOBUF */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " C=%s",
+ m->m_defcharset);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " T=%s/%s/%s",
+ m->m_mtatype == NULL
+ ? "<undefined>" : m->m_mtatype,
+ m->m_addrtype == NULL
+ ? "<undefined>" : m->m_addrtype,
+ m->m_diagtype == NULL
+ ? "<undefined>" : m->m_diagtype);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " r=%d", m->m_maxrcpt);
if (m->m_argv != NULL)
{
char **a = m->m_argv;
- printf(" A=");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " A=");
while (*a != NULL)
{
if (a != m->m_argv)
- printf(" ");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " ");
xputs(*a++);
}
}
- printf("\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
}
- /*
+/*
** SETOPTION -- set global processing option
**
** Parameters:
@@ -1532,6 +1820,9 @@ static struct resolverflags
{ "defnames", RES_DEFNAMES },
{ "stayopen", RES_STAYOPEN },
{ "dnsrch", RES_DNSRCH },
+# ifdef RES_USE_INET6
+ { "use_inet6", RES_USE_INET6 },
+# endif /* RES_USE_INET6 */
{ "true", 0 }, /* avoid error on old syntax */
{ NULL, 0 }
};
@@ -1544,9 +1835,9 @@ static struct resolverflags
static struct optioninfo
{
- char *o_name; /* long name of option */
- u_char o_code; /* short name of option */
- u_short o_flags; /* option flags */
+ char *o_name; /* long name of option */
+ unsigned char o_code; /* short name of option */
+ unsigned short o_flags; /* option flags */
} OptionTab[] =
{
#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE)
@@ -1560,15 +1851,15 @@ static struct optioninfo
{ "MinFreeBlocks", 'b', OI_SAFE },
{ "CheckpointInterval", 'C', OI_SAFE },
{ "HoldExpensive", 'c', OI_NONE },
-#if !_FFR_REMOVE_AUTOREBUILD
- { "AutoRebuildAliases", 'D', OI_NONE },
-#endif /* !_FFR_REMOVE_AUTOREBUILD */
{ "DeliveryMode", 'd', OI_SAFE },
{ "ErrorHeader", 'E', OI_NONE },
{ "ErrorMode", 'e', OI_SAFE },
{ "TempFileMode", 'F', OI_NONE },
{ "SaveFromLine", 'f', OI_NONE },
{ "MatchGECOS", 'G', OI_NONE },
+
+ /* no long name, just here to avoid problems in setoption */
+ { "", 'g', OI_NONE },
{ "HelpFile", 'H', OI_NONE },
{ "MaxHopCount", 'h', OI_NONE },
{ "ResolverOptions", 'I', OI_NONE },
@@ -1580,6 +1871,9 @@ static struct optioninfo
{ "UseErrorsTo", 'l', OI_NONE },
{ "LogLevel", 'L', OI_SAFE },
{ "MeToo", 'm', OI_SAFE },
+
+ /* no long name, just here to avoid problems in setoption */
+ { "", 'M', OI_NONE },
{ "CheckAliases", 'n', OI_NONE },
{ "OldStyleHeaders", 'o', OI_SAFE },
{ "DaemonPortOptions", 'O', OI_NONE },
@@ -1704,49 +1998,92 @@ static struct optioninfo
{ "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE },
#define O_XF_BUFSIZE 0xb1
{ "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE },
-# define O_LDAPDEFAULTSPEC 0xb2
+#define O_LDAPDEFAULTSPEC 0xb2
{ "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE },
#if _FFR_QUEUEDELAY
-#define O_QUEUEDELAY 0xb3
+# define O_QUEUEDELAY 0xb3
{ "QueueDelay", O_QUEUEDELAY, OI_NONE },
#endif /* _FFR_QUEUEDELAY */
-# define O_SRVCERTFILE 0xb4
+#define O_SRVCERTFILE 0xb4
{ "ServerCertFile", O_SRVCERTFILE, OI_NONE },
-# define O_SRVKEYFILE 0xb5
+#define O_SRVKEYFILE 0xb5
{ "Serverkeyfile", O_SRVKEYFILE, OI_NONE },
-# define O_CLTCERTFILE 0xb6
+#define O_CLTCERTFILE 0xb6
{ "ClientCertFile", O_CLTCERTFILE, OI_NONE },
-# define O_CLTKEYFILE 0xb7
+#define O_CLTKEYFILE 0xb7
{ "Clientkeyfile", O_CLTKEYFILE, OI_NONE },
-# define O_CACERTFILE 0xb8
+#define O_CACERTFILE 0xb8
{ "CACERTFile", O_CACERTFILE, OI_NONE },
-# define O_CACERTPATH 0xb9
+#define O_CACERTPATH 0xb9
{ "CACERTPath", O_CACERTPATH, OI_NONE },
-# define O_DHPARAMS 0xba
+#define O_DHPARAMS 0xba
{ "DHParameters", O_DHPARAMS, OI_NONE },
-#if _FFR_MILTER
#define O_INPUTMILTER 0xbb
{ "InputMailFilters", O_INPUTMILTER, OI_NONE },
#define O_MILTER 0xbc
{ "Milter", O_MILTER, OI_SUBOPT },
-#endif /* _FFR_MILTER */
#define O_SASLOPTS 0xbd
{ "AuthOptions", O_SASLOPTS, OI_NONE },
-#if _FFR_QUEUE_FILE_MODE
#define O_QUEUE_FILE_MODE 0xbe
{ "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE },
-#endif /* _FFR_QUEUE_FILE_MODE */
-# if _FFR_TLS_1
+#if _FFR_TLS_1
# define O_DHPARAMS5 0xbf
{ "DHParameters512", O_DHPARAMS5, OI_NONE },
# define O_CIPHERLIST 0xc0
{ "CipherList", O_CIPHERLIST, OI_NONE },
-# endif /* _FFR_TLS_1 */
-# define O_RANDFILE 0xc1
+#endif /* _FFR_TLS_1 */
+#define O_RANDFILE 0xc1
{ "RandFile", O_RANDFILE, OI_NONE },
+#define O_TLS_SRV_OPTS 0xc2
+ { "TLSSrvOptions", O_TLS_SRV_OPTS, OI_NONE },
+#define O_RCPTTHROT 0xc3
+ { "BadRcptThrottle", O_RCPTTHROT, OI_SAFE },
+#define O_DLVR_MIN 0xc4
+ { "DeliverByMin", O_DLVR_MIN, OI_NONE },
+#define O_MAXQUEUECHILDREN 0xc5
+ { "MaxQueueChildren", O_MAXQUEUECHILDREN, OI_NONE },
+#define O_MAXRUNNERSPERQUEUE 0xc6
+ { "MaxRunnersPerQueue", O_MAXRUNNERSPERQUEUE, OI_NONE },
+#define O_DIRECTSUBMODIFIERS 0xc7
+ { "DirectSubmissionModifiers", O_DIRECTSUBMODIFIERS, OI_NONE },
+#define O_NICEQUEUERUN 0xc8
+ { "NiceQueueRun", O_NICEQUEUERUN, OI_NONE },
+#define O_SHMKEY 0xc9
+ { "SharedMemoryKey", O_SHMKEY, OI_NONE },
+#define O_SASLBITS 0xca
+ { "AuthMaxBits", O_SASLBITS, OI_NONE },
+#define O_MBDB 0xcb
+ { "MailboxDatabase", O_MBDB, OI_NONE },
+#define O_MSQ 0xcc
+ { "UseMSP", O_MSQ, OI_NONE },
+#define O_DELAY_LA 0xcd
+ { "DelayLA", O_DELAY_LA, OI_NONE },
+#define O_FASTSPLIT 0xce
+ { "FastSplit", O_FASTSPLIT, OI_NONE },
+#if _FFR_SOFT_BOUNCE
+# define O_SOFTBOUNCE 0xcf
+ { "SoftBounce", O_SOFTBOUNCE, OI_NONE },
+#endif /* _FFR_SOFT_BOUNCE */
{ NULL, '\0', OI_NONE }
};
+# define CANONIFY(val)
+
+# define SET_OPT_DEFAULT(opt, val) opt = val
+
+/* set a string option by expanding the value and assigning it */
+/* WARNING this belongs ONLY into a case statement! */
+#define SET_STRING_EXP(str) \
+ expand(val, exbuf, sizeof exbuf, e); \
+ newval = sm_pstrdup_x(exbuf); \
+ if (str != NULL) \
+ sm_free(str); \
+ CANONIFY(newval); \
+ str = newval; \
+ break
+
+#define OPTNAME o->o_name == NULL ? "<unknown>" : o->o_name
+
void
setoption(opt, val, safe, sticky, e)
int opt;
@@ -1764,8 +2101,12 @@ setoption(opt, val, safe, sticky, e)
char buf[50];
extern bool Warn_Q_option;
#if _FFR_ALLOW_SASLINFO
- extern int SubmitMode;
+ extern unsigned int SubmitMode;
#endif /* _FFR_ALLOW_SASLINFO */
+#if STARTTLS
+ char *newval;
+ char exbuf[MAXLINE];
+#endif /* STARTTLS */
errno = 0;
if (opt == ' ')
@@ -1795,7 +2136,7 @@ setoption(opt, val, safe, sticky, e)
sel = NULL;
for (o = OptionTab; o->o_name != NULL; o++)
{
- if (strncasecmp(o->o_name, val, strlen(val)) != 0)
+ if (sm_strncasecmp(o->o_name, val, strlen(val)) != 0)
continue;
if (strlen(o->o_name) == strlen(val))
{
@@ -1839,27 +2180,29 @@ setoption(opt, val, safe, sticky, e)
if (o->o_code == opt)
break;
}
+ if (o->o_name == NULL)
+ {
+ syserr("readcf: unknown option name 0x%x", opt & 0xff);
+ return;
+ }
subopt = NULL;
}
if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags))
{
if (tTd(37, 1))
- dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
- o->o_name == NULL ? "<unknown>" : o->o_name,
- subopt);
+ sm_dprintf("setoption: %s does not support suboptions, ignoring .%s\n",
+ OPTNAME, subopt);
subopt = NULL;
}
if (tTd(37, 1))
{
- dprintf(isascii(opt) && isprint(opt) ?
- "setoption %s (%c)%s%s=" :
- "setoption %s (0x%x)%s%s=",
- o->o_name == NULL ? "<unknown>" : o->o_name,
- opt,
- subopt == NULL ? "" : ".",
- subopt == NULL ? "" : subopt);
+ sm_dprintf(isascii(opt) && isprint(opt) ?
+ "setoption %s (%c)%s%s=" :
+ "setoption %s (0x%x)%s%s=",
+ OPTNAME, opt, subopt == NULL ? "" : ".",
+ subopt == NULL ? "" : subopt);
xputs(val);
}
@@ -1870,7 +2213,7 @@ setoption(opt, val, safe, sticky, e)
if (!sticky && bitnset(opt, StickyOpt))
{
if (tTd(37, 1))
- dprintf(" (ignored)\n");
+ sm_dprintf(" (ignored)\n");
return;
}
@@ -1879,7 +2222,7 @@ setoption(opt, val, safe, sticky, e)
*/
if (!safe && RealUid == 0)
- safe = TRUE;
+ safe = true;
if (!safe && !bitset(OI_SAFE, o->o_flags))
{
if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
@@ -1887,13 +2230,13 @@ setoption(opt, val, safe, sticky, e)
int dp;
if (tTd(37, 1))
- dprintf(" (unsafe)");
- dp = drop_privileges(TRUE);
+ sm_dprintf(" (unsafe)");
+ dp = drop_privileges(true);
setstat(dp);
}
}
if (tTd(37, 1))
- dprintf("\n");
+ sm_dprintf("\n");
switch (opt & 0xff)
{
@@ -1905,14 +2248,14 @@ setoption(opt, val, safe, sticky, e)
#if MIME8TO7
switch (*val)
{
- case 'm': /* convert 8-bit, convert MIME */
- MimeMode = MM_CVTMIME|MM_MIME8BIT;
- break;
-
case 'p': /* pass 8 bit, convert MIME */
MimeMode = MM_CVTMIME|MM_PASS8BIT;
break;
+ case 'm': /* convert 8-bit, convert MIME */
+ MimeMode = MM_CVTMIME|MM_MIME8BIT;
+ break;
+
case 's': /* strict adherence */
MimeMode = MM_CVTMIME;
break;
@@ -1937,23 +2280,30 @@ setoption(opt, val, safe, sticky, e)
default:
syserr("Unknown 8-bit mode %c", *val);
- finis(FALSE, EX_USAGE);
+ finis(false, true, EX_USAGE);
}
#else /* MIME8TO7 */
- printf("Warning: Option EightBitMode requires MIME8TO7 support\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires MIME8TO7 support\n",
+ OPTNAME);
#endif /* MIME8TO7 */
break;
case 'A': /* set default alias file */
if (val[0] == '\0')
- setalias("aliases");
+ {
+ char *al;
+
+ SET_OPT_DEFAULT(al, "aliases");
+ setalias(al);
+ }
else
setalias(val);
break;
case 'a': /* look N minutes for "@:@" in alias file */
if (val[0] == '\0')
- SafeAlias = 5 * 60; /* five minutes */
+ SafeAlias = 5 MINUTES;
else
SafeAlias = convtime(val, 'm');
break;
@@ -1991,12 +2341,6 @@ setoption(opt, val, safe, sticky, e)
case SM_QUEUE: /* queue only */
case SM_DEFER: /* queue only and defer map lookups */
-#if !QUEUE
- syserr("need QUEUE to set -odqueue or -oddefer");
- break;
-#endif /* !QUEUE */
- /* FALLTHROUGH */
-
case SM_DELIVER: /* do everything */
case SM_FORK: /* fork after verification */
set_delivery_mode(*val, e);
@@ -2004,16 +2348,10 @@ setoption(opt, val, safe, sticky, e)
default:
syserr("Unknown delivery mode %c", *val);
- finis(FALSE, EX_USAGE);
+ finis(false, true, EX_USAGE);
}
break;
-#if !_FFR_REMOVE_AUTOREBUILD
- case 'D': /* rebuild alias database as needed */
- AutoRebuild = atobool(val);
- break;
-#endif /* !_FFR_REMOVE_AUTOREBUILD */
-
case 'E': /* error message header/header file */
if (*val != '\0')
ErrMsgFile = newstr(val);
@@ -2064,9 +2402,12 @@ setoption(opt, val, safe, sticky, e)
case 'H': /* help file */
if (val[0] == '\0')
- HelpFile = "helpfile";
+ {
+ SET_OPT_DEFAULT(HelpFile, "helpfile");
+ }
else
{
+ CANONIFY(val);
HelpFile = newstr(val);
}
break;
@@ -2087,9 +2428,9 @@ setoption(opt, val, safe, sticky, e)
p++;
if (*p == '\0')
break;
- clearmode = FALSE;
+ clearmode = false;
if (*p == '-')
- clearmode = TRUE;
+ clearmode = true;
else if (*p != '+')
p--;
p++;
@@ -2098,21 +2439,19 @@ setoption(opt, val, safe, sticky, e)
p++;
if (*p != '\0')
*p++ = '\0';
- if (strcasecmp(q, "HasWildcardMX") == 0)
+ if (sm_strcasecmp(q, "HasWildcardMX") == 0)
{
HasWildcardMX = !clearmode;
continue;
}
-#if _FFR_WORKAROUND_BROKEN_NAMESERVERS
if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
{
WorkAroundBrokenAAAA = !clearmode;
continue;
}
-#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */
for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
{
- if (strcasecmp(q, rfp->rf_name) == 0)
+ if (sm_strcasecmp(q, rfp->rf_name) == 0)
break;
}
if (rfp->rf_name == NULL)
@@ -2123,8 +2462,8 @@ setoption(opt, val, safe, sticky, e)
_res.options |= rfp->rf_bits;
}
if (tTd(8, 2))
- dprintf("_res.options = %x, HasWildcardMX = %d\n",
- (u_int) _res.options, HasWildcardMX);
+ sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
+ (unsigned int) _res.options, HasWildcardMX);
#else /* NAMED_BIND */
usrerr("name server (I option) specified but BIND not compiled in");
#endif /* NAMED_BIND */
@@ -2139,6 +2478,7 @@ setoption(opt, val, safe, sticky, e)
break;
case 'J': /* .forward search path */
+ CANONIFY(val);
ForwardPath = newstr(val);
break;
@@ -2162,14 +2502,14 @@ setoption(opt, val, safe, sticky, e)
break;
case 'M': /* define macro */
- sticky = FALSE;
- mid = macid(val, &ep);
+ sticky = false;
+ mid = macid_parse(val, &ep);
if (mid == 0)
break;
p = newstr(ep);
if (!safe)
cleanstrcpy(p, p, MAXNAME);
- define(mid, p, CurEnv);
+ macdefine(&CurEnv->e_macro, A_TEMP, mid, p);
break;
case 'm': /* send to me too */
@@ -2183,12 +2523,8 @@ setoption(opt, val, safe, sticky, e)
/* 'N' available -- was "net name" */
case 'O': /* daemon options */
-#if DAEMON
if (!setdaemonoptions(val))
syserr("too many daemons defined (%d max)", MAXDAEMONS);
-#else /* DAEMON */
- syserr("DaemonPortOptions (O option) set but DAEMON not compiled in");
-#endif /* DAEMON */
break;
case 'o': /* assume old style headers */
@@ -2217,7 +2553,7 @@ setoption(opt, val, safe, sticky, e)
for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
{
- if (strcasecmp(val, pv->pv_name) == 0)
+ if (sm_strcasecmp(val, pv->pv_name) == 0)
break;
}
if (pv->pv_name == NULL)
@@ -2225,7 +2561,7 @@ setoption(opt, val, safe, sticky, e)
else
PrivacyFlags |= pv->pv_flag;
}
- sticky = FALSE;
+ sticky = false;
break;
case 'P': /* postmaster copy address for returned mail */
@@ -2246,7 +2582,7 @@ setoption(opt, val, safe, sticky, e)
QueueDir = newstr(val);
}
if (RealUid != 0 && !safe)
- Warn_Q_option = TRUE;
+ Warn_Q_option = true;
break;
case 'R': /* don't prune routes */
@@ -2262,15 +2598,21 @@ setoption(opt, val, safe, sticky, e)
case 'S': /* status file */
if (val[0] == '\0')
- StatFile = "statistics";
+ {
+ SET_OPT_DEFAULT(StatFile, "statistics");
+ }
else
{
+ CANONIFY(val);
StatFile = newstr(val);
}
break;
case 's': /* be super safe, even if expensive */
- SuperSafe = atobool(val);
+ if (tolower(*val) == 'i')
+ SuperSafe = SAFE_INTERACTIVE;
+ else
+ SuperSafe = atobool(val) ? SAFE_REALLY : SAFE_NO;
break;
case 'T': /* queue timeout */
@@ -2294,7 +2636,11 @@ setoption(opt, val, safe, sticky, e)
case 'u': /* set default uid */
for (p = val; *p != '\0'; p++)
{
+#if _FFR_DOTTED_USERNAMES
+ if (*p == '/' || *p == ':')
+#else /* _FFR_DOTTED_USERNAMES */
if (*p == '.' || *p == '/' || *p == ':')
+#endif /* _FFR_DOTTED_USERNAMES */
{
*p++ = '\0';
break;
@@ -2324,14 +2670,14 @@ setoption(opt, val, safe, sticky, e)
}
}
-#ifdef UID_MAX
+# ifdef UID_MAX
if (DefUid > UID_MAX)
{
syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
- (long) DefUid, (long) UID_MAX);
+ (long)DefUid, (long)UID_MAX);
break;
}
-#endif /* UID_MAX */
+# endif /* UID_MAX */
/* handle the group if it is there */
if (*p == '\0')
@@ -2358,10 +2704,14 @@ setoption(opt, val, safe, sticky, e)
QueueLA = atoi(val);
break;
- case 'X': /* load avg at which to auto-reject connections */
+ case 'X': /* load avg at which to auto-reject connections */
RefuseLA = atoi(val);
break;
+ case O_DELAY_LA: /* load avg at which to delay connections */
+ DelayLA = atoi(val);
+ break;
+
case 'y': /* work recipient factor */
WkRecipFact = atoi(val);
break;
@@ -2382,11 +2732,21 @@ setoption(opt, val, safe, sticky, e)
case O_QUEUESORTORD: /* queue sorting order */
switch (*val)
{
+ case 'f': /* File Name */
+ case 'F':
+ QueueSortOrder = QSO_BYFILENAME;
+ break;
+
case 'h': /* Host first */
case 'H':
QueueSortOrder = QSO_BYHOST;
break;
+ case 'm': /* Modification time */
+ case 'M':
+ QueueSortOrder = QSO_BYMODTIME;
+ break;
+
case 'p': /* Priority order */
case 'P':
QueueSortOrder = QSO_BYPRIORITY;
@@ -2397,10 +2757,17 @@ setoption(opt, val, safe, sticky, e)
QueueSortOrder = QSO_BYTIME;
break;
- case 'f': /* File Name */
- case 'F':
- QueueSortOrder = QSO_BYFILENAME;
+ case 'r': /* Random */
+ case 'R':
+ QueueSortOrder = QSO_RANDOM;
+ break;
+
+#if _FFR_RHS
+ case 's': /* Shuffled host name */
+ case 'S':
+ QueueSortOrder = QSO_BYSHUFFLE;
break;
+#endif /* _FFR_RHS */
default:
syserr("Invalid queue sort order \"%s\"", val);
@@ -2445,6 +2812,7 @@ setoption(opt, val, safe, sticky, e)
#endif /* _FFR_QUEUEDELAY */
case O_HOSTSFILE: /* pathname of /etc/hosts file */
+ CANONIFY(val);
HostsFile = newstr(val);
break;
@@ -2453,10 +2821,11 @@ setoption(opt, val, safe, sticky, e)
break;
case O_DEFCHARSET: /* default character set for mimefying */
- DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
+ DefaultCharSet = newstr(denlstring(val, true, true));
break;
case O_SSFILE: /* service switch file */
+ CANONIFY(val);
ServiceSwitchFile = newstr(val);
break;
@@ -2465,15 +2834,15 @@ setoption(opt, val, safe, sticky, e)
break;
case O_NORCPTACTION: /* what to do if no recipient */
- if (strcasecmp(val, "none") == 0)
+ if (sm_strcasecmp(val, "none") == 0)
NoRecipientAction = NRA_NO_ACTION;
- else if (strcasecmp(val, "add-to") == 0)
+ else if (sm_strcasecmp(val, "add-to") == 0)
NoRecipientAction = NRA_ADD_TO;
- else if (strcasecmp(val, "add-apparently-to") == 0)
+ else if (sm_strcasecmp(val, "add-apparently-to") == 0)
NoRecipientAction = NRA_ADD_APPARENTLY_TO;
- else if (strcasecmp(val, "add-bcc") == 0)
+ else if (sm_strcasecmp(val, "add-bcc") == 0)
NoRecipientAction = NRA_ADD_BCC;
- else if (strcasecmp(val, "add-to-undisclosed") == 0)
+ else if (sm_strcasecmp(val, "add-to-undisclosed") == 0)
NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
else
syserr("Invalid NoRecipientAction: %s", val);
@@ -2492,13 +2861,41 @@ setoption(opt, val, safe, sticky, e)
break;
case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
- MaxQueueRun = atol(val);
+ MaxQueueRun = atoi(val);
break;
case O_MAXCHILDREN: /* max # of children of daemon */
MaxChildren = atoi(val);
break;
+ case O_MAXQUEUECHILDREN: /* max # of children of daemon */
+ MaxQueueChildren = atoi(val);
+ break;
+
+ case O_MAXRUNNERSPERQUEUE: /* max # runners in a queue group */
+ MaxRunnersPerQueue = atoi(val);
+ break;
+
+ case O_NICEQUEUERUN: /* nice queue runs */
+#if !HASNICE
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: NiceQueueRun set on system that doesn't support nice()\n");
+#endif /* !HASNICE */
+
+ /* XXX do we want to check the range? > 0 ? */
+ NiceQueueRun = atoi(val);
+ break;
+
+ case O_SHMKEY : /* shared memory key */
+#if SM_CONF_SHM
+ ShmKey = atol(val);
+#else /* SM_CONF_SHM */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires shared memory support (-DSM_CONF_SHM)\n",
+ OPTNAME);
+#endif /* SM_CONF_SHM */
+ break;
+
#if _FFR_MAX_FORWARD_ENTRIES
case O_MAXFORWARD: /* max # of forward entries */
MaxForwardEntries = atoi(val);
@@ -2510,11 +2907,12 @@ setoption(opt, val, safe, sticky, e)
break;
case O_MUSTQUOTE: /* must quote these characters in phrases */
- (void) strlcpy(buf, "@,;:\\()[]", sizeof buf);
- if (strlen(val) < (SIZE_T) sizeof buf - 10)
- (void) strlcat(buf, val, sizeof buf);
+ (void) sm_strlcpy(buf, "@,;:\\()[]", sizeof buf);
+ if (strlen(val) < sizeof buf - 10)
+ (void) sm_strlcat(buf, val, sizeof buf);
else
- printf("Warning: MustQuoteChars too long, ignored.\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: MustQuoteChars too long, ignored.\n");
MustQuoteChars = newstr(buf);
break;
@@ -2528,7 +2926,8 @@ setoption(opt, val, safe, sticky, e)
case O_OPCHARS: /* operator characters (old $o macro) */
if (OperatorChars != NULL)
- printf("Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n");
OperatorChars = newstr(munchstring(val, NULL, '\0'));
break;
@@ -2559,15 +2958,13 @@ setoption(opt, val, safe, sticky, e)
break;
case O_DBLBOUNCE: /* address to which to send double bounces */
- if (val[0] != '\0')
- DoubleBounceAddr = newstr(val);
- else
- syserr("readcf: option DoubleBounceAddress: value required");
+ DoubleBounceAddr = newstr(val);
break;
case O_HSDIR: /* persistent host status directory */
if (val[0] != '\0')
{
+ CANONIFY(val);
HostStatDir = newstr(val);
}
break;
@@ -2579,7 +2976,11 @@ setoption(opt, val, safe, sticky, e)
case O_RUNASUSER: /* run bulk of code as this user */
for (p = val; *p != '\0'; p++)
{
+#if _FFR_DOTTED_USERNAMES
+ if (*p == '/' || *p == ':')
+#else /* _FFR_DOTTED_USERNAMES */
if (*p == '.' || *p == '/' || *p == ':')
+#endif /* _FFR_DOTTED_USERNAMES */
{
*p++ = '\0';
break;
@@ -2607,21 +3008,37 @@ setoption(opt, val, safe, sticky, e)
RunAsUid = pw->pw_uid;
RunAsGid = pw->pw_gid;
}
+ else if (EffGid == pw->pw_gid)
+ RunAsGid = pw->pw_gid;
+ else if (UseMSP && *p == '\0')
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
+ (int) EffGid,
+ (int) pw->pw_gid);
}
-#ifdef UID_MAX
+# ifdef UID_MAX
if (RunAsUid > UID_MAX)
{
syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
(long) RunAsUid, (long) UID_MAX);
break;
}
-#endif /* UID_MAX */
+# endif /* UID_MAX */
if (*p != '\0')
{
if (isascii(*p) && isdigit(*p))
{
- if (can_setuid)
- RunAsGid = atoi(p);
+ gid_t runasgid;
+
+ runasgid = (gid_t) atoi(p);
+ if (can_setuid || EffGid == runasgid)
+ RunAsGid = runasgid;
+ else if (UseMSP)
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
+ (int) EffGid,
+ (int) runasgid);
}
else
{
@@ -2631,13 +3048,19 @@ setoption(opt, val, safe, sticky, e)
if (gr == NULL)
syserr("readcf: option RunAsUser: unknown group %s",
p);
- else if (can_setuid)
+ else if (can_setuid || EffGid == gr->gr_gid)
RunAsGid = gr->gr_gid;
+ else if (UseMSP)
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "WARNING: RunAsGid for MSP ignored, check group ids (egid=%d, want=%d)\n",
+ (int) EffGid,
+ (int) gr->gr_gid);
}
}
if (tTd(47, 5))
- dprintf("readcf: RunAsUser = %d:%d\n",
- (int)RunAsUid, (int)RunAsGid);
+ sm_dprintf("readcf: RunAsUser = %d:%d\n",
+ (int) RunAsUid, (int) RunAsGid);
break;
case O_DSN_RRT:
@@ -2645,12 +3068,10 @@ setoption(opt, val, safe, sticky, e)
break;
case O_PIDFILE:
- if (PidFile != NULL)
- sm_free(PidFile);
- PidFile = newstr(val);
+ PSTRSET(PidFile, val);
break;
- case O_DONTBLAMESENDMAIL:
+ case O_DONTBLAMESENDMAIL:
p = val;
for (;;)
{
@@ -2670,7 +3091,7 @@ setoption(opt, val, safe, sticky, e)
for (dbs = DontBlameSendmailValues;
dbs->dbs_name != NULL; dbs++)
{
- if (strcasecmp(val, dbs->dbs_name) == 0)
+ if (sm_strcasecmp(val, dbs->dbs_name) == 0)
break;
}
if (dbs->dbs_name == NULL)
@@ -2680,21 +3101,29 @@ setoption(opt, val, safe, sticky, e)
else
setbitn(dbs->dbs_flag, DontBlameSendmail);
}
- sticky = FALSE;
+ sticky = false;
break;
case O_DPI:
- DontProbeInterfaces = atobool(val);
+ if (sm_strcasecmp(val, "loopback") == 0)
+ DontProbeInterfaces = DPI_SKIPLOOPBACK;
+ else if (atobool(val))
+ DontProbeInterfaces = DPI_PROBENONE;
+ else
+ DontProbeInterfaces = DPI_PROBEALL;
break;
case O_MAXRCPT:
MaxRcptPerMsg = atoi(val);
break;
+ case O_RCPTTHROT:
+ BadRcptThrottle = atoi(val);
+ break;
+
case O_DEADLETTER:
- if (DeadLetterDrop != NULL)
- sm_free(DeadLetterDrop);
- DeadLetterDrop = newstr(val);
+ CANONIFY(val);
+ PSTRSET(DeadLetterDrop, val);
break;
#if _FFR_DONTLOCKFILESFORREAD_OPTION
@@ -2710,26 +3139,36 @@ setoption(opt, val, safe, sticky, e)
case O_CNCTONLYTO:
/* XXX should probably use gethostbyname */
#if NETINET || NETINET6
+ ConnectOnlyTo.sa.sa_family = AF_UNSPEC;
# if NETINET6
- if (inet_addr(val) == INADDR_NONE)
- {
+ if (anynet_pton(AF_INET6, val,
+ &ConnectOnlyTo.sin6.sin6_addr) != 1)
ConnectOnlyTo.sa.sa_family = AF_INET6;
- if (inet_pton(AF_INET6, val,
- &ConnectOnlyTo.sin6.sin6_addr) != 1)
- syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
- val);
- }
else
# endif /* NETINET6 */
+# if NETINET
{
- ConnectOnlyTo.sa.sa_family = AF_INET;
ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val);
+ if (ConnectOnlyTo.sin.sin_addr.s_addr != INADDR_NONE)
+ ConnectOnlyTo.sa.sa_family = AF_INET;
+ }
+
+# endif /* NETINET */
+ if (ConnectOnlyTo.sa.sa_family == AF_UNSPEC)
+ {
+ syserr("readcf: option ConnectOnlyTo: invalid IP address %s",
+ val);
+ break;
}
#endif /* NETINET || NETINET6 */
break;
case O_TRUSTUSER:
-#if HASFCHOWN
+# if !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING)
+ if (!UseMSP)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "readcf: option TrustedUser may cause problems on systems\n which do not support fchown() if UseMSP is not set.\n");
+# endif /* !HASFCHOWN && !defined(_FFR_DROP_TRUSTUSER_WARNING) */
if (isascii(*val) && isdigit(*val))
TrustedUid = atoi(val);
else
@@ -2755,9 +3194,6 @@ setoption(opt, val, safe, sticky, e)
TrustedUid = 0;
}
# endif /* UID_MAX */
-#else /* HASFCHOWN */
- syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()");
-#endif /* HASFCHOWN */
break;
case O_MAXMIMEHDRLEN:
@@ -2773,18 +3209,18 @@ setoption(opt, val, safe, sticky, e)
if (MaxMimeHeaderLength < 0)
MaxMimeHeaderLength = 0;
else if (MaxMimeHeaderLength < 128)
- printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
if (MaxMimeFieldLength < 0)
MaxMimeFieldLength = 0;
else if (MaxMimeFieldLength < 40)
- printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
break;
case O_CONTROLSOCKET:
- if (ControlSocketName != NULL)
- sm_free(ControlSocketName);
- ControlSocketName = newstr(val);
+ PSTRSET(ControlSocketName, val);
break;
case O_MAXHDRSLEN:
@@ -2792,20 +3228,23 @@ setoption(opt, val, safe, sticky, e)
if (MaxHeadersLength > 0 &&
MaxHeadersLength < (MAXHDRSLEN / 2))
- printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", (MAXHDRSLEN / 2));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: MaxHeadersLength: headers length limit set lower than %d\n",
+ (MAXHDRSLEN / 2));
break;
case O_PROCTITLEPREFIX:
- if (ProcTitlePrefix != NULL)
- sm_free(ProcTitlePrefix);
- ProcTitlePrefix = newstr(val);
+ PSTRSET(ProcTitlePrefix, val);
break;
#if SASL
case O_SASLINFO:
-#if _FFR_ALLOW_SASLINFO
+# if _FFR_ALLOW_SASLINFO
/*
- ** Allow users to select their own authinfo file.
+ ** Allow users to select their own authinfo file
+ ** under certain circumstances, otherwise just ignore
+ ** the option. If the option isn't ignored, several
+ ** commands don't work very well, e.g., mailq.
** However, this is not a "perfect" solution.
** If mail is queued, the authentication info
** will not be used in subsequent delivery attempts.
@@ -2814,22 +3253,14 @@ setoption(opt, val, safe, sticky, e)
*/
if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 &&
RunAsUid != RealUid)
- {
- errno = 0;
- syserr("Error: %s only allowed with -U\n",
- o->o_name == NULL ? "<unknown>" : o->o_name);
- ExitStat = EX_USAGE;
break;
- }
-#endif /* _FFR_ALLOW_SASLINFO */
- if (SASLInfo != NULL)
- sm_free(SASLInfo);
- SASLInfo = newstr(val);
+# endif /* _FFR_ALLOW_SASLINFO */
+ PSTRSET(SASLInfo, val);
break;
case O_SASLMECH:
if (AuthMechanisms != NULL)
- sm_free(AuthMechanisms);
+ sm_free(AuthMechanisms); /* XXX */
if (*val != '\0')
AuthMechanisms = newstr(val);
else
@@ -2839,12 +3270,11 @@ setoption(opt, val, safe, sticky, e)
case O_SASLOPTS:
while (val != NULL && *val != '\0')
{
- switch(*val)
+ switch (*val)
{
case 'A':
SASLOpts |= SASL_AUTH_AUTH;
break;
-# if _FFR_SASL_OPTS
case 'a':
SASLOpts |= SASL_SEC_NOACTIVE;
break;
@@ -2863,13 +3293,17 @@ setoption(opt, val, safe, sticky, e)
case 'y':
SASLOpts |= SASL_SEC_NOANONYMOUS;
break;
-# endif /* _FFR_SASL_OPTS */
+ case ' ': /* ignore */
+ case '\t': /* ignore */
+ case ',': /* ignore */
+ break;
default:
- printf("Warning: Option: %s unknown parameter '%c'\n",
- o->o_name == NULL ? "<unknown>"
- : o->o_name,
- (isascii(*val) && isprint(*val)) ? *val
- : '?');
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s unknown parameter '%c'\n",
+ OPTNAME,
+ (isascii(*val) &&
+ isprint(*val))
+ ? *val : '?');
break;
}
++val;
@@ -2878,80 +3312,99 @@ setoption(opt, val, safe, sticky, e)
++val;
}
break;
+ case O_SASLBITS:
+ MaxSLBits = atoi(val);
+ break;
#else /* SASL */
case O_SASLINFO:
case O_SASLMECH:
case O_SASLOPTS:
- printf("Warning: Option: %s requires SASL support (-DSASL)\n",
- o->o_name == NULL ? "<unknown>" : o->o_name);
+ case O_SASLBITS:
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires SASL support (-DSASL)\n",
+ OPTNAME);
break;
#endif /* SASL */
#if STARTTLS
case O_SRVCERTFILE:
- if (SrvCERTfile != NULL)
- sm_free(SrvCERTfile);
- SrvCERTfile = newstr(val);
- break;
-
+ SET_STRING_EXP(SrvCERTfile);
case O_SRVKEYFILE:
- if (Srvkeyfile != NULL)
- sm_free(Srvkeyfile);
- Srvkeyfile = newstr(val);
- break;
-
+ SET_STRING_EXP(Srvkeyfile);
case O_CLTCERTFILE:
- if (CltCERTfile != NULL)
- sm_free(CltCERTfile);
- CltCERTfile = newstr(val);
- break;
-
+ SET_STRING_EXP(CltCERTfile);
case O_CLTKEYFILE:
- if (Cltkeyfile != NULL)
- sm_free(Cltkeyfile);
- Cltkeyfile = newstr(val);
- break;
-
+ SET_STRING_EXP(Cltkeyfile);
case O_CACERTFILE:
- if (CACERTfile != NULL)
- sm_free(CACERTfile);
- CACERTfile = newstr(val);
- break;
-
+ SET_STRING_EXP(CACERTfile);
case O_CACERTPATH:
- if (CACERTpath != NULL)
- sm_free(CACERTpath);
- CACERTpath = newstr(val);
- break;
-
+ SET_STRING_EXP(CACERTpath);
case O_DHPARAMS:
- if (DHParams != NULL)
- sm_free(DHParams);
- DHParams = newstr(val);
- break;
-
-# if _FFR_TLS_1
+ SET_STRING_EXP(DHParams);
+# if _FFR_TLS_1
case O_DHPARAMS5:
- if (DHParams5 != NULL)
- sm_free(DHParams5);
- DHParams5 = newstr(val);
- break;
-
+ SET_STRING_EXP(DHParams5);
case O_CIPHERLIST:
- if (CipherList != NULL)
- sm_free(CipherList);
- CipherList = newstr(val);
+ SET_STRING_EXP(CipherList);
+# endif /* _FFR_TLS_1 */
+
+ /*
+ ** XXX How about options per daemon/client instead of globally?
+ ** This doesn't work well for some options, e.g., no server cert,
+ ** but fine for others.
+ **
+ ** XXX Some people may want different certs per server.
+ **
+ ** See also srvfeatures()
+ */
+
+ case O_TLS_SRV_OPTS:
+ while (val != NULL && *val != '\0')
+ {
+ switch (*val)
+ {
+ case 'V':
+ TLS_Srv_Opts |= TLS_I_NO_VRFY;
+ break;
+# if _FFR_TLS_1
+ /*
+ ** Server without a cert? That works only if
+ ** AnonDH is enabled as cipher, which is not in the
+ ** default list. Hence the CipherList option must
+ ** be available. Moreover: which clients support this
+ ** besides sendmail with this setting?
+ */
+
+ case 'C':
+ TLS_Srv_Opts &= ~TLS_I_SRV_CERT;
+ break;
+# endif /* _FFR_TLS_1 */
+ case ' ': /* ignore */
+ case '\t': /* ignore */
+ case ',': /* ignore */
+ break;
+ default:
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s unknown parameter '%c'\n",
+ OPTNAME,
+ (isascii(*val) &&
+ isprint(*val))
+ ? *val : '?');
+ break;
+ }
+ ++val;
+ val = strpbrk(val, ", \t");
+ if (val != NULL)
+ ++val;
+ }
break;
-# endif /* _FFR_TLS_1 */
case O_RANDFILE:
- if (RandFile != NULL)
- sm_free(RandFile);
- RandFile= newstr(val);
+ PSTRSET(RandFile, val);
break;
-# else /* STARTTLS */
+#else /* STARTTLS */
case O_SRVCERTFILE:
case O_SRVKEYFILE:
case O_CLTCERTFILE:
@@ -2959,23 +3412,20 @@ setoption(opt, val, safe, sticky, e)
case O_CACERTFILE:
case O_CACERTPATH:
case O_DHPARAMS:
-# if _FFR_TLS_1
+# if _FFR_TLS_1
case O_DHPARAMS5:
case O_CIPHERLIST:
-# endif /* _FFR_TLS_1 */
+# endif /* _FFR_TLS_1 */
case O_RANDFILE:
- printf("Warning: Option: %s requires TLS support\n",
- o->o_name == NULL ? "<unknown>" : o->o_name);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires TLS support\n",
+ OPTNAME);
break;
-# endif /* STARTTLS */
+#endif /* STARTTLS */
case O_CLIENTPORT:
-#if DAEMON
setclientoptions(val);
-#else /* DAEMON */
- syserr("ClientPortOptions (O option) set but DAEMON not compiled in");
-#endif /* DAEMON */
break;
case O_DF_BUFSIZE:
@@ -2987,37 +3437,80 @@ setoption(opt, val, safe, sticky, e)
break;
case O_LDAPDEFAULTSPEC:
-#ifdef LDAPMAP
+#if LDAPMAP
ldapmap_set_defaults(val);
#else /* LDAPMAP */
- printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
- o->o_name == NULL ? "<unknown>" : o->o_name);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires LDAP support (-DLDAPMAP)\n",
+ OPTNAME);
#endif /* LDAPMAP */
break;
-#if _FFR_MILTER
case O_INPUTMILTER:
+#if MILTER
InputFilterList = newstr(val);
+#else /* MILTER */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires Milter support (-DMILTER)\n",
+ OPTNAME);
+#endif /* MILTER */
break;
case O_MILTER:
+#if MILTER
milter_set_option(subopt, val, sticky);
+#else /* MILTER */
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Warning: Option: %s requires Milter support (-DMILTER)\n",
+ OPTNAME);
+#endif /* MILTER */
break;
-#endif /* _FFR_MILTER */
-#if _FFR_QUEUE_FILE_MODE
case O_QUEUE_FILE_MODE: /* queue file mode */
QueueFileMode = atooct(val) & 0777;
break;
-#endif /* _FFR_QUEUE_FILE_MODE */
+
+ case O_DLVR_MIN: /* deliver by minimum time */
+ DeliverByMin = convtime(val, 's');
+ break;
+
+ /* modifiers {daemon_flags} for direct submissions */
+ case O_DIRECTSUBMODIFIERS:
+ {
+ BITMAP256 m; /* ignored */
+ extern ENVELOPE BlankEnvelope;
+
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{daemon_flags}"),
+ getmodifiers(val, m));
+ }
+ break;
+
+ case O_FASTSPLIT:
+ FastSplit = atoi(val);
+ break;
+
+ case O_MBDB:
+ Mbdb = newstr(val);
+ break;
+
+ case O_MSQ:
+ UseMSP = atobool(val);
+ break;
+
+#if _FFR_SOFT_BOUNCE
+ case O_SOFTBOUNCE:
+ SoftBounce = atobool(val);
+ break;
+#endif /* _FFR_SOFT_BOUNCE */
default:
if (tTd(37, 1))
{
if (isascii(opt) && isprint(opt))
- dprintf("Warning: option %c unknown\n", opt);
+ sm_dprintf("Warning: option %c unknown\n", opt);
else
- dprintf("Warning: option 0x%x unknown\n", opt);
+ sm_dprintf("Warning: option 0x%x unknown\n", opt);
}
break;
}
@@ -3033,7 +3526,7 @@ setoption(opt, val, safe, sticky, e)
if (sticky && !bitset(OI_SUBOPT, o->o_flags))
setbitn(opt, StickyOpt);
}
- /*
+/*
** SETCLASS -- set a string into a class
**
** Parameters:
@@ -3059,25 +3552,25 @@ setclass(class, str)
int mid;
str++;
- mid = macid(str, NULL);
+ mid = macid(str);
if (mid == 0)
return;
if (tTd(37, 8))
- dprintf("setclass(%s, $=%s)\n",
- macname(class), macname(mid));
+ sm_dprintf("setclass(%s, $=%s)\n",
+ macname(class), macname(mid));
copy_class(mid, class);
}
else
{
if (tTd(37, 8))
- dprintf("setclass(%s, %s)\n", macname(class), str);
+ sm_dprintf("setclass(%s, %s)\n", macname(class), str);
s = stab(str, ST_CLASS, ST_ENTER);
setbitn(bitidx(class), s->s_class);
}
}
- /*
+/*
** MAKEMAPENTRY -- create a map entry
**
** Parameters:
@@ -3133,7 +3626,8 @@ makemapentry(line)
class = stab(classname, ST_MAPCLASS, ST_FIND);
if (class == NULL)
{
- syserr("readcf: map %s: class %s not available", mapname, classname);
+ syserr("readcf: map %s: class %s not available", mapname,
+ classname);
return NULL;
}
@@ -3147,19 +3641,16 @@ makemapentry(line)
if (tTd(37, 5))
{
- dprintf("map %s, class %s, flags %lx, file %s,\n",
- s->s_map.map_mname, s->s_map.map_class->map_cname,
- s->s_map.map_mflags,
- s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
- dprintf("\tapp %s, domain %s, rebuild %s\n",
- s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
- s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
- s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
+ sm_dprintf("map %s, class %s, flags %lx, file %s,\n",
+ s->s_map.map_mname, s->s_map.map_class->map_cname,
+ s->s_map.map_mflags, s->s_map.map_file);
+ sm_dprintf("\tapp %s, domain %s, rebuild %s\n",
+ s->s_map.map_app, s->s_map.map_domain,
+ s->s_map.map_rebuild);
}
-
return &s->s_map;
}
- /*
+/*
** STRTORWSET -- convert string to rewriting set number
**
** Parameters:
@@ -3277,7 +3768,7 @@ strtorwset(p, endp, stabmode)
char *h = NULL;
if (RuleSetNames[ruleset] != NULL)
- sm_free(RuleSetNames[ruleset]);
+ sm_free(RuleSetNames[ruleset]); /* XXX */
if (delim != '\0' && (h = strchr(q, delim)) != NULL)
*h = '\0';
RuleSetNames[ruleset] = newstr(q);
@@ -3287,7 +3778,7 @@ strtorwset(p, endp, stabmode)
}
return ruleset;
}
- /*
+/*
** SETTIMEOUT -- set an individual timeout
**
** Parameters:
@@ -3305,8 +3796,8 @@ static BITMAP256 StickyTimeoutOpt;
static struct timeoutinfo
{
- char *to_name; /* long name of timeout */
- u_char to_code; /* code for option */
+ char *to_name; /* long name of timeout */
+ unsigned char to_code; /* code for option */
} TimeOutTab[] =
{
#define TO_INITIAL 0x01
@@ -3373,6 +3864,14 @@ static struct timeoutinfo
{ "resolver.retry.first", TO_RESOLVER_RETRY_FIRST },
#define TO_CONTROL 0x1F
{ "control", TO_CONTROL },
+#define TO_LHLO 0x20
+ { "lhlo", TO_LHLO },
+#define TO_AUTH 0x21
+ { "auth", TO_AUTH },
+#define TO_STARTTLS 0x22
+ { "starttls", TO_STARTTLS },
+#define TO_ACONNECT 0x23
+ { "aconnect", TO_ACONNECT },
{ NULL, 0 },
};
@@ -3384,16 +3883,15 @@ settimeout(name, val, sticky)
bool sticky;
{
register struct timeoutinfo *to;
- int i;
- int addopts;
+ int i, addopts;
time_t toval;
if (tTd(37, 2))
- dprintf("settimeout(%s = %s)", name, val);
+ sm_dprintf("settimeout(%s = %s)", name, val);
for (to = TimeOutTab; to->to_name != NULL; to++)
{
- if (strcasecmp(to->to_name, name) == 0)
+ if (sm_strcasecmp(to->to_name, name) == 0)
break;
}
@@ -3411,12 +3909,12 @@ settimeout(name, val, sticky)
if (!sticky && bitnset(to->to_code, StickyTimeoutOpt))
{
if (tTd(37, 2))
- dprintf(" (ignored)\n");
+ sm_dprintf(" (ignored)\n");
return;
}
if (tTd(37, 2))
- dprintf("\n");
+ sm_dprintf("\n");
toval = convtime(val, 'm');
addopts = 0;
@@ -3483,6 +3981,10 @@ settimeout(name, val, sticky)
TimeOuts.to_iconnect = toval;
break;
+ case TO_ACONNECT:
+ TimeOuts.to_aconnect = toval;
+ break;
+
case TO_QUEUEWARN:
toval = convtime(val, 'h');
TimeOuts.to_q_warning[TOC_NORMAL] = toval;
@@ -3570,6 +4072,22 @@ settimeout(name, val, sticky)
TimeOuts.to_control = toval;
break;
+ case TO_LHLO:
+ TimeOuts.to_lhlo = toval;
+ break;
+
+#if SASL
+ case TO_AUTH:
+ TimeOuts.to_auth = toval;
+ break;
+#endif /* SASL */
+
+#if STARTTLS
+ case TO_STARTTLS:
+ TimeOuts.to_starttls = toval;
+ break;
+#endif /* STARTTLS */
+
default:
syserr("settimeout: invalid timeout %s", name);
break;
@@ -3581,7 +4099,7 @@ settimeout(name, val, sticky)
setbitn(to->to_code + i, StickyTimeoutOpt);
}
}
- /*
+/*
** INITTIMEOUTS -- parse and set timeout values
**
** Parameters:
@@ -3605,10 +4123,11 @@ inittimeouts(val, sticky)
register char *p;
if (tTd(37, 2))
- dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
+ sm_dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
if (val == NULL)
{
TimeOuts.to_connect = (time_t) 0 SECONDS;
+ TimeOuts.to_aconnect = (time_t) 0 SECONDS;
TimeOuts.to_initial = (time_t) 5 MINUTES;
TimeOuts.to_helo = (time_t) 5 MINUTES;
TimeOuts.to_mail = (time_t) 10 MINUTES;
@@ -3627,24 +4146,44 @@ inittimeouts(val, sticky)
#endif /* IDENTPROTO */
TimeOuts.to_fileopen = (time_t) 60 SECONDS;
TimeOuts.to_control = (time_t) 2 MINUTES;
+ TimeOuts.to_lhlo = (time_t) 2 MINUTES;
+#if SASL
+ TimeOuts.to_auth = (time_t) 10 MINUTES;
+#endif /* SASL */
+#if STARTTLS
+ TimeOuts.to_starttls = (time_t) 1 HOUR;
+#endif /* STARTTLS */
if (tTd(37, 5))
{
- dprintf("Timeouts:\n");
- dprintf(" connect = %ld\n", (long)TimeOuts.to_connect);
- dprintf(" initial = %ld\n", (long)TimeOuts.to_initial);
- dprintf(" helo = %ld\n", (long)TimeOuts.to_helo);
- dprintf(" mail = %ld\n", (long)TimeOuts.to_mail);
- dprintf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt);
- dprintf(" datainit = %ld\n", (long)TimeOuts.to_datainit);
- dprintf(" datablock = %ld\n", (long)TimeOuts.to_datablock);
- dprintf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal);
- dprintf(" rset = %ld\n", (long)TimeOuts.to_rset);
- dprintf(" quit = %ld\n", (long)TimeOuts.to_quit);
- dprintf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand);
- dprintf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort);
- dprintf(" ident = %ld\n", (long)TimeOuts.to_ident);
- dprintf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen);
- dprintf(" control = %ld\n", (long)TimeOuts.to_control);
+ sm_dprintf("Timeouts:\n");
+ sm_dprintf(" connect = %ld\n",
+ (long) TimeOuts.to_connect);
+ sm_dprintf(" aconnect = %ld\n",
+ (long) TimeOuts.to_aconnect);
+ sm_dprintf(" initial = %ld\n",
+ (long) TimeOuts.to_initial);
+ sm_dprintf(" helo = %ld\n", (long) TimeOuts.to_helo);
+ sm_dprintf(" mail = %ld\n", (long) TimeOuts.to_mail);
+ sm_dprintf(" rcpt = %ld\n", (long) TimeOuts.to_rcpt);
+ sm_dprintf(" datainit = %ld\n",
+ (long) TimeOuts.to_datainit);
+ sm_dprintf(" datablock = %ld\n",
+ (long) TimeOuts.to_datablock);
+ sm_dprintf(" datafinal = %ld\n",
+ (long) TimeOuts.to_datafinal);
+ sm_dprintf(" rset = %ld\n", (long) TimeOuts.to_rset);
+ sm_dprintf(" quit = %ld\n", (long) TimeOuts.to_quit);
+ sm_dprintf(" nextcommand = %ld\n",
+ (long) TimeOuts.to_nextcommand);
+ sm_dprintf(" miscshort = %ld\n",
+ (long) TimeOuts.to_miscshort);
+ sm_dprintf(" ident = %ld\n", (long) TimeOuts.to_ident);
+ sm_dprintf(" fileopen = %ld\n",
+ (long) TimeOuts.to_fileopen);
+ sm_dprintf(" lhlo = %ld\n",
+ (long) TimeOuts.to_lhlo);
+ sm_dprintf(" control = %ld\n",
+ (long) TimeOuts.to_control);
}
return;
}
diff --git a/contrib/sendmail/src/recipient.c b/contrib/sendmail/src/recipient.c
index bfed632..378088a 100644
--- a/contrib/sendmail/src/recipient.c
+++ b/contrib/sendmail/src/recipient.c
@@ -11,15 +11,125 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: recipient.c,v 8.231.14.11 2001/05/03 17:24:14 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: recipient.c,v 8.327 2001/11/20 13:59:53 ca Exp $")
static void includetimeout __P((void));
static ADDRESS *self_reference __P((ADDRESS *));
+static int sortexpensive __P((ADDRESS *, ADDRESS *));
+static int sortbysignature __P((ADDRESS *, ADDRESS *));
+static int sorthost __P((ADDRESS *, ADDRESS *));
+
+typedef int sortfn_t __P((ADDRESS *, ADDRESS *));
+
+/*
+** SORTHOST -- strcmp()-like func for host portion of an ADDRESS
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** <0 when xx->q_host is less than yy->q_host
+** >0 when xx->q_host is greater than yy->q_host
+** 0 when equal
+*/
+
+static int
+sorthost(xx, yy)
+ register ADDRESS *xx;
+ register ADDRESS *yy;
+{
+#if _FFR_HOST_SORT_REVERSE
+ /* XXX maybe compare hostnames from the end? */
+ return sm_strrevcasecmp(xx->q_host, yy->q_host);
+#else /* _FFR_HOST_SORT_REVERSE */
+ return sm_strcasecmp(xx->q_host, yy->q_host);
+#endif /* _FFR_HOST_SORT_REVERSE */
+}
+
+/*
+** SORTEXPENSIVE -- strcmp()-like func for expensive mailers
+**
+** The mailer has been noted already as "expensive" for 'xx'. This
+** will give a result relative to 'yy'. Expensive mailers get rated
+** "greater than" non-expensive mailers because during the delivery phase
+** it will get queued -- no use it getting in the way of less expensive
+** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are
+** expensive since an MX RR lookup happens when extracted from the queue
+** later.
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** <0 when xx->q_host is less than yy->q_host and both are
+** expensive
+** >0 when xx->q_host is greater than yy->q_host, or when
+** 'yy' is non-expensive
+** 0 when equal (by expense and q_host)
+*/
+
+static int
+sortexpensive(xx, yy)
+ ADDRESS *xx;
+ ADDRESS *yy;
+{
+ if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags))
+ return 1; /* xx should go later */
+#if _FFR_HOST_SORT_REVERSE
+ /* XXX maybe compare hostnames from the end? */
+ return sm_strrevcasecmp(xx->q_host, yy->q_host);
+#else /* _FFR_HOST_SORT_REVERSE */
+ return sm_strcasecmp(xx->q_host, yy->q_host);
+#endif /* _FFR_HOST_SORT_REVERSE */
+}
+
+/*
+** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS
+**
+** Parameters:
+** xx -- first ADDRESS
+** yy -- second ADDRESS
+**
+** Returns:
+** 0 when the "signature"'s are same
+** <0 when xx->q_signature is less than yy->q_signature
+** >0 when xx->q_signature is greater than yy->q_signature
+**
+** Side Effect:
+** May set ADDRESS pointer for q_signature if not already set.
+*/
+
+static int
+sortbysignature(xx, yy)
+ ADDRESS *xx;
+ ADDRESS *yy;
+{
+ register int ret;
+
+ /* Let's avoid redoing the signature over and over again */
+ if (xx->q_signature == NULL)
+ xx->q_signature = hostsignature(xx->q_mailer, xx->q_host);
+ if (yy->q_signature == NULL)
+ yy->q_signature = hostsignature(yy->q_mailer, yy->q_host);
+ ret = strcmp(xx->q_signature, yy->q_signature);
+
+ /*
+ ** If the two signatures are the same then we will return a sort
+ ** value based on 'q_user'. But note that we have reversed xx and yy
+ ** on purpose. This additional compare helps reduce the number of
+ ** sameaddr() calls and loops in recipient() for the case when
+ ** the rcpt list has been provided already in-order.
+ */
+
+ if (ret == 0)
+ return strcmp(yy->q_user, xx->q_user);
+ else
+ return ret;
+}
/*
** SENDTOLIST -- Designate a send list.
@@ -41,9 +151,6 @@ static ADDRESS *self_reference __P((ADDRESS *));
**
** Returns:
** The number of addresses actually on the list.
-**
-** Side Effects:
-** none.
*/
/* q_flags bits inherited from ctladdr */
@@ -58,12 +165,12 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
register ENVELOPE *e;
{
register char *p;
- register ADDRESS *al; /* list of addresses to send to */
- char delimiter; /* the address delimiter */
- int naddrs;
- int i;
+ register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */
+ SM_NONVOLATILE char delimiter; /* the address delimiter */
+ SM_NONVOLATILE int naddrs;
+ SM_NONVOLATILE int i;
char *oldto = e->e_to;
- char *bufp;
+ char *SM_NONVOLATILE bufp;
char buf[MAXNAME + 1];
if (list == NULL)
@@ -74,8 +181,8 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
if (tTd(25, 1))
{
- dprintf("sendto: %s\n ctladdr=", list);
- printaddr(ctladdr, FALSE);
+ sm_dprintf("sendto: %s\n ctladdr=", list);
+ printaddr(ctladdr, false);
}
/* heuristic to determine old versus new style addresses */
@@ -98,105 +205,111 @@ sendtolist(list, ctladdr, sendq, aliaslevel, e)
i = sizeof buf;
}
else
- bufp = xalloc(i);
- (void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
-
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
- for (p = bufp; *p != '\0'; )
- {
- auto char *delimptr;
- register ADDRESS *a;
-
- /* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
- p = delimptr;
- if (a == NULL)
- continue;
- a->q_next = al;
- a->q_alias = ctladdr;
+ bufp = sm_malloc_x(i);
+
+ SM_TRY
+ {
+ (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
- /* arrange to inherit attributes from parent */
- if (ctladdr != NULL)
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
+ for (p = bufp; *p != '\0'; )
{
- ADDRESS *b;
+ auto char *delimptr;
+ register ADDRESS *a;
+
+ /* parse the address */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter,
+ &delimptr, e, true);
+ p = delimptr;
+ if (a == NULL)
+ continue;
+ a->q_next = al;
+ a->q_alias = ctladdr;
- /* self reference test */
- if (sameaddr(ctladdr, a))
+ /* arrange to inherit attributes from parent */
+ if (ctladdr != NULL)
{
- if (tTd(27, 5))
- {
- dprintf("sendtolist: QSELFREF ");
- printaddr(ctladdr, FALSE);
- }
- ctladdr->q_flags |= QSELFREF;
- }
+ ADDRESS *b;
- /* check for address loops */
- b = self_reference(a);
- if (b != NULL)
- {
- b->q_flags |= QSELFREF;
- if (tTd(27, 5))
+ /* self reference test */
+ if (sameaddr(ctladdr, a))
{
- dprintf("sendtolist: QSELFREF ");
- printaddr(b, FALSE);
+ if (tTd(27, 5))
+ {
+ sm_dprintf("sendtolist: QSELFREF ");
+ printaddr(ctladdr, false);
+ }
+ ctladdr->q_flags |= QSELFREF;
}
- if (a != b)
+
+ /* check for address loops */
+ b = self_reference(a);
+ if (b != NULL)
{
+ b->q_flags |= QSELFREF;
if (tTd(27, 5))
{
- dprintf("sendtolist: QS_DONTSEND ");
- printaddr(a, FALSE);
+ sm_dprintf("sendtolist: QSELFREF ");
+ printaddr(b, false);
+ }
+ if (a != b)
+ {
+ if (tTd(27, 5))
+ {
+ sm_dprintf("sendtolist: QS_DONTSEND ");
+ printaddr(a, false);
+ }
+ a->q_state = QS_DONTSEND;
+ b->q_flags |= a->q_flags & QNOTREMOTE;
+ continue;
}
- a->q_state = QS_DONTSEND;
- b->q_flags |= a->q_flags & QNOTREMOTE;
- continue;
}
- }
- /* full name */
- if (a->q_fullname == NULL)
- a->q_fullname = ctladdr->q_fullname;
+ /* full name */
+ if (a->q_fullname == NULL)
+ a->q_fullname = ctladdr->q_fullname;
+
+ /* various flag bits */
+ a->q_flags &= ~QINHERITEDBITS;
+ a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
- /* various flag bits */
- a->q_flags &= ~QINHERITEDBITS;
- a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
+ /* DSN recipient information */
+ a->q_finalrcpt = ctladdr->q_finalrcpt;
+ a->q_orcpt = ctladdr->q_orcpt;
+ }
- /* original recipient information */
- a->q_orcpt = ctladdr->q_orcpt;
+ al = a;
}
- al = a;
- }
+ /* arrange to send to everyone on the local send list */
+ while (al != NULL)
+ {
+ register ADDRESS *a = al;
- /* arrange to send to everyone on the local send list */
- while (al != NULL)
+ al = a->q_next;
+ a = recipient(a, sendq, aliaslevel, e);
+ naddrs++;
+ }
+ }
+ SM_FINALLY
{
- register ADDRESS *a = al;
-
- al = a->q_next;
- a = recipient(a, sendq, aliaslevel, e);
- naddrs++;
+ e->e_to = oldto;
+ if (bufp != buf)
+ sm_free(bufp);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
}
-
- e->e_to = oldto;
- if (bufp != buf)
- sm_free(bufp);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ SM_END_TRY
return naddrs;
}
- /*
+#if MILTER
+/*
** REMOVEFROMLIST -- Remove addresses from a send list.
**
** The parameter is a comma-separated list of recipients to remove.
** Note that it only deletes matching addresses. If those addresses
-** have been expended already in the sendq, it won't mark the
+** have been expanded already in the sendq, it won't mark the
** expanded recipients as QS_REMOVED.
**
** Parameters:
@@ -216,12 +329,12 @@ removefromlist(list, sendq, e)
ADDRESS **sendq;
ENVELOPE *e;
{
- char delimiter; /* the address delimiter */
- int naddrs;
- int i;
+ SM_NONVOLATILE char delimiter; /* the address delimiter */
+ SM_NONVOLATILE int naddrs;
+ SM_NONVOLATILE int i;
char *p;
char *oldto = e->e_to;
- char *bufp;
+ char *SM_NONVOLATILE bufp;
char buf[MAXNAME + 1];
if (list == NULL)
@@ -231,7 +344,7 @@ removefromlist(list, sendq, e)
}
if (tTd(25, 1))
- dprintf("removefromlist: %s\n", list);
+ sm_dprintf("removefromlist: %s\n", list);
/* heuristic to determine old versus new style addresses */
if (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
@@ -251,61 +364,65 @@ removefromlist(list, sendq, e)
i = sizeof buf;
}
else
- bufp = xalloc(i);
- (void) strlcpy(bufp, denlstring(list, FALSE, TRUE), i);
-
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-#endif /* _FFR_ADDR_TYPE */
- for (p = bufp; *p != '\0'; )
- {
- ADDRESS a; /* parsed address to be removed */
- ADDRESS *q;
- ADDRESS **pq;
- char *delimptr;
-
- /* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- if (parseaddr(p, &a, RF_COPYALL,
- delimiter, &delimptr, e) == NULL)
+ bufp = sm_malloc_x(i);
+
+ SM_TRY
+ {
+ (void) sm_strlcpy(bufp, denlstring(list, false, true), i);
+
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
+ for (p = bufp; *p != '\0'; )
{
+ ADDRESS a; /* parsed address to be removed */
+ ADDRESS *q;
+ ADDRESS **pq;
+ char *delimptr;
+
+ /* parse the address */
+ while ((isascii(*p) && isspace(*p)) || *p == ',')
+ p++;
+ if (parseaddr(p, &a, RF_COPYALL,
+ delimiter, &delimptr, e, true) == NULL)
+ {
+ p = delimptr;
+ continue;
+ }
p = delimptr;
- continue;
- }
- p = delimptr;
- for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
- {
- if (!QS_IS_DEAD(q->q_state) &&
- sameaddr(q, &a))
+ for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
- if (tTd(25, 5))
+ if (!QS_IS_DEAD(q->q_state) &&
+ sameaddr(q, &a))
{
- dprintf("removefromlist: QS_REMOVED ");
- printaddr(&a, FALSE);
+ if (tTd(25, 5))
+ {
+ sm_dprintf("removefromlist: QS_REMOVED ");
+ printaddr(&a, false);
+ }
+ q->q_state = QS_REMOVED;
+ naddrs++;
+ break;
}
- q->q_state = QS_REMOVED;
- naddrs++;
- break;
}
}
}
-
- e->e_to = oldto;
- if (bufp != buf)
- sm_free(bufp);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ SM_FINALLY
+ {
+ e->e_to = oldto;
+ if (bufp != buf)
+ sm_free(bufp);
+ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
+ }
+ SM_END_TRY
return naddrs;
}
- /*
+#endif /* MILTER */
+/*
** RECIPIENT -- Designate a message recipient
**
** Saves the named person for future mailing.
**
** Parameters:
-** a -- the (preparsed) address header for the recipient.
+** new -- the (preparsed) address header for the recipient.
** sendq -- a pointer to the head of a queue to put the
** recipient in. Duplicate suppression is done
** in this queue.
@@ -316,62 +433,121 @@ removefromlist(list, sendq, e)
** The actual address in the queue. This will be "a" if
** the address is not a duplicate, else the original address.
**
-** Side Effects:
-** none.
*/
ADDRESS *
-recipient(a, sendq, aliaslevel, e)
- register ADDRESS *a;
+recipient(new, sendq, aliaslevel, e)
+ register ADDRESS *new;
register ADDRESS **sendq;
int aliaslevel;
register ENVELOPE *e;
{
register ADDRESS *q;
ADDRESS **pq;
+ ADDRESS **prev;
register struct mailer *m;
- register char *p = NULL;
- bool quoted = FALSE; /* set if the addr has a quote bit */
- int findusercount = 0;
- bool initialdontsend = QS_IS_DEAD(a->q_state);
+ register char *p;
int i, buflen;
+ bool quoted; /* set if the addr has a quote bit */
+ bool insert;
+ int findusercount;
+ bool initialdontsend;
char *buf;
char buf0[MAXNAME + 1]; /* unquoted image of the user name */
-
- e->e_to = a->q_paddr;
- m = a->q_mailer;
+ sortfn_t *sortfn;
+
+ p = NULL;
+ quoted = false;
+ insert = false;
+ findusercount = 0;
+ initialdontsend = QS_IS_DEAD(new->q_state);
+ e->e_to = new->q_paddr;
+ m = new->q_mailer;
errno = 0;
if (aliaslevel == 0)
- a->q_flags |= QPRIMARY;
+ new->q_flags |= QPRIMARY;
if (tTd(26, 1))
{
- dprintf("\nrecipient (%d): ", aliaslevel);
- printaddr(a, FALSE);
+ sm_dprintf("\nrecipient (%d): ", aliaslevel);
+ printaddr(new, false);
}
- /* if this is primary, add it to the original recipient list */
- if (a->q_alias == NULL)
+ /* if this is primary, use it as original recipient */
+ if (new->q_alias == NULL)
{
if (e->e_origrcpt == NULL)
- e->e_origrcpt = a->q_paddr;
- else if (e->e_origrcpt != a->q_paddr)
+ e->e_origrcpt = new->q_paddr;
+ else if (e->e_origrcpt != new->q_paddr)
e->e_origrcpt = "";
}
+ /* find parent recipient for finalrcpt and orcpt */
+ for (q = new; q->q_alias != NULL; q = q->q_alias)
+ continue;
+
+ /* find final recipient DSN address */
+ if (new->q_finalrcpt == NULL &&
+ e->e_from.q_mailer != NULL)
+ {
+ char frbuf[MAXLINE];
+
+ p = e->e_from.q_mailer->m_addrtype;
+ if (p == NULL)
+ p = "rfc822";
+ if (sm_strcasecmp(p, "rfc822") != 0)
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ q->q_mailer->m_addrtype,
+ q->q_user);
+ }
+ else if (strchr(q->q_user, '@') != NULL)
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ p, q->q_user);
+ }
+ else if (strchr(q->q_paddr, '@') != NULL)
+ {
+ char *qp;
+ bool b;
+
+ qp = q->q_paddr;
+
+ /* strip brackets from address */
+ b = false;
+ if (*qp == '<')
+ {
+ b = qp[strlen(qp) - 1] == '>';
+ if (b)
+ qp[strlen(qp) - 1] = '\0';
+ qp++;
+ }
+ (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s",
+ p, qp);
+
+ /* undo damage */
+ if (b)
+ qp[strlen(qp)] = '>';
+ }
+ else
+ {
+ (void) sm_snprintf(frbuf, sizeof frbuf,
+ "%s; %.700s@%.100s",
+ p, q->q_user, MyHostName);
+ }
+ new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf);
+ }
+
#if _FFR_GEN_ORCPT
/* set ORCPT DSN arg if not already set */
- if (a->q_orcpt == NULL)
+ if (new->q_orcpt == NULL)
{
- for (q = a; q->q_alias != NULL; q = q->q_alias)
- continue;
-
/* check for an existing ORCPT */
if (q->q_orcpt != NULL)
- a->q_orcpt = q->q_orcpt;
+ new->q_orcpt = q->q_orcpt;
else
{
/* make our own */
- bool b = FALSE;
+ bool b = false;
char *qp;
char obuf[MAXLINE];
@@ -379,8 +555,7 @@ recipient(a, sendq, aliaslevel, e)
p = e->e_from.q_mailer->m_addrtype;
if (p == NULL)
p = "rfc822";
- (void) strlcpy(obuf, p, sizeof obuf);
- (void) strlcat(obuf, ";", sizeof obuf);
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2, p, ";");
qp = q->q_paddr;
@@ -395,9 +570,9 @@ recipient(a, sendq, aliaslevel, e)
qp++;
}
- p = xtextify(denlstring(qp, TRUE, FALSE), NULL);
+ p = xtextify(denlstring(qp, true, false), NULL);
- if (strlcat(obuf, p, sizeof obuf) >= sizeof obuf)
+ if (sm_strlcat(obuf, p, sizeof obuf) >= sizeof obuf)
{
/* if too big, don't use it */
obuf[0] = '\0';
@@ -408,7 +583,8 @@ recipient(a, sendq, aliaslevel, e)
qp[strlen(qp)] = '>';
if (obuf[0] != '\0')
- a->q_orcpt = newstr(obuf);
+ new->q_orcpt =
+ sm_rpool_strdup_x(e->e_rpool, obuf);
}
}
#endif /* _FFR_GEN_ORCPT */
@@ -416,12 +592,12 @@ recipient(a, sendq, aliaslevel, e)
/* break aliasing loops */
if (aliaslevel > MaxAliasRecursion)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
aliaslevel, MaxAliasRecursion);
- return a;
+ return new;
}
/*
@@ -429,7 +605,7 @@ recipient(a, sendq, aliaslevel, e)
*/
/* get unquoted user for file, program or user.name check */
- i = strlen(a->q_user);
+ i = strlen(new->q_user);
if (i >= sizeof buf0)
{
buflen = i + 1;
@@ -440,45 +616,46 @@ recipient(a, sendq, aliaslevel, e)
buf = buf0;
buflen = sizeof buf0;
}
- (void) strlcpy(buf, a->q_user, buflen);
+ (void) sm_strlcpy(buf, new->q_user, buflen);
for (p = buf; *p != '\0' && !quoted; p++)
{
if (*p == '\\')
- quoted = TRUE;
+ quoted = true;
}
stripquotes(buf);
/* check for direct mailing to restricted mailers */
if (m == ProgMailer)
{
- if (a->q_alias == NULL)
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to programs");
}
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ if (new->q_alias->q_ruser == NULL)
+ usrerrenh(new->q_status,
"550 UID %d is an unknown user: cannot mail to programs",
- a->q_alias->q_uid);
+ new->q_alias->q_uid);
else
- usrerrenh(a->q_status,
+ usrerrenh(new->q_status,
"550 User %s@%s doesn't have a valid shell for mailing to programs",
- a->q_alias->q_ruser, MyHostName);
+ new->q_alias->q_ruser, MyHostName);
}
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("550 Unsafe for mailing to programs");
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ new->q_rstatus = "550 Unsafe for mailing to programs";
+ usrerrenh(new->q_status,
"550 Address %s is unsafe for mailing to programs",
- a->q_alias->q_paddr);
+ new->q_alias->q_paddr);
}
}
@@ -491,52 +668,123 @@ recipient(a, sendq, aliaslevel, e)
** [Please note: the emphasis is on "hack."]
*/
+ prev = NULL;
+
+ /*
+ ** If this message is going to the queue or FastSplit is set
+ ** and it is the first try and the envelope hasn't split, then we
+ ** avoid doing an MX RR lookup now because one will be done when the
+ ** message is extracted from the queue later. It can go to the queue
+ ** because all messages are going to the queue or this mailer of
+ ** the current recipient is marked expensive.
+ */
+
+ if (WILL_BE_QUEUED(e->e_sendmode) ||
+ (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 &&
+ FastSplit > 0))
+ sortfn = sorthost;
+ else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags))
+ sortfn = sortexpensive;
+ else
+ sortfn = sortbysignature;
+
for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
{
- if (sameaddr(q, a) &&
- (bitset(QRCPTOK, q->q_flags) ||
- !bitset(QPRIMARY, q->q_flags)))
+ /*
+ ** If address is "less than" it should be inserted now.
+ ** If address is "greater than" current comparison it'll
+ ** insert later in the list; so loop again (if possible).
+ ** If address is "equal" (different equal than sameaddr()
+ ** call) then check if sameaddr() will be true.
+ ** Because this list is now sorted, it'll mean fewer
+ ** comparisons and fewer loops which is important for more
+ ** recipients.
+ */
+
+ i = (*sortfn)(new, q);
+ if (i == 0) /* equal */
{
- if (tTd(26, 1))
- {
- dprintf("%s in sendq: ", a->q_paddr);
- printaddr(q, FALSE);
- }
- if (!bitset(QPRIMARY, q->q_flags))
- {
- if (!QS_IS_DEAD(a->q_state))
- message("duplicate suppressed");
- else
- q->q_state = QS_DUPLICATE;
- q->q_flags |= a->q_flags;
- }
- else if (bitset(QSELFREF, q->q_flags)
-#if _FFR_MILTER
- || q->q_state == QS_REMOVED
-#endif /* _FFR_MILTER */
- )
+ /*
+ ** Sortbysignature() has said that the two have
+ ** equal MX RR's and the same user. Calling sameaddr()
+ ** now checks if the two hosts are as identical as the
+ ** MX RR's are (which might not be the case)
+ ** before saying these are the identical addresses.
+ */
+
+ if (sameaddr(q, new) &&
+ (bitset(QRCPTOK, q->q_flags) ||
+ !bitset(QPRIMARY, q->q_flags)))
{
-#if _FFR_MILTER
- /*
- ** If an earlier milter removed the address,
- ** a later one can still add it back.
- */
-#endif /* _FFR_MILTER */
- q->q_state = a->q_state;
- q->q_flags |= a->q_flags;
+ if (tTd(26, 1))
+ {
+ sm_dprintf("%s in sendq: ",
+ new->q_paddr);
+ printaddr(q, false);
+ }
+ if (!bitset(QPRIMARY, q->q_flags))
+ {
+ if (!QS_IS_DEAD(new->q_state))
+ message("duplicate suppressed");
+ else
+ q->q_state = QS_DUPLICATE;
+ q->q_flags |= new->q_flags;
+ }
+ else if (bitset(QSELFREF, q->q_flags)
+ || q->q_state == QS_REMOVED)
+ {
+ /*
+ ** If an earlier milter removed the
+ ** address, a later one can still add
+ ** it back.
+ */
+
+ q->q_state = new->q_state;
+ q->q_flags |= new->q_flags;
+ }
+ new = q;
+ goto done;
}
- a = q;
- goto done;
}
+ else if (i < 0) /* less than */
+ {
+ insert = true;
+ break;
+ }
+ prev = pq;
}
+ /* pq should point to an address, never NULL */
+ SM_ASSERT(pq != NULL);
+
/* add address on list */
- if (pq != NULL)
+ if (insert)
{
- *pq = a;
- a->q_next = NULL;
+ /*
+ ** insert before 'pq'. Only possible when at least 1
+ ** ADDRESS is in the list already.
+ */
+
+ new->q_next = *pq;
+ if (prev == NULL)
+ *sendq = new; /* To be the first ADDRESS */
+ else
+ (*prev)->q_next = new;
+ }
+ else
+ {
+ /*
+ ** Place in list at current 'pq' position. Possible
+ ** when there are 0 or more ADDRESS's in the list.
+ */
+
+ new->q_next = NULL;
+ *pq = new;
}
+ /* added a new address: clear split flag */
+ e->e_flags &= ~EF_SPLIT;
+
/*
** Alias the name and handle special mailer types.
*/
@@ -544,108 +792,120 @@ recipient(a, sendq, aliaslevel, e)
trylocaluser:
if (tTd(29, 7))
{
- dprintf("at trylocaluser: ");
- printaddr(a, FALSE);
+ sm_dprintf("at trylocaluser: ");
+ printaddr(new, false);
}
- if (!QS_IS_OK(a->q_state))
+ if (!QS_IS_OK(new->q_state))
+ {
+ if (QS_IS_UNDELIVERED(new->q_state))
+ e->e_nrcpts++;
goto testselfdestruct;
+ }
if (m == InclMailer)
{
- a->q_state = QS_INCLUDED;
- if (a->q_alias == NULL)
+ new->q_state = QS_INCLUDED;
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to :include:s");
}
else
{
int ret;
- message("including file %s", a->q_user);
- ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
+ message("including file %s", new->q_user);
+ ret = include(new->q_user, false, new,
+ sendq, aliaslevel, e);
if (transienterror(ret))
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, e->e_id,
"include %s: transient error: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
- a->q_state = QS_QUEUEUP;
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
+ new->q_state = QS_QUEUEUP;
usrerr("451 4.2.4 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
}
else if (ret != 0)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.2.4";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.2.4";
+ usrerrenh(new->q_status,
"550 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
+ shortenstring(new->q_user,
+ MAXSHORTSTR),
+ sm_errstring(ret));
}
}
}
else if (m == FileMailer)
{
- /* check if writable or creatable */
- if (a->q_alias == NULL)
+ /* check if allowed */
+ if (new->q_alias == NULL || UseMSP ||
+ bitset(EF_UNSAFE, e->e_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ usrerrenh(new->q_status,
"550 Cannot mail directly to files");
}
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
+ else if (bitset(QBOGUSSHELL, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ if (new->q_alias->q_ruser == NULL)
+ usrerrenh(new->q_status,
"550 UID %d is an unknown user: cannot mail to files",
- a->q_alias->q_uid);
+ new->q_alias->q_uid);
else
- usrerrenh(a->q_status,
+ usrerrenh(new->q_status,
"550 User %s@%s doesn't have a valid shell for mailing to files",
- a->q_alias->q_ruser, MyHostName);
+ new->q_alias->q_ruser, MyHostName);
}
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
+ else if (bitset(QUNSAFEADDR, new->q_alias->q_flags))
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("550 Unsafe for mailing to files");
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.7.1";
+ new->q_rstatus = "550 Unsafe for mailing to files";
+ usrerrenh(new->q_status,
"550 Address %s is unsafe for mailing to files",
- a->q_alias->q_paddr);
+ new->q_alias->q_paddr);
}
}
/* try aliasing */
- if (!quoted && QS_IS_OK(a->q_state) &&
+ if (!quoted && QS_IS_OK(new->q_state) &&
bitnset(M_ALIASABLE, m->m_flags))
- alias(a, sendq, aliaslevel, e);
+ alias(new, sendq, aliaslevel, e);
#if USERDB
/* if not aliased, look it up in the user database */
- if (!bitset(QNOTREMOTE, a->q_flags) &&
- QS_IS_SENDABLE(a->q_state) &&
+ if (!bitset(QNOTREMOTE, new->q_flags) &&
+ QS_IS_SENDABLE(new->q_state) &&
bitnset(M_CHECKUDB, m->m_flags))
{
- if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
+ if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL)
{
- a->q_state = QS_QUEUEUP;
+ new->q_state = QS_QUEUEUP;
if (e->e_message == NULL)
- e->e_message = newstr("Deferred: user database error");
+ e->e_message = "Deferred: user database error";
+ if (new->q_message == NULL)
+ new->q_message = "Deferred: user database error";
if (LogLevel > 8)
sm_syslog(LOG_INFO, e->e_id,
"deferred: udbexpand: %s",
- errstring(errno));
+ sm_errstring(errno));
message("queued (user database error): %s",
- errstring(errno));
+ sm_errstring(errno));
e->e_nrcpts++;
goto testselfdestruct;
}
@@ -655,22 +915,22 @@ recipient(a, sendq, aliaslevel, e)
/*
** If we have a level two config file, then pass the name through
** Ruleset 5 before sending it off. Ruleset 5 has the right
- ** to send rewrite it to another mailer. This gives us a hook
+ ** to rewrite it to another mailer. This gives us a hook
** after local aliasing has been done.
*/
if (tTd(29, 5))
{
- dprintf("recipient: testing local? cl=%d, rr5=%lx\n\t",
- ConfigLevel, (u_long) RewriteRules[5]);
- printaddr(a, FALSE);
+ sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t",
+ ConfigLevel, RewriteRules[5]);
+ printaddr(new, false);
}
if (ConfigLevel >= 2 && RewriteRules[5] != NULL &&
bitnset(M_TRYRULESET5, m->m_flags) &&
- !bitset(QNOTREMOTE, a->q_flags) &&
- QS_IS_OK(a->q_state))
+ !bitset(QNOTREMOTE, new->q_flags) &&
+ QS_IS_OK(new->q_state))
{
- maplocaluser(a, sendq, aliaslevel + 1, e);
+ maplocaluser(new, sendq, aliaslevel + 1, e);
}
/*
@@ -678,90 +938,99 @@ recipient(a, sendq, aliaslevel, e)
** and deliver it.
*/
- if (QS_IS_OK(a->q_state) &&
+ if (QS_IS_OK(new->q_state) &&
bitnset(M_HASPWENT, m->m_flags))
{
auto bool fuzzy;
- register struct passwd *pw;
+ SM_MBDB_T user;
+ int status;
/* warning -- finduser may trash buf */
- pw = finduser(buf, &fuzzy);
- if (pw == NULL || strlen(pw->pw_name) > MAXNAME)
- {
- {
- a->q_state = QS_BADADDR;
- a->q_status = "5.1.1";
- a->q_rstatus = newstr("550 5.1.1 User unknown");
- giveresponse(EX_NOUSER, a->q_status, m, NULL,
- a->q_alias, (time_t) 0, e);
- }
- }
- else
+ status = finduser(buf, &fuzzy, &user);
+ switch (status)
{
- char nbuf[MAXNAME + 1];
-
+ case EX_TEMPFAIL:
+ new->q_state = QS_QUEUEUP;
+ new->q_status = "4.5.2";
+ giveresponse(EX_TEMPFAIL, new->q_status, m, NULL,
+ new->q_alias, (time_t) 0, e, new);
+ break;
+ default:
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.1.1";
+ new->q_rstatus = "550 5.1.1 User unknown";
+ giveresponse(EX_NOUSER, new->q_status, m, NULL,
+ new->q_alias, (time_t) 0, e, new);
+ break;
+ case EX_OK:
if (fuzzy)
{
/* name was a fuzzy match */
- a->q_user = newstr(pw->pw_name);
+ new->q_user = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_name);
if (findusercount++ > 3)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop for %s broken",
- pw->pw_name);
+ user.mbdb_name);
goto done;
}
/* see if it aliases */
- (void) strlcpy(buf, pw->pw_name, buflen);
+ (void) sm_strlcpy(buf, user.mbdb_name, buflen);
goto trylocaluser;
}
- if (*pw->pw_dir == '\0')
- a->q_home = NULL;
- else if (strcmp(pw->pw_dir, "/") == 0)
- a->q_home = "";
+ if (*user.mbdb_homedir == '\0')
+ new->q_home = NULL;
+ else if (strcmp(user.mbdb_homedir, "/") == 0)
+ new->q_home = "";
else
- a->q_home = newstr(pw->pw_dir);
- a->q_uid = pw->pw_uid;
- a->q_gid = pw->pw_gid;
- a->q_ruser = newstr(pw->pw_name);
- a->q_flags |= QGOODUID;
- buildfname(pw->pw_gecos, pw->pw_name, nbuf, sizeof nbuf);
- if (nbuf[0] != '\0')
- a->q_fullname = newstr(nbuf);
- if (!usershellok(pw->pw_name, pw->pw_shell))
+ new->q_home = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_homedir);
+ if (user.mbdb_uid != SM_NO_UID)
{
- a->q_flags |= QBOGUSSHELL;
+ new->q_uid = user.mbdb_uid;
+ new->q_gid = user.mbdb_gid;
+ new->q_flags |= QGOODUID;
+ }
+ new->q_ruser = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_name);
+ if (user.mbdb_fullname[0] != '\0')
+ new->q_fullname = sm_rpool_strdup_x(e->e_rpool,
+ user.mbdb_fullname);
+ if (!usershellok(user.mbdb_name, user.mbdb_shell))
+ {
+ new->q_flags |= QBOGUSSHELL;
}
if (bitset(EF_VRFYONLY, e->e_flags))
{
/* don't do any more now */
- a->q_state = QS_VERIFIED;
+ new->q_state = QS_VERIFIED;
}
else if (!quoted)
- forward(a, sendq, aliaslevel, e);
+ forward(new, sendq, aliaslevel, e);
}
}
- if (!QS_IS_DEAD(a->q_state))
+ if (!QS_IS_DEAD(new->q_state))
e->e_nrcpts++;
testselfdestruct:
- a->q_flags |= QTHISPASS;
+ new->q_flags |= QTHISPASS;
if (tTd(26, 8))
{
- dprintf("testselfdestruct: ");
- printaddr(a, FALSE);
+ sm_dprintf("testselfdestruct: ");
+ printaddr(new, false);
if (tTd(26, 10))
{
- dprintf("SENDQ:\n");
- printaddr(*sendq, TRUE);
- dprintf("----\n");
+ sm_dprintf("SENDQ:\n");
+ printaddr(*sendq, true);
+ sm_dprintf("----\n");
}
}
- if (a->q_alias == NULL && a != &e->e_from &&
- QS_IS_DEAD(a->q_state))
+ if (new->q_alias == NULL && new != &e->e_from &&
+ QS_IS_DEAD(new->q_state))
{
for (q = *sendq; q != NULL; q = q->q_next)
{
@@ -770,17 +1039,17 @@ recipient(a, sendq, aliaslevel, e)
}
if (q == NULL)
{
- a->q_state = QS_BADADDR;
- a->q_status = "5.4.6";
- usrerrenh(a->q_status,
+ new->q_state = QS_BADADDR;
+ new->q_status = "5.4.6";
+ usrerrenh(new->q_status,
"554 aliasing/forwarding loop broken");
}
}
done:
- a->q_flags |= QTHISPASS;
+ new->q_flags |= QTHISPASS;
if (buf != buf0)
- sm_free(buf);
+ sm_free(buf); /* XXX leak if above code raises exception */
/*
** If we are at the top level, check to see if this has
@@ -821,18 +1090,20 @@ recipient(a, sendq, aliaslevel, e)
{
/* arrange for return receipt */
e->e_flags |= EF_SENDRECEIPT;
- a->q_flags |= QEXPANDED;
+ new->q_flags |= QEXPANDED;
if (e->e_xfp != NULL &&
- bitset(QPINGONSUCCESS, a->q_flags))
- fprintf(e->e_xfp,
- "%s... expanded to multiple addresses\n",
- a->q_paddr);
+ bitset(QPINGONSUCCESS, new->q_flags))
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "%s... expanded to multiple addresses\n",
+ new->q_paddr);
}
}
- a->q_flags |= QRCPTOK;
- return a;
+ new->q_flags |= QRCPTOK;
+ (void) sm_snprintf(buf0, sizeof buf0, "%d", e->e_nrcpts);
+ macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0);
+ return new;
}
- /*
+/*
** FINDUSER -- find the password entry for a user.
**
** This looks a lot like getpwnam, except that it may want to
@@ -843,33 +1114,39 @@ recipient(a, sendq, aliaslevel, e)
**
** Parameters:
** name -- the name to match against.
-** fuzzyp -- an outarg that is set to TRUE if this entry
+** fuzzyp -- an outarg that is set to true if this entry
** was found using the fuzzy matching algorithm;
-** set to FALSE otherwise.
+** set to false otherwise.
+** user -- structure to fill in if user is found
**
** Returns:
-** A pointer to a pw struct.
-** NULL if name is unknown or ambiguous.
+** On success, fill in *user, set *fuzzyp and return EX_OK.
+** If the user was not found, return EX_NOUSER.
+** On error, return EX_TEMPFAIL or EX_OSERR.
**
** Side Effects:
** may modify name.
*/
-struct passwd *
-finduser(name, fuzzyp)
+int
+finduser(name, fuzzyp, user)
char *name;
bool *fuzzyp;
+ SM_MBDB_T *user;
{
+#if MATCHGECOS
register struct passwd *pw;
+#endif /* MATCHGECOS */
register char *p;
bool tryagain;
+ int status;
if (tTd(29, 4))
- dprintf("finduser(%s): ", name);
+ sm_dprintf("finduser(%s): ", name);
- *fuzzyp = FALSE;
+ *fuzzyp = false;
-#ifdef HESIOD
+#if HESIOD
/* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
for (p = name; *p != '\0'; p++)
if (!isascii(*p) || !isdigit(*p))
@@ -877,35 +1154,36 @@ finduser(name, fuzzyp)
if (*p == '\0')
{
if (tTd(29, 4))
- dprintf("failed (numeric input)\n");
- return NULL;
+ sm_dprintf("failed (numeric input)\n");
+ return EX_NOUSER;
}
#endif /* HESIOD */
/* look up this login name using fast path */
- if ((pw = sm_getpwnam(name)) != NULL)
+ status = sm_mbdb_lookup(name, user);
+ if (status != EX_NOUSER)
{
if (tTd(29, 4))
- dprintf("found (non-fuzzy)\n");
- return pw;
+ sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status));
+ return status;
}
/* try mapping it to lower case */
- tryagain = FALSE;
+ tryagain = false;
for (p = name; *p != '\0'; p++)
{
if (isascii(*p) && isupper(*p))
{
*p = tolower(*p);
- tryagain = TRUE;
+ tryagain = true;
}
}
- if (tryagain && (pw = sm_getpwnam(name)) != NULL)
+ if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER)
{
if (tTd(29, 4))
- dprintf("found (lower case)\n");
- *fuzzyp = TRUE;
- return pw;
+ sm_dprintf("%s (lower case)\n", sm_strexit(status));
+ *fuzzyp = true;
+ return status;
}
#if MATCHGECOS
@@ -913,8 +1191,8 @@ finduser(name, fuzzyp)
if (!MatchGecos)
{
if (tTd(29, 4))
- dprintf("not found (fuzzy disabled)\n");
- return NULL;
+ sm_dprintf("not found (fuzzy disabled)\n");
+ return EX_NOUSER;
}
/* search for a matching full name instead */
@@ -929,38 +1207,41 @@ finduser(name, fuzzyp)
char buf[MAXNAME + 1];
# if 0
- if (strcasecmp(pw->pw_name, name) == 0)
+ if (sm_strcasecmp(pw->pw_name, name) == 0)
{
if (tTd(29, 4))
- dprintf("found (case wrapped)\n");
+ sm_dprintf("found (case wrapped)\n");
break;
}
# endif /* 0 */
- buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
- if (strchr(buf, ' ') != NULL && strcasecmp(buf, name) == 0)
+ sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
+ if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0)
{
if (tTd(29, 4))
- dprintf("fuzzy matches %s\n", pw->pw_name);
+ sm_dprintf("fuzzy matches %s\n", pw->pw_name);
message("sending to login name %s", pw->pw_name);
break;
}
}
if (pw != NULL)
- *fuzzyp = TRUE;
+ *fuzzyp = true;
else if (tTd(29, 4))
- dprintf("no fuzzy match found\n");
+ sm_dprintf("no fuzzy match found\n");
# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */
endpwent();
# endif /* DEC_OSF_BROKEN_GETPWENT */
- return pw;
+ if (pw == NULL)
+ return EX_NOUSER;
+ sm_mbdb_frompw(user, pw);
+ return EX_OK;
#else /* MATCHGECOS */
if (tTd(29, 4))
- dprintf("not found (fuzzy disabled)\n");
- return NULL;
+ sm_dprintf("not found (fuzzy disabled)\n");
+ return EX_NOUSER;
#endif /* MATCHGECOS */
}
- /*
+/*
** WRITABLE -- predicate returning if the file is writable.
**
** This routine must duplicate the algorithm in sys/fio.c.
@@ -977,8 +1258,8 @@ finduser(name, fuzzyp)
** flags -- SFF_* flags to control the function.
**
** Returns:
-** TRUE -- if we will be able to write this file.
-** FALSE -- if we cannot write this file.
+** true -- if we will be able to write this file.
+** false -- if we cannot write this file.
**
** Side Effects:
** none.
@@ -995,7 +1276,7 @@ writable(filename, ctladdr, flags)
char *user = NULL;
if (tTd(44, 5))
- dprintf("writable(%s, 0x%lx)\n", filename, flags);
+ sm_dprintf("writable(%s, 0x%lx)\n", filename, flags);
/*
** File does exist -- check that it is writable.
@@ -1052,13 +1333,13 @@ writable(filename, ctladdr, flags)
errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL);
return errno == 0;
}
- /*
+/*
** INCLUDE -- handle :include: specification.
**
** Parameters:
** fname -- filename to include.
-** forwarding -- if TRUE, we are reading a .forward file.
-** if FALSE, it's a :include: file.
+** forwarding -- if true, we are reading a .forward file.
+** if false, it's a :include: file.
** ctladdr -- address template to use to fill in these
** addresses -- effective user/group id are
** the important things.
@@ -1099,14 +1380,14 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
int aliaslevel;
ENVELOPE *e;
{
- FILE *volatile fp = NULL;
+ SM_FILE_T *volatile fp = NULL;
char *oldto = e->e_to;
char *oldfilename = FileName;
int oldlinenumber = LineNumber;
- register EVENT *ev = NULL;
+ register SM_EVENT *ev = NULL;
int nincludes;
int mode;
- volatile bool maxreached = FALSE;
+ volatile bool maxreached = false;
register ADDRESS *ca;
volatile uid_t saveduid;
volatile gid_t savedgid;
@@ -1116,29 +1397,29 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
int rval = 0;
volatile long sfflags = SFF_REGONLY;
register char *p;
- bool safechown = FALSE;
- volatile bool safedir = FALSE;
+ bool safechown = false;
+ volatile bool safedir = false;
struct stat st;
char buf[MAXLINE];
if (tTd(27, 2))
- dprintf("include(%s)\n", fname);
+ sm_dprintf("include(%s)\n", fname);
if (tTd(27, 4))
- dprintf(" ruid=%d euid=%d\n",
+ sm_dprintf(" ruid=%d euid=%d\n",
(int) getuid(), (int) geteuid());
if (tTd(27, 14))
{
- dprintf("ctladdr ");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("ctladdr ");
+ printaddr(ctladdr, false);
}
if (tTd(27, 9))
- dprintf("include: old uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: old uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
-#if _FFR_UNSAFE_WRITABLE_INCLUDE
if (forwarding)
{
+ sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;
if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail))
sfflags |= SFF_NOGWFILES;
if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail))
@@ -1151,10 +1432,6 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail))
sfflags |= SFF_NOWWFILES;
}
-#endif /* _FFR_UNSAFE_WRITABLE_INCLUDE */
-
- if (forwarding)
- sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;
/*
** If RunAsUser set, won't be able to run programs as user
@@ -1165,8 +1442,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
!bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail))
{
if (tTd(27, 4))
- dprintf("include: not safe (euid=%d, RunAsUid=%d)\n",
- (int) geteuid(), (int) RunAsUid);
+ sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n",
+ (int) geteuid(), (int) RunAsUid);
ctladdr->q_flags |= QUNSAFEADDR;
}
@@ -1243,8 +1520,8 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
#endif /* MAILER_SETUID_METHOD != USE_SETUID */
if (tTd(27, 9))
- dprintf("include: new uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: new uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
/*
** If home directory is remote mounted but server is down,
@@ -1261,7 +1538,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
goto resetuid;
}
if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
+ ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0);
else
ev = NULL;
@@ -1278,7 +1555,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
if (ret == 0)
{
/* in safe directory: relax chown & link rules */
- safedir = TRUE;
+ safedir = true;
sfflags |= SFF_NOPATHCHECK;
}
else
@@ -1314,7 +1591,7 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
DontBlameSendmail))
{
- if (LogLevel >= 12)
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: unsafe directory path, marked unsafe",
shortenstring(fname, MAXSHORTSTR));
@@ -1337,23 +1614,24 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
{
/* don't use this :include: file */
if (tTd(27, 4))
- dprintf("include: not safe (uid=%d): %s\n",
- (int) uid, errstring(rval));
+ sm_dprintf("include: not safe (uid=%d): %s\n",
+ (int) uid, sm_errstring(rval));
}
- else if ((fp = fopen(fname, "r")) == NULL)
+ else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname,
+ SM_IO_RDONLY, NULL)) == NULL)
{
rval = errno;
if (tTd(27, 4))
- dprintf("include: open: %s\n", errstring(rval));
+ sm_dprintf("include: open: %s\n", sm_errstring(rval));
}
- else if (filechanged(fname, fileno(fp), &st))
+ else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st))
{
rval = E_SM_FILECHANGE;
if (tTd(27, 4))
- dprintf("include: file changed after open\n");
+ sm_dprintf("include: file changed after open\n");
}
if (ev != NULL)
- clrevent(ev);
+ sm_clrevent(ev);
resetuid:
@@ -1365,25 +1643,27 @@ resetuid:
# if USESETEUID
if (seteuid(0) < 0)
syserr("!seteuid(0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
+ (int) getuid(), (int) geteuid());
# else /* USESETEUID */
if (setreuid(-1, 0) < 0)
syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
+ (int) getuid(), (int) geteuid());
if (setreuid(RealUid, 0) < 0)
syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)",
- RealUid, getuid(), geteuid());
+ (int) RealUid, (int) getuid(),
+ (int) geteuid());
# endif /* USESETEUID */
}
if (setgid(savedgid) < 0)
syserr("!setgid(%d) failure (real=%d eff=%d)",
- savedgid, getgid(), getegid());
+ (int) savedgid, (int) getgid(),
+ (int) getegid());
}
#endif /* HASSETREUID || USESETEUID */
if (tTd(27, 9))
- dprintf("include: reset uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
+ sm_dprintf("include: reset uid = %d/%d\n",
+ (int) getuid(), (int) geteuid());
if (rval == E_SM_OPENTIMEOUT)
usrerr("451 4.4.1 open timeout on %s", fname);
@@ -1391,21 +1671,20 @@ resetuid:
if (fp == NULL)
return rval;
- if (fstat(fileno(fp), &st) < 0)
+ if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0)
{
rval = errno;
syserr("Cannot fstat %s!", fname);
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
return rval;
}
/* if path was writable, check to avoid file giveaway tricks */
- safechown = chownsafe(fileno(fp), safedir);
+ safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir);
if (tTd(27, 6))
- dprintf("include: parent of %s is %s, chown is %ssafe\n",
- fname,
- safedir ? "safe" : "dangerous",
- safechown ? "" : "un");
+ sm_dprintf("include: parent of %s is %s, chown is %ssafe\n",
+ fname, safedir ? "safe" : "dangerous",
+ safechown ? "" : "un");
/* if no controlling user or coming from an alias delivery */
if (safechown &&
@@ -1436,17 +1715,19 @@ resetuid:
{
char *sh;
- ctladdr->q_ruser = newstr(pw->pw_name);
+ ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool,
+ pw->pw_name);
if (safechown)
sh = pw->pw_shell;
else
sh = "/SENDMAIL/ANY/SHELL/";
if (!usershellok(pw->pw_name, sh))
{
- if (LogLevel >= 12)
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: user %s has bad shell %s, marked %s",
- shortenstring(fname, MAXSHORTSTR),
+ shortenstring(fname,
+ MAXSHORTSTR),
pw->pw_name, sh,
safechown ? "bogus" : "unsafe");
if (safechown)
@@ -1462,7 +1743,7 @@ resetuid:
/* don't do any more now */
ctladdr->q_state = QS_VERIFIED;
e->e_nrcpts++;
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
return rval;
}
@@ -1484,10 +1765,11 @@ resetuid:
if (bitset(mode, st.st_mode))
{
if (tTd(27, 6))
- dprintf("include: %s is %s writable, marked unsafe\n",
- shortenstring(fname, MAXSHORTSTR),
- bitset(S_IWOTH, st.st_mode) ? "world" : "group");
- if (LogLevel >= 12)
+ sm_dprintf("include: %s is %s writable, marked unsafe\n",
+ shortenstring(fname, MAXSHORTSTR),
+ bitset(S_IWOTH, st.st_mode) ? "world"
+ : "group");
+ if (LogLevel > 11)
sm_syslog(LOG_INFO, e->e_id,
"%s: %s writable %s file, marked unsafe",
shortenstring(fname, MAXSHORTSTR),
@@ -1501,9 +1783,10 @@ resetuid:
LineNumber = 0;
ctladdr->q_flags &= ~QSELFREF;
nincludes = 0;
- while (fgets(buf, sizeof buf, fp) != NULL && !maxreached)
+ while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL &&
+ !maxreached)
{
- fixcrlf(buf, TRUE);
+ fixcrlf(buf, true);
LineNumber++;
if (buf[0] == '#' || buf[0] == '\0')
continue;
@@ -1542,28 +1825,30 @@ resetuid:
nincludes >= MaxForwardEntries)
{
/* just stop reading and processing further entries */
- /* additional: (?)
+#if 0
+ /* additional: (?) */
ctladdr->q_state = QS_DONTSEND;
- **/
- syserr("Attempt to forward to more then %d addresses (in %s)!",
+#endif /* 0 */
+
+ syserr("Attempt to forward to more than %d addresses (in %s)!",
MaxForwardEntries,fname);
- maxreached = TRUE;
+ maxreached = true;
}
}
- if (ferror(fp) && tTd(27, 3))
- dprintf("include: read error: %s\n", errstring(errno));
+ if (sm_io_error(fp) && tTd(27, 3))
+ sm_dprintf("include: read error: %s\n", sm_errstring(errno));
if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
{
if (tTd(27, 5))
{
- dprintf("include: QS_DONTSEND ");
- printaddr(ctladdr, FALSE);
+ sm_dprintf("include: QS_DONTSEND ");
+ printaddr(ctladdr, false);
}
ctladdr->q_state = QS_DONTSEND;
}
- (void) fclose(fp);
+ (void) sm_io_close(fp, SM_TIME_DEFAULT);
FileName = oldfilename;
LineNumber = oldlinenumber;
e->e_to = oldto;
@@ -1582,7 +1867,7 @@ includetimeout()
errno = ETIMEDOUT;
longjmp(CtxIncludeTimeout, 1);
}
- /*
+/*
** SENDTOARGV -- send to an argument vector.
**
** Parameters:
@@ -1605,11 +1890,9 @@ sendtoargv(argv, e)
register char *p;
while ((p = *argv++) != NULL)
- {
(void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
- }
}
- /*
+/*
** GETCTLADDR -- get controlling address from an address header.
**
** If none, get one corresponding to the effective userid.
@@ -1619,9 +1902,6 @@ sendtoargv(argv, e)
**
** Returns:
** the controlling address.
-**
-** Side Effects:
-** none.
*/
ADDRESS *
@@ -1632,7 +1912,7 @@ getctladdr(a)
a = a->q_alias;
return a;
}
- /*
+/*
** SELF_REFERENCE -- check to see if an address references itself
**
** The check is done through a chain of aliases. If it is part of
@@ -1659,7 +1939,7 @@ self_reference(a)
ADDRESS *c; /* entry that point to a real mail box */
if (tTd(27, 1))
- dprintf("self_reference(%s)\n", a->q_paddr);
+ sm_dprintf("self_reference(%s)\n", a->q_paddr);
for (b = a->q_alias; b != NULL; b = b->q_alias)
{
@@ -1670,40 +1950,42 @@ self_reference(a)
if (b == NULL)
{
if (tTd(27, 1))
- dprintf("\t... no self ref\n");
+ sm_dprintf("\t... no self ref\n");
return NULL;
}
/*
** Pick the first address that resolved to a real mail box
- ** i.e has a pw entry. The returned value will be marked
+ ** i.e has a mbdb entry. The returned value will be marked
** QSELFREF in recipient(), which in turn will disable alias()
** from marking it as QS_IS_DEAD(), which mean it will be used
** as a deliverable address.
**
** The 2 key thing to note here are:
** 1) we are in a recursive call sequence:
- ** alias->sentolist->recipient->alias
+ ** alias->sendtolist->recipient->alias
** 2) normally, when we return back to alias(), the address
** will be marked QS_EXPANDED, since alias() assumes the
** expanded form will be used instead of the current address.
** This behaviour is turned off if the address is marked
- ** QSELFREF We set QSELFREF when we return to recipient().
+ ** QSELFREF. We set QSELFREF when we return to recipient().
*/
c = a;
while (c != NULL)
{
if (tTd(27, 10))
- dprintf(" %s", c->q_user);
+ sm_dprintf(" %s", c->q_user);
if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
{
+ SM_MBDB_T user;
+
if (tTd(27, 2))
- dprintf("\t... getpwnam(%s)... ", c->q_user);
- if (sm_getpwnam(c->q_user) != NULL)
+ sm_dprintf("\t... getpwnam(%s)... ", c->q_user);
+ if (sm_mbdb_lookup(c->q_user, &user) == EX_OK)
{
if (tTd(27, 2))
- dprintf("found\n");
+ sm_dprintf("found\n");
/* ought to cache results here */
if (sameaddr(b, c))
@@ -1712,7 +1994,7 @@ self_reference(a)
return c;
}
if (tTd(27, 2))
- dprintf("failed\n");
+ sm_dprintf("failed\n");
}
else
{
@@ -1721,7 +2003,7 @@ self_reference(a)
b->q_mailer == c->q_mailer)
{
if (tTd(27, 2))
- dprintf("\t... local match (%s)\n",
+ sm_dprintf("\t... local match (%s)\n",
c->q_user);
if (sameaddr(b, c))
return b;
@@ -1730,12 +2012,12 @@ self_reference(a)
}
}
if (tTd(27, 10))
- dprintf("\n");
+ sm_dprintf("\n");
c = c->q_alias;
}
if (tTd(27, 1))
- dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
+ sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
return NULL;
}
diff --git a/contrib/sendmail/src/sasl.c b/contrib/sendmail/src/sasl.c
new file mode 100644
index 0000000..9136f8a
--- /dev/null
+++ b/contrib/sendmail/src/sasl.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#if SASL
+# include <sm/gen.h>
+SM_RCSID("@(#)$Id: sasl.c,v 8.11 2001/09/11 04:05:16 gshapiro Exp $")
+# include <stdlib.h>
+# include <sendmail.h>
+# include <errno.h>
+# include <sasl.h>
+
+/*
+** In order to ensure that storage leaks are tracked, and to prevent
+** conflicts between the sm_heap package and sasl, we tell sasl to
+** use the following heap allocation functions. Unfortunately,
+** the sasl package incorrectly specifies the size of a block
+** using unsigned long: for portability, it should be size_t.
+*/
+
+void *sm_sasl_malloc __P((unsigned long));
+static void *sm_sasl_calloc __P((unsigned long, unsigned long));
+static void *sm_sasl_realloc __P((void *, unsigned long));
+void sm_sasl_free __P((void *));
+
+/*
+** We can't use an rpool for Cyrus-SASL memory management routines,
+** since the encryption/decryption routines in Cyrus-SASL
+** allocate/deallocate a buffer each time. Since rpool
+** don't release memory until the very end, memory consumption is
+** proportional to the size of an e-mail, which is unacceptable.
+**
+*/
+
+/*
+** SM_SASL_MALLOC -- malloc() for SASL
+**
+** Parameters:
+** size -- size of requested memory.
+**
+** Returns:
+** pointer to memory.
+*/
+
+void *
+sm_sasl_malloc(size)
+ unsigned long size;
+{
+ return sm_malloc((size_t) size);
+}
+
+/*
+** SM_SASL_CALLOC -- calloc() for SASL
+**
+** Parameters:
+** nelem -- number of elements.
+** elemsize -- size of each element.
+**
+** Returns:
+** pointer to memory.
+**
+** Notice:
+** this isn't currently used by SASL.
+*/
+
+static void *
+sm_sasl_calloc(nelem, elemsize)
+ unsigned long nelem;
+ unsigned long elemsize;
+{
+ size_t size;
+ void *p;
+
+ size = (size_t) nelem * (size_t) elemsize;
+ p = sm_malloc(size);
+ if (p == NULL)
+ return NULL;
+ memset(p, '\0', size);
+ return p;
+}
+
+/*
+** SM_SASL_REALLOC -- realloc() for SASL
+**
+** Parameters:
+** p -- pointer to old memory.
+** size -- size of requested memory.
+**
+** Returns:
+** pointer to new memory.
+*/
+
+static void *
+sm_sasl_realloc(o, size)
+ void *o;
+ unsigned long size;
+{
+ return sm_realloc(o, (size_t) size);
+}
+
+/*
+** SM_SASL_FREE -- free() for SASL
+**
+** Parameters:
+** p -- pointer to free.
+**
+** Returns:
+** none
+*/
+
+void
+sm_sasl_free(p)
+ void *p;
+{
+ sm_free(p);
+}
+
+/*
+** SM_SASL_INIT -- sendmail specific SASL initialization
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none
+**
+** Side Effects:
+** installs memory management routines for SASL.
+*/
+
+void
+sm_sasl_init()
+{
+ sasl_set_alloc(sm_sasl_malloc, sm_sasl_calloc,
+ sm_sasl_realloc, sm_sasl_free);
+}
+/*
+** INTERSECT -- create the intersection between two lists
+**
+** Parameters:
+** s1, s2 -- lists of items (separated by single blanks).
+** rpool -- resource pool from which result is allocated.
+**
+** Returns:
+** the intersection of both lists.
+*/
+
+char *
+intersect(s1, s2, rpool)
+ char *s1, *s2;
+ SM_RPOOL_T *rpool;
+{
+ char *hr, *h1, *h, *res;
+ int l1, l2, rl;
+
+ if (s1 == NULL || s2 == NULL) /* NULL string(s) -> NULL result */
+ return NULL;
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+ rl = SM_MIN(l1, l2);
+ res = (char *) sm_rpool_malloc(rpool, rl + 1);
+ if (res == NULL)
+ return NULL;
+ *res = '\0';
+ if (rl == 0) /* at least one string empty? */
+ return res;
+ hr = res;
+ h1 = s1;
+ h = s1;
+
+ /* walk through s1 */
+ while (h != NULL && *h1 != '\0')
+ {
+ /* is there something after the current word? */
+ if ((h = strchr(h1, ' ')) != NULL)
+ *h = '\0';
+ l1 = strlen(h1);
+
+ /* does the current word appear in s2 ? */
+ if (iteminlist(h1, s2, " ") != NULL)
+ {
+ /* add a blank if not first item */
+ if (hr != res)
+ *hr++ = ' ';
+
+ /* copy the item */
+ memcpy(hr, h1, l1);
+
+ /* advance pointer in result list */
+ hr += l1;
+ *hr = '\0';
+ }
+ if (h != NULL)
+ {
+ /* there are more items */
+ *h = ' ';
+ h1 = h + 1;
+ }
+ }
+ return res;
+}
+#endif /* SASL */
diff --git a/contrib/sendmail/src/savemail.c b/contrib/sendmail/src/savemail.c
index fb7f8fd..c7fe609 100644
--- a/contrib/sendmail/src/savemail.c
+++ b/contrib/sendmail/src/savemail.c
@@ -11,12 +11,9 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: savemail.c,v 8.212.4.13 2001/05/03 17:24:15 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: savemail.c,v 8.297 2001/12/28 22:32:19 ca Exp $")
static void errbody __P((MCI *, ENVELOPE *, char *));
static bool pruneroute __P((char *));
@@ -31,11 +28,12 @@ static bool pruneroute __P((char *));
**
** Parameters:
** e -- the envelope containing the message in error.
-** sendbody -- if TRUE, also send back the body of the
+** sendbody -- if true, also send back the body of the
** message; otherwise just send the header.
**
** Returns:
-** none
+** true if savemail panic'ed, (i.e., the data file should
+** be preserved by dropenvelope())
**
** Side Effects:
** Saves the letter, by writing or mailing it back to the
@@ -53,14 +51,13 @@ static bool pruneroute __P((char *));
#define ESM_PANIC 6 /* call loseqfile() */
#define ESM_DONE 7 /* message is successfully delivered */
-
-void
+bool
savemail(e, sendbody)
register ENVELOPE *e;
bool sendbody;
{
- register struct passwd *pw;
- register FILE *fp;
+ register SM_FILE_T *fp;
+ bool panic = false;
int state;
auto ADDRESS *q = NULL;
register char *p;
@@ -68,19 +65,21 @@ savemail(e, sendbody)
int flags;
long sff;
char buf[MAXLINE + 1];
+ SM_MBDB_T user;
+
if (tTd(6, 1))
{
- dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
+ sm_dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
ExitStat);
- printaddr(&e->e_from, FALSE);
+ printaddr(&e->e_from, false);
}
if (e->e_id == NULL)
{
/* can't return a message with no id */
- return;
+ return panic;
}
/*
@@ -92,10 +91,11 @@ savemail(e, sendbody)
{
e->e_sender = "Postmaster";
if (parseaddr(e->e_sender, &e->e_from,
- RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
+ RF_COPYPARSE|RF_SENDERADDR,
+ '\0', NULL, e, false) == NULL)
{
syserr("553 5.3.5 Cannot parse Postmaster!");
- finis(TRUE, EX_SOFTWARE);
+ finis(true, true, EX_SOFTWARE);
}
}
e->e_to = NULL;
@@ -135,10 +135,10 @@ savemail(e, sendbody)
case EM_QUIET:
/* no need to return anything at all */
- return;
+ return panic;
default:
- syserr("554 5.3.0 savemail: bogus errormode x%x\n",
+ syserr("554 5.3.0 savemail: bogus errormode x%x",
e->e_errormode);
state = ESM_MAIL;
break;
@@ -151,7 +151,7 @@ savemail(e, sendbody)
bitset(EF_RESPONSE, e->e_parent->e_flags))
{
/* got an error sending a response -- can it */
- return;
+ return panic;
}
state = ESM_POSTMASTER;
}
@@ -159,7 +159,7 @@ savemail(e, sendbody)
while (state != ESM_DONE)
{
if (tTd(6, 5))
- dprintf(" state %d\n", state);
+ sm_dprintf(" state %d\n", state);
switch (state)
{
@@ -178,29 +178,41 @@ savemail(e, sendbody)
*/
p = ttypath();
- if (p == NULL || freopen(p, "w", stdout) == NULL)
+ if (p == NULL || sm_io_reopen(SmFtStdio,
+ SM_TIME_DEFAULT,
+ p, SM_IO_WRONLY, NULL,
+ smioout) == NULL)
{
state = ESM_MAIL;
break;
}
expand("\201n", buf, sizeof buf, e);
- printf("\r\nMessage from %s...\r\n", buf);
- printf("Errors occurred while sending mail.\r\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "\r\nMessage from %s...\r\n", buf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Errors occurred while sending mail.\r\n");
if (e->e_xfp != NULL)
{
(void) bfrewind(e->e_xfp);
- printf("Transcript follows:\r\n");
- while (fgets(buf, sizeof buf, e->e_xfp) != NULL &&
- !ferror(stdout))
- (void) fputs(buf, stdout);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Transcript follows:\r\n");
+ while (sm_io_fgets(e->e_xfp, SM_TIME_DEFAULT,
+ buf, sizeof buf) != NULL &&
+ !sm_io_error(smioout))
+ (void) sm_io_fputs(smioout,
+ SM_TIME_DEFAULT,
+ buf);
}
else
{
- syserr("Cannot open %s", queuename(e, 'x'));
- printf("Transcript of session is unavailable.\r\n");
+ syserr("Cannot open %s",
+ queuename(e, XSCRPT_LETTER));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Transcript of session is unavailable.\r\n");
}
- printf("Original message will be saved in dead.letter.\r\n");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Original message will be saved in dead.letter.\r\n");
state = ESM_DEADLETTER;
break;
@@ -225,32 +237,23 @@ savemail(e, sendbody)
if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
{
- (void) sendtolist("postmaster",
- NULLADDR, &e->e_errorqueue, 0, e);
+ (void) sendtolist("postmaster", NULLADDR,
+ &e->e_errorqueue, 0, e);
}
if (!emptyaddr(&e->e_from))
{
char from[TOBUFSIZE];
- if (strlen(e->e_from.q_paddr) >= sizeof from)
+ if (sm_strlcpy(from, e->e_from.q_paddr,
+ sizeof from) >= sizeof from)
{
state = ESM_POSTMASTER;
break;
}
- (void) strlcpy(from, e->e_from.q_paddr,
- sizeof from);
- if (!DontPruneRoutes && pruneroute(from))
- {
- ADDRESS *a;
-
- for (a = e->e_errorqueue; a != NULL;
- a = a->q_next)
- {
- if (sameaddr(a, &e->e_from))
- a->q_state = QS_DUPLICATE;
- }
- }
+ if (!DontPruneRoutes)
+ (void) pruneroute(from);
+
(void) sendtolist(from, NULLADDR,
&e->e_errorqueue, 0, e);
}
@@ -297,6 +300,17 @@ savemail(e, sendbody)
q = NULL;
expand(DoubleBounceAddr, buf, sizeof buf, e);
+
+ /*
+ ** Just drop it on the floor if DoubleBounceAddr
+ ** expands to an empty string.
+ */
+
+ if (*buf == '\0')
+ {
+ state = ESM_DONE;
+ break;
+ }
if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
{
syserr("553 5.3.0 cannot parse %s!", buf);
@@ -332,9 +346,10 @@ savemail(e, sendbody)
{
if (e->e_from.q_home != NULL)
p = e->e_from.q_home;
- else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL &&
- *pw->pw_dir != '\0')
- p = pw->pw_dir;
+ else if (sm_mbdb_lookup(e->e_from.q_user, &user)
+ == EX_OK &&
+ *user.mbdb_homedir != '\0')
+ p = user.mbdb_homedir;
}
if (p == NULL || e->e_dfp == NULL)
{
@@ -344,11 +359,11 @@ savemail(e, sendbody)
}
/* we have a home directory; write dead.letter */
- define('z', p, e);
+ macdefine(&e->e_macro, A_TEMP, 'z', p);
/* get the sender for the UnixFromLine */
p = macvalue('g', e);
- define('g', e->e_sender, e);
+ macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
expand("\201z/dead.letter", buf, sizeof buf, e);
sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
@@ -365,11 +380,11 @@ savemail(e, sendbody)
if (Verbose > 0)
message("Saved message in %s", buf);
Verbose = oldverb;
- define('g', p, e);
+ macdefine(&e->e_macro, A_PERM, 'g', p);
state = ESM_DONE;
break;
}
- define('g', p, e);
+ macdefine(&e->e_macro, A_PERM, 'g', p);
state = ESM_MAIL;
break;
@@ -409,15 +424,15 @@ savemail(e, sendbody)
/* get the sender for the UnixFromLine */
p = macvalue('g', e);
- define('g', e->e_sender, e);
+ macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
putfromline(&mcibuf, e);
(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
(*e->e_putbody)(&mcibuf, e, NULL);
- putline("\n", &mcibuf);
- (void) fflush(fp);
- if (ferror(fp) ||
- fclose(fp) < 0)
+ putline("\n", &mcibuf); /* XXX EOL from FileMailer? */
+ (void) sm_io_flush(fp, SM_TIME_DEFAULT);
+ if (sm_io_error(fp) ||
+ sm_io_close(fp, SM_TIME_DEFAULT) < 0)
state = ESM_PANIC;
else
{
@@ -435,23 +450,26 @@ savemail(e, sendbody)
DeadLetterDrop);
state = ESM_DONE;
}
- define('g', p, e);
+ macdefine(&e->e_macro, A_PERM, 'g', p);
break;
default:
syserr("554 5.3.5 savemail: unknown state %d", state);
-
/* FALLTHROUGH */
case ESM_PANIC:
/* leave the locked queue & transcript files around */
loseqfile(e, "savemail panic");
+ panic = true;
errno = 0;
- syserr("!554 savemail: cannot save rejected email anywhere");
+ syserr("554 savemail: cannot save rejected email anywhere");
+ state = ESM_DONE;
+ break;
}
}
+ return panic;
}
- /*
+/*
** RETURNTOSENDER -- return a message to the sender with an error.
**
** Parameters:
@@ -468,12 +486,11 @@ savemail(e, sendbody)
** else -- some error.
**
** Side Effects:
-** Returns the current message to the sender via
-** mail.
+** Returns the current message to the sender via mail.
*/
#define MAXRETURNS 6 /* max depth of returning messages */
-#define ERRORFUDGE 100 /* nominal size of error message text */
+#define ERRORFUDGE 1024 /* nominal size of error message text */
int
returntosender(msg, returnq, flags, e)
@@ -498,13 +515,13 @@ returntosender(msg, returnq, flags, e)
if (tTd(6, 1))
{
- dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=",
- msg, returndepth, (u_long) e);
- printaddr(returnq, TRUE);
+ sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=",
+ msg, returndepth, e);
+ printaddr(returnq, true);
if (tTd(6, 20))
{
- dprintf("Sendq=");
- printaddr(e->e_sendqueue, TRUE);
+ sm_dprintf("Sendq=");
+ printaddr(e->e_sendqueue, true);
}
}
@@ -518,32 +535,32 @@ returntosender(msg, returnq, flags, e)
return 0;
}
- define('g', e->e_sender, e);
- define('u', NULL, e);
+ macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
+ macdefine(&e->e_macro, A_PERM, 'u', NULL);
/* initialize error envelope */
- ee = newenvelope(&errenvelope, e);
- define('a', "\201b", ee);
- define('r', "", ee);
- define('s', "localhost", ee);
- define('_', "localhost", ee);
+ ee = newenvelope(&errenvelope, e, sm_rpool_new_x(NULL));
+ macdefine(&ee->e_macro, A_PERM, 'a', "\201b");
+ macdefine(&ee->e_macro, A_PERM, 'r', "");
+ macdefine(&ee->e_macro, A_PERM, 's', "localhost");
+ macdefine(&ee->e_macro, A_PERM, '_', "localhost");
#if SASL
- define(macid("{auth_type}", NULL), "", ee);
- define(macid("{auth_authen}", NULL), "", ee);
- define(macid("{auth_author}", NULL), "", ee);
- define(macid("{auth_ssf}", NULL), "", ee);
+ macdefine(&ee->e_macro, A_PERM, macid("{auth_type}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{auth_authen}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{auth_author}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{auth_ssf}"), "");
#endif /* SASL */
#if STARTTLS
- define(macid("{cert_issuer}", NULL), "", ee);
- define(macid("{cert_subject}", NULL), "", ee);
- define(macid("{cipher_bits}", NULL), "", ee);
- define(macid("{cipher}", NULL), "", ee);
- define(macid("{tls_version}", NULL), "", ee);
- define(macid("{verify}", NULL), "", ee);
+ macdefine(&ee->e_macro, A_PERM, macid("{cert_issuer}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{cert_subject}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{cipher_bits}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{cipher}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{tls_version}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{verify}"), "");
# if _FFR_TLS_1
- define(macid("{alg_bits}", NULL), "", ee);
- define(macid("{cn_issuer}", NULL), "", ee);
- define(macid("{cn_subject}", NULL), "", ee);
+ macdefine(&ee->e_macro, A_PERM, macid("{alg_bits}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{cn_issuer}"), "");
+ macdefine(&ee->e_macro, A_PERM, macid("{cn_subject}"), "");
# endif /* _FFR_TLS_1 */
#endif /* STARTTLS */
@@ -567,12 +584,21 @@ returntosender(msg, returnq, flags, e)
}
ee->e_sendqueue = returnq;
- ee->e_msgsize = ERRORFUDGE;
+ ee->e_msgsize = 0;
if (bitset(RTSF_SEND_BODY, flags) &&
!bitset(PRIV_NOBODYRETN, PrivacyFlags))
- ee->e_msgsize += e->e_msgsize;
+ ee->e_msgsize = ERRORFUDGE + e->e_msgsize;
else
ee->e_flags |= EF_NO_BODY_RETN;
+
+ if (!setnewqueue(ee))
+ {
+ syserr("554 5.3.0 returntosender: cannot select queue for %s",
+ returnq->q_paddr);
+ ExitStat = EX_UNAVAILABLE;
+ returndepth--;
+ return -1;
+ }
initsys(ee);
#if NAMED_BIND
@@ -591,7 +617,7 @@ returntosender(msg, returnq, flags, e)
ee->e_nrcpts++;
if (q->q_alias == NULL)
- addheader("To", q->q_paddr, 0, &ee->e_header);
+ addheader("To", q->q_paddr, 0, ee);
}
if (LogLevel > 5)
@@ -604,72 +630,69 @@ returntosender(msg, returnq, flags, e)
p = "postmaster notify";
else
p = "DSN";
- sm_syslog(LOG_INFO, e->e_id,
- "%s: %s: %s",
+ sm_syslog(LOG_INFO, e->e_id, "%s: %s: %s",
ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
}
if (SendMIMEErrors)
{
- addheader("MIME-Version", "1.0", 0, &ee->e_header);
-
- (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
- ee->e_id, (long) curtime(), MyHostName);
- ee->e_msgboundary = newstr(buf);
- (void) snprintf(buf, sizeof buf,
+ addheader("MIME-Version", "1.0", 0, ee);
+ (void) sm_snprintf(buf, sizeof buf, "%s.%ld/%.100s",
+ ee->e_id, (long)curtime(), MyHostName);
+ ee->e_msgboundary = sm_rpool_strdup_x(ee->e_rpool, buf);
+ (void) sm_snprintf(buf, sizeof buf,
#if DSN
"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
#else /* DSN */
"multipart/mixed; boundary=\"%s\"",
#endif /* DSN */
ee->e_msgboundary);
- addheader("Content-Type", buf, 0, &ee->e_header);
+ addheader("Content-Type", buf, 0, ee);
p = hvalue("Content-Transfer-Encoding", e->e_header);
- if (p != NULL && strcasecmp(p, "binary") != 0)
+ if (p != NULL && sm_strcasecmp(p, "binary") != 0)
p = NULL;
if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
p = "8bit";
if (p != NULL)
- addheader("Content-Transfer-Encoding",
- p, 0, &ee->e_header);
+ addheader("Content-Transfer-Encoding", p, 0, ee);
}
if (strncmp(msg, "Warning:", 8) == 0)
{
- addheader("Subject", msg, 0, &ee->e_header);
+ addheader("Subject", msg, 0, ee);
p = "warning-timeout";
}
else if (strncmp(msg, "Postmaster warning:", 19) == 0)
{
- addheader("Subject", msg, 0, &ee->e_header);
+ addheader("Subject", msg, 0, ee);
p = "postmaster-warning";
}
else if (strcmp(msg, "Return receipt") == 0)
{
- addheader("Subject", msg, 0, &ee->e_header);
+ addheader("Subject", msg, 0, ee);
p = "return-receipt";
}
else if (bitset(RTSF_PM_BOUNCE, flags))
{
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Postmaster notify: see transcript for details");
- addheader("Subject", buf, 0, &ee->e_header);
+ addheader("Subject", buf, 0, ee);
p = "postmaster-notification";
}
else
{
- snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Returned mail: see transcript for details");
- addheader("Subject", buf, 0, &ee->e_header);
+ addheader("Subject", buf, 0, ee);
p = "failure";
}
- (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
- addheader("Auto-Submitted", buf, 0, &ee->e_header);
+ (void) sm_snprintf(buf, sizeof buf, "auto-generated (%s)", p);
+ addheader("Auto-Submitted", buf, 0, ee);
/* fake up an address header for the from person */
expand("\201n", buf, sizeof buf, e);
if (parseaddr(buf, &ee->e_from,
- RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
+ RF_COPYALL|RF_SENDERADDR, '\0', NULL, e, false) == NULL)
{
syserr("553 5.3.5 Can't parse myself!");
ExitStat = EX_SOFTWARE;
@@ -682,18 +705,19 @@ returntosender(msg, returnq, flags, e)
/* push state into submessage */
CurEnv = ee;
- define('f', "\201n", ee);
- define('x', "Mail Delivery Subsystem", ee);
- eatheader(ee, TRUE);
+ macdefine(&ee->e_macro, A_PERM, 'f', "\201n");
+ macdefine(&ee->e_macro, A_PERM, 'x', "Mail Delivery Subsystem");
+ eatheader(ee, true, true);
/* mark statistics */
- markstats(ee, NULLADDR, FALSE);
+ markstats(ee, NULLADDR, STATS_NORMAL);
/* actually deliver the error message */
sendall(ee, SM_DELIVER);
/* restore state */
- dropenvelope(ee, TRUE);
+ dropenvelope(ee, true, false);
+ sm_rpool_free(ee->e_rpool);
CurEnv = oldcur;
returndepth--;
@@ -708,7 +732,7 @@ returntosender(msg, returnq, flags, e)
}
return -1;
}
- /*
+/*
** ERRBODY -- output the body of an error message.
**
** Typically this is a copy of the transcript plus a copy of the
@@ -717,7 +741,7 @@ returntosender(msg, returnq, flags, e)
** Parameters:
** mci -- the mailer connection information.
** e -- the envelope we are working in.
-** separator -- any possible MIME separator.
+** separator -- any possible MIME separator (unused).
**
** Returns:
** none
@@ -737,9 +761,10 @@ errbody(mci, e, separator)
bool sendbody;
bool pm_notify;
int save_errno;
- register FILE *xfile;
+ register SM_FILE_T *xfile;
char *p;
register ADDRESS *q = NULL;
+ char actual[MAXLINE];
char buf[MAXLINE];
if (bitset(MCIF_INHEADER, mci->mci_flags))
@@ -762,7 +787,7 @@ errbody(mci, e, separator)
{
putline("This is a MIME-encapsulated message", mci);
putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", e->e_msgboundary);
putline(buf, mci);
putline("", mci);
}
@@ -771,10 +796,10 @@ errbody(mci, e, separator)
** Output introductory information.
*/
- pm_notify = FALSE;
+ pm_notify = false;
p = hvalue("subject", e->e_header);
if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
- pm_notify = TRUE;
+ pm_notify = true;
else
{
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
@@ -796,8 +821,9 @@ errbody(mci, e, separator)
mci);
putline("", mci);
}
- snprintf(buf, sizeof buf, "The original message was received at %s",
- arpadate(ctime(&e->e_parent->e_ctime)));
+ (void) sm_snprintf(buf, sizeof buf,
+ "The original message was received at %s",
+ arpadate(ctime(&e->e_parent->e_ctime)));
putline(buf, mci);
expand("from \201_", buf, sizeof buf, e->e_parent);
putline(buf, mci);
@@ -805,7 +831,8 @@ errbody(mci, e, separator)
/* include id in postmaster copies */
if (pm_notify && e->e_parent->e_id != NULL)
{
- snprintf(buf, sizeof buf, "with id %s", e->e_parent->e_id);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "with id ",
+ e->e_parent->e_id);
putline(buf, mci);
}
putline("", mci);
@@ -829,13 +856,14 @@ errbody(mci, e, separator)
xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
if (xfile != NULL)
{
- while (fgets(buf, sizeof buf, xfile) != NULL)
+ while (sm_io_fgets(xfile, SM_TIME_DEFAULT, buf,
+ sizeof buf) != NULL)
{
translate_dollars(buf);
expand(buf, buf, sizeof buf, e);
putline(buf, mci);
}
- (void) fclose(xfile);
+ (void) sm_io_close(xfile, SM_TIME_DEFAULT);
putline("\n", mci);
}
}
@@ -851,7 +879,8 @@ errbody(mci, e, separator)
** Output message introduction
*/
- printheader = TRUE;
+ /* permanent fatal errors */
+ printheader = true;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (!QS_IS_BADADDR(q->q_state) ||
@@ -862,35 +891,39 @@ errbody(mci, e, separator)
{
putline(" ----- The following addresses had permanent fatal errors -----",
mci);
- printheader = FALSE;
+ printheader = false;
}
- snprintf(buf, sizeof buf, "%s",
- shortenstring(q->q_paddr, MAXSHORTSTR));
+ (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
+ sizeof buf);
putline(buf, mci);
if (q->q_rstatus != NULL)
{
- snprintf(buf, sizeof buf, " (reason: %s)",
- shortenstring(exitstat(q->q_rstatus),
- MAXSHORTSTR));
+ (void) sm_snprintf(buf, sizeof buf,
+ " (reason: %s)",
+ shortenstring(exitstat(q->q_rstatus),
+ MAXSHORTSTR));
putline(buf, mci);
}
if (q->q_alias != NULL)
{
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr,
- MAXSHORTSTR));
+ (void) sm_snprintf(buf, sizeof buf,
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
putline(buf, mci);
}
}
if (!printheader)
putline("", mci);
- printheader = TRUE;
+ /* transient non-fatal errors */
+ printheader = true;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state) ||
!bitset(QPRIMARY, q->q_flags) ||
+ !bitset(QBYNDELAY, q->q_flags) ||
!bitset(QDELAYED, q->q_flags))
continue;
@@ -898,30 +931,37 @@ errbody(mci, e, separator)
{
putline(" ----- The following addresses had transient non-fatal errors -----",
mci);
- printheader = FALSE;
+ printheader = false;
}
- snprintf(buf, sizeof buf, "%s",
- shortenstring(q->q_paddr, MAXSHORTSTR));
+ (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
+ sizeof buf);
putline(buf, mci);
if (q->q_alias != NULL)
{
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr,
- MAXSHORTSTR));
+ (void) sm_snprintf(buf, sizeof buf,
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
putline(buf, mci);
}
}
if (!printheader)
putline("", mci);
- printheader = TRUE;
+ /* successful delivery notifications */
+ printheader = true;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
if (QS_IS_BADADDR(q->q_state) ||
!bitset(QPRIMARY, q->q_flags) ||
+ bitset(QBYNDELAY, q->q_flags) ||
bitset(QDELAYED, q->q_flags))
continue;
+ else if (bitset(QBYNRELAY, q->q_flags))
+ p = "Deliver-By notify: relayed";
+ else if (bitset(QBYTRACE, q->q_flags))
+ p = "Deliver-By trace: relayed";
else if (!bitset(QPINGONSUCCESS, q->q_flags))
continue;
else if (bitset(QRELAYED, q->q_flags))
@@ -942,17 +982,18 @@ errbody(mci, e, separator)
{
putline(" ----- The following addresses had successful delivery notifications -----",
mci);
- printheader = FALSE;
+ printheader = false;
}
- snprintf(buf, sizeof buf, "%s (%s)",
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)",
shortenstring(q->q_paddr, MAXSHORTSTR), p);
putline(buf, mci);
if (q->q_alias != NULL)
{
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr,
- MAXSHORTSTR));
+ (void) sm_snprintf(buf, sizeof buf,
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
putline(buf, mci);
}
}
@@ -963,7 +1004,7 @@ errbody(mci, e, separator)
** Output transcript of errors
*/
- (void) fflush(stdout);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
if (e->e_parent->e_xfp == NULL)
{
putline(" ----- Transcript of session is unavailable -----\n",
@@ -971,16 +1012,17 @@ errbody(mci, e, separator)
}
else
{
- printheader = TRUE;
+ printheader = true;
(void) bfrewind(e->e_parent->e_xfp);
if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
- while (fgets(buf, sizeof buf, e->e_parent->e_xfp) != NULL)
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
+ while (sm_io_fgets(e->e_parent->e_xfp, SM_TIME_DEFAULT, buf,
+ sizeof buf) != NULL)
{
if (printheader)
putline(" ----- Transcript of session follows -----\n",
mci);
- printheader = FALSE;
+ printheader = false;
putline(buf, mci);
}
}
@@ -993,10 +1035,8 @@ errbody(mci, e, separator)
if (e->e_msgboundary != NULL)
{
- time_t now = curtime();
-
putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", e->e_msgboundary);
putline(buf, mci);
putline("Content-Type: message/delivery-status", mci);
putline("", mci);
@@ -1008,15 +1048,15 @@ errbody(mci, e, separator)
/* original envelope id from MAIL FROM: line */
if (e->e_parent->e_envid != NULL)
{
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Original-Envelope-Id: %.800s",
xuntextify(e->e_parent->e_envid));
putline(buf, mci);
}
/* Reporting-MTA: is us (required) */
- (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s",
- MyHostName);
+ (void) sm_snprintf(buf, sizeof buf,
+ "Reporting-MTA: dns; %.800s", MyHostName);
putline(buf, mci);
/* DSN-Gateway: not relevant since we are not translating */
@@ -1028,24 +1068,35 @@ errbody(mci, e, separator)
if (e->e_parent->e_from.q_mailer == NULL ||
(p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
p = "dns";
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Received-From-MTA: %s; %.800s",
p, RealHostName);
putline(buf, mci);
}
/* Arrival-Date: -- when it arrived here */
- (void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Arrival-Date: ",
arpadate(ctime(&e->e_parent->e_ctime)));
putline(buf, mci);
+ /* Deliver-By-Date: -- when it should have been delivered */
+ if (IS_DLVR_BY(e->e_parent))
+ {
+ time_t dbyd;
+
+ dbyd = e->e_parent->e_ctime + e->e_parent->e_deliver_by;
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Deliver-By-Date: ",
+ arpadate(ctime(&dbyd)));
+ putline(buf, mci);
+ }
+
/*
** Output per-address information.
*/
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
- register ADDRESS *r;
char *action;
if (QS_IS_BADADDR(q->q_state))
@@ -1071,6 +1122,12 @@ errbody(mci, e, separator)
action = "expanded (to multi-recipient alias)";
else if (bitset(QDELAYED, q->q_flags))
action = "delayed";
+ else if (bitset(QBYTRACE, q->q_flags))
+ action = "relayed (Deliver-By trace mode)";
+ else if (bitset(QBYNDELAY, q->q_flags))
+ action = "delayed (Deliver-By notify mode)";
+ else if (bitset(QBYNRELAY, q->q_flags))
+ action = "relayed (Deliver-By notify mode)";
else
continue;
@@ -1079,63 +1136,15 @@ errbody(mci, e, separator)
/* Original-Recipient: -- passed from on high */
if (q->q_orcpt != NULL)
{
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Original-Recipient: %.800s",
q->q_orcpt);
putline(buf, mci);
}
- /* Final-Recipient: -- the name from the RCPT command */
- p = e->e_parent->e_from.q_mailer->m_addrtype;
- if (p == NULL)
- p = "rfc822";
- for (r = q; r->q_alias != NULL; r = r->q_alias)
- continue;
- if (strcasecmp(p, "rfc822") != 0)
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.800s",
- r->q_mailer->m_addrtype,
- r->q_user);
- }
- else if (strchr(r->q_user, '@') != NULL)
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.800s",
- p, r->q_user);
- }
- else if (strchr(r->q_paddr, '@') != NULL)
- {
- char *qp;
- bool b;
-
- qp = r->q_paddr;
- /* strip brackets from address */
- b = FALSE;
- if (*qp == '<')
- {
- b = qp[strlen(qp) - 1] == '>';
- if (b)
- qp[strlen(qp) - 1] = '\0';
- qp++;
- }
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.800s",
- p, qp);
- /* undo damage */
- if (b)
- qp[strlen(qp)] = '>';
- }
- else
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.700s@%.100s",
- p, r->q_user, MyHostName);
- }
- putline(buf, mci);
-
- /* X-Actual-Recipient: -- the real problem address */
- if (r != q && q->q_user[0] != '\0')
+ /* Figure out actual recipient */
+ actual[0] = '\0';
+ if (q->q_user[0] != '\0')
{
if (q->q_mailer != NULL &&
q->q_mailer->m_addrtype != NULL)
@@ -1143,25 +1152,59 @@ errbody(mci, e, separator)
else
p = "rfc822";
- if (strcasecmp(p, "rfc822") == 0 &&
+ if (sm_strcasecmp(p, "rfc822") == 0 &&
strchr(q->q_user, '@') == NULL)
{
- (void) snprintf(buf, sizeof buf,
- "X-Actual-Recipient: %s; %.700s@%.100s",
- p, q->q_user,
- MyHostName);
+ (void) sm_snprintf(actual,
+ sizeof actual,
+ "%s; %.700s@%.100s",
+ p, q->q_user,
+ MyHostName);
}
else
{
- (void) snprintf(buf, sizeof buf,
- "X-Actual-Recipient: %s; %.800s",
- p, q->q_user);
+ (void) sm_snprintf(actual,
+ sizeof actual,
+ "%s; %.800s",
+ p, q->q_user);
}
+ }
+
+ /* Final-Recipient: -- the name from the RCPT command */
+ if (q->q_finalrcpt == NULL)
+ {
+ /* should never happen */
+ sm_syslog(LOG_ERR, e->e_id,
+ "returntosender: q_finalrcpt is NULL");
+
+ /* try to fall back to the actual recipient */
+ if (actual[0] != '\0')
+ q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
+ actual);
+ }
+
+ if (q->q_finalrcpt != NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ "Final-Recipient: %s",
+ q->q_finalrcpt);
+ putline(buf, mci);
+ }
+
+ /* X-Actual-Recipient: -- the real problem address */
+ if (actual[0] != '\0' &&
+ q->q_finalrcpt != NULL &&
+ strcmp(actual, q->q_finalrcpt) != 0)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ "X-Actual-Recipient: %s",
+ actual);
putline(buf, mci);
}
/* Action: -- what happened? */
- snprintf(buf, sizeof buf, "Action: %s", action);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Action: ",
+ action);
putline(buf, mci);
/* Status: -- what _really_ happened? */
@@ -1173,7 +1216,7 @@ errbody(mci, e, separator)
p = "4.0.0";
else
p = "2.0.0";
- snprintf(buf, sizeof buf, "Status: %s", p);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Status: ", p);
putline(buf, mci);
/* Remote-MTA: -- who was I talking to? */
@@ -1182,7 +1225,7 @@ errbody(mci, e, separator)
if (q->q_mailer == NULL ||
(p = q->q_mailer->m_mtatype) == NULL)
p = "dns";
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Remote-MTA: %s; %.800s",
p, q->q_statmta);
p = &buf[strlen(buf) - 1];
@@ -1197,7 +1240,7 @@ errbody(mci, e, separator)
p = q->q_mailer->m_diagtype;
if (p == NULL)
p = "smtp";
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Diagnostic-Code: %s; %.800s",
p, q->q_rstatus);
putline(buf, mci);
@@ -1205,9 +1248,9 @@ errbody(mci, e, separator)
/* Last-Attempt-Date: -- fine granularity */
if (q->q_statdate == (time_t) 0L)
- q->q_statdate = now;
- (void) snprintf(buf, sizeof buf,
- "Last-Attempt-Date: %s",
+ q->q_statdate = curtime();
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Last-Attempt-Date: ",
arpadate(ctime(&q->q_statdate)));
putline(buf, mci);
@@ -1218,8 +1261,8 @@ errbody(mci, e, separator)
xdate = e->e_parent->e_ctime +
TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
- snprintf(buf, sizeof buf,
- "Will-Retry-Until: %s",
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Will-Retry-Until: ",
arpadate(ctime(&xdate)));
putline(buf, mci);
}
@@ -1246,25 +1289,25 @@ errbody(mci, e, separator)
}
else
{
- (void) snprintf(buf, sizeof buf, "--%s",
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--",
e->e_msgboundary);
putline(buf, mci);
- (void) snprintf(buf, sizeof buf, "Content-Type: %s",
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Content-Type: ",
sendbody ? "message/rfc822"
: "text/rfc822-headers");
putline(buf, mci);
p = hvalue("Content-Transfer-Encoding",
e->e_parent->e_header);
- if (p != NULL && strcasecmp(p, "binary") != 0)
+ if (p != NULL && sm_strcasecmp(p, "binary") != 0)
p = NULL;
if (p == NULL &&
bitset(EF_HAS8BIT, e->e_parent->e_flags))
p = "8bit";
if (p != NULL)
{
- (void) snprintf(buf, sizeof buf,
+ (void) sm_snprintf(buf, sizeof buf,
"Content-Transfer-Encoding: %s",
p);
putline(buf, mci);
@@ -1290,11 +1333,12 @@ errbody(mci, e, separator)
if (e->e_msgboundary != NULL)
{
putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
+ (void) sm_strlcpyn(buf, sizeof buf, 3, "--", e->e_msgboundary,
+ "--");
putline(buf, mci);
}
putline("", mci);
- (void) fflush(mci->mci_out);
+ (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
/*
** Cleanup and exit
@@ -1303,7 +1347,7 @@ errbody(mci, e, separator)
if (errno != 0)
syserr("errbody: I/O error");
}
- /*
+/*
** SMTPTODSN -- convert SMTP to DSN status code
**
** Parameters:
@@ -1311,6 +1355,11 @@ errbody(mci, e, separator)
**
** Returns:
** The DSN version of the status code.
+**
+** Storage Management:
+** smtptodsn() returns a pointer to a character string literal,
+** which will remain valid forever, and thus does not need to
+** be copied. Current code relies on this property.
*/
char *
@@ -1368,7 +1417,7 @@ smtptodsn(smtpstat)
return "4.0.0";
return "5.0.0";
}
- /*
+/*
** XTEXTIFY -- take regular text and turn it into DSN-style xtext
**
** Parameters:
@@ -1405,6 +1454,11 @@ xtextify(t, taboo)
nbogus++;
l++;
}
+ if (nbogus < 0)
+ {
+ /* since nbogus is ssize_t and wrapped, 2 * size_t would wrap */
+ syserr("!xtextify string too long");
+ }
if (nbogus == 0)
return t;
l += nbogus * 2 + 1;
@@ -1413,8 +1467,8 @@ xtextify(t, taboo)
if (l > bplen)
{
if (bp != NULL)
- sm_free(bp);
- bp = xalloc(l);
+ sm_free(bp); /* XXX */
+ bp = sm_pmalloc_x(l);
bplen = l;
}
@@ -1437,7 +1491,7 @@ xtextify(t, taboo)
*p = '\0';
return bp;
}
- /*
+/*
** XUNTEXTIFY -- take xtext and turn it into plain text
**
** Parameters:
@@ -1466,7 +1520,7 @@ xuntextify(t)
if (l > bplen)
{
if (bp != NULL)
- sm_free(bp);
+ sm_free(bp); /* XXX */
bp = xalloc(l);
bplen = l;
}
@@ -1517,7 +1571,7 @@ xuntextify(t)
*p = '\0';
return bp;
}
- /*
+/*
** XTEXTOK -- check if a string is legal xtext
**
** Xtext is used in Delivery Status Notifications. The spec was
@@ -1528,8 +1582,8 @@ xuntextify(t)
** s -- the string to check.
**
** Returns:
-** TRUE -- if 's' is legal xtext.
-** FALSE -- if it has any illegal characters in it.
+** true -- if 's' is legal xtext.
+** false -- if it has any illegal characters in it.
*/
bool
@@ -1544,17 +1598,17 @@ xtextok(s)
{
c = *s++;
if (!isascii(c) || !isxdigit(c))
- return FALSE;
+ return false;
c = *s++;
if (!isascii(c) || !isxdigit(c))
- return FALSE;
+ return false;
}
else if (c < '!' || c > '~' || c == '=')
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
- /*
+/*
** PRUNEROUTE -- prune an RFC-822 source route
**
** Trims down a source route to the last internet-registered hop.
@@ -1564,8 +1618,8 @@ xtextok(s)
** addr -- the address
**
** Returns:
-** TRUE -- address was modified
-** FALSE -- address could not be pruned
+** true -- address was modified
+** false -- address could not be pruned
**
** Side Effects:
** modifies addr in-place
@@ -1578,6 +1632,7 @@ pruneroute(addr)
#if NAMED_BIND
char *start, *at, *comma;
char c;
+ int braclev;
int rcode;
int i;
char hostbuf[BUFSIZ];
@@ -1585,37 +1640,60 @@ pruneroute(addr)
/* check to see if this is really a route-addr */
if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
- return FALSE;
- start = strchr(addr, ':');
+ return false;
+
+ /*
+ ** Can't simply find the first ':' is the address might be in the
+ ** form: "<@[IPv6:::1]:user@host>" and the first ':' in inside
+ ** the IPv6 address.
+ */
+
+ start = addr;
+ braclev = 0;
+ while (*start != '\0')
+ {
+ if (*start == ':' && braclev <= 0)
+ break;
+ else if (*start == '[')
+ braclev++;
+ else if (*start == ']' && braclev > 0)
+ braclev--;
+ start++;
+ }
+ if (braclev > 0 || *start != ':')
+ return false;
+
at = strrchr(addr, '@');
- if (start == NULL || at == NULL || at < start)
- return FALSE;
+ if (at == NULL || at < start)
+ return false;
/* slice off the angle brackets */
i = strlen(at + 1);
- if (i >= (SIZE_T) sizeof hostbuf)
- return FALSE;
- (void) strlcpy(hostbuf, at + 1, sizeof hostbuf);
+ if (i >= sizeof hostbuf)
+ return false;
+ (void) sm_strlcpy(hostbuf, at + 1, sizeof hostbuf);
hostbuf[i - 1] = '\0';
- while (start)
+ while (start != NULL)
{
- if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0)
+ if (getmxrr(hostbuf, mxhosts, NULL, false,
+ &rcode, true, NULL) > 0)
{
- (void) strlcpy(addr + 1, start + 1, strlen(addr) - 1);
- return TRUE;
+ (void) sm_strlcpy(addr + 1, start + 1,
+ strlen(addr) - 1);
+ return true;
}
c = *start;
*start = '\0';
comma = strrchr(addr, ',');
if (comma != NULL && comma[1] == '@' &&
- strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
- (void) strlcpy(hostbuf, comma + 2, sizeof hostbuf);
+ strlen(comma + 2) < sizeof hostbuf)
+ (void) sm_strlcpy(hostbuf, comma + 2, sizeof hostbuf);
else
comma = NULL;
*start = c;
start = comma;
}
#endif /* NAMED_BIND */
- return FALSE;
+ return false;
}
diff --git a/contrib/sendmail/src/sendmail.8 b/contrib/sendmail/src/sendmail.8
index bbcd55d..dcad542 100644
--- a/contrib/sendmail/src/sendmail.8
+++ b/contrib/sendmail/src/sendmail.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+.\" Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
.\" All rights reserved.
.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
.\" Copyright (c) 1988, 1991, 1993
@@ -9,9 +9,9 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: sendmail.8,v 8.36.8.3 2000/12/14 23:08:15 gshapiro Exp $
+.\" $Id: sendmail.8,v 8.49 2001/03/23 22:10:00 ca Exp $
.\"
-.TH SENDMAIL 8 "$Date: 2000/12/14 23:08:15 $"
+.TH SENDMAIL 8 "$Date: 2001/03/23 22:10:00 $"
.SH NAME
sendmail
\- an electronic mail transport agent
@@ -67,6 +67,14 @@ and `group' includes `john' in the expansion,
then the letter will also be delivered to `john'.
.SS Parameters
.TP
+.B \-Ac
+Use submit.cf even if the operation mode does not indicate
+an initial mail submission.
+.TP
+.B \-Am
+Use sendmail.cf even if the operation mode indicates
+an initial mail submission.
+.TP
.BI \-B type
Set the body type to
.IR type .
@@ -113,7 +121,11 @@ Initialize the alias database.
Deliver mail in the usual way (default).
.TP
.B \-bp
-Print a listing of the queue.
+Print a listing of the queue(s).
+.TP
+.B \-bP
+Print number of entries in the queue(s);
+only available with shared memory support.
.TP
.B \-bs
Use the
@@ -237,7 +249,7 @@ This can be a simple protocol name such as ``UUCP''
or a protocol and hostname, such as ``UUCP:ucbvax''.
.TP
\fB\-q\fR[\fItime\fR]
-Processed saved messages in the queue at given intervals.
+Process saved messages in the queue at given intervals.
If
.I time
is omitted, process the queue once.
@@ -247,7 +259,7 @@ with
`s'
being seconds,
`m'
-being minutes,
+being minutes (default),
`h'
being hours,
`d'
@@ -260,28 +272,50 @@ For example,
or
`\-q90m'
would both set the timeout to one hour thirty minutes.
-If
-.I time
-is specified,
+By default,
.B sendmail
-will run in the background.
+will run in the background.
This option can be used safely with
.BR \-bd .
.TP
-.BI \-qI substr
+\fB\-qp\fR[\fItime\fR]
+Similar to \fB\-q\fItime\fR,
+except that instead of periodically forking a child to process the queue,
+sendmail forks a single persistent child for each queue
+that alternates between processing the queue and sleeping.
+The sleep time is given as the argument; it defaults to 1 second.
+The process will always sleep at least 5 seconds if the queue was
+empty in the previous queue run.
+.TP
+\fB\-q\fRf
+Process saved messages in the queue once and do not fork(),
+but run in the foreground.
+.TP
+\fB\-q\fRG name
+Process jobs in queue group called
+.I name
+only.
+.TP
+\fB\-q\fR[\fI!\fR]I substr
Limit processed jobs to those containing
.I substr
-as a substring of the queue id.
+as a substring of the queue id or not when
+.I !
+is specified.
.TP
-.BI \-qR substr
+\fB\-q\fR[\fI!\fR]R substr
Limit processed jobs to those containing
.I substr
-as a substring of one of the recipients.
+as a substring of one of the recipients or not when
+.I !
+is specified.
.TP
-.BI \-qS substr
+\fB\-q\fR[\fI!\fR]S substr
Limit processed jobs to those containing
.I substr
-as a substring of the sender.
+as a substring of the sender or not when
+.I !
+is specified.
.TP
.BI "\-R " return
Set the amount of the message to be returned
@@ -305,18 +339,6 @@ Read message for recipients.
To:, Cc:, and Bcc: lines will be scanned for recipient addresses.
The Bcc: line will be deleted before transmission.
.TP
-.B \-U
-Initial (user) submission. This should
-.I always
-be set when called from a user agent such as
-.B Mail
-or
-.B exmh
-and
-.I never
-be set when called by a network delivery agent such as
-.BR rmail .
-.TP
.BI "\-V " envid
Set the original envelope id.
This is propagated across SMTP to servers that support DSNs
diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h
index 611116c..86a3c48 100644
--- a/contrib/sendmail/src/sendmail.h
+++ b/contrib/sendmail/src/sendmail.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -15,13 +15,10 @@
*/
#ifndef _SENDMAIL_H
-#define _SENDMAIL_H 1
+# define _SENDMAIL_H 1
#ifdef _DEFINE
# define EXTERN
-# ifndef lint
-static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca Exp $";
-# endif /* ! lint */
#else /* _DEFINE */
# define EXTERN extern
#endif /* _DEFINE */
@@ -29,18 +26,9 @@ static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca
#include <unistd.h>
-#if SFIO
-# include <sfio/stdio.h>
-# if defined(SFIO_VERSION) && SFIO_VERSION > 20000000L
- ERROR README: SFIO 2000 does not work with sendmail, use SFIO 1999 instead.
-# endif /* defined(SFIO_VERSION) && SFIO_VERSION > 20000000L */
-#endif /* SFIO */
-
#include <stddef.h>
#include <stdlib.h>
-#if !SFIO
-# include <stdio.h>
-#endif /* !SFIO */
+#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
#include <string.h>
@@ -48,11 +36,36 @@ static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca
# ifdef EX_OK
# undef EX_OK /* for SVr4.2 SMP */
# endif /* EX_OK */
-#include <sysexits.h>
#include "sendmail/sendmail.h"
+
+/* profiling? */
+#if MONCONTROL
+# define SM_PROF(x) moncontrol(x)
+#else /* MONCONTROL */
+# define SM_PROF(x)
+#endif /* MONCONTROL */
+
+#ifdef _DEFINE
+# ifndef lint
+SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.902 2002/01/09 00:10:11 ca Exp $";
+# endif /* ! lint */
+#endif /* _DEFINE */
+
#include "bf.h"
#include "timers.h"
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/debug.h>
+#include <sm/rpool.h>
+#include <sm/io.h>
+#include <sm/path.h>
+#include <sm/signal.h>
+#include <sm/clock.h>
+#include <sm/mbdb.h>
+#include <sm/errstring.h>
+#include <sm/sysexits.h>
+#include <sm/shm.h>
#ifdef LOG
# include <syslog.h>
@@ -91,9 +104,12 @@ static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca
# undef NOERROR /* avoid <sys/streams.h> conflict */
# endif /* NOERROR */
# include <resolv.h>
+# else /* NAMED_BIND */
+# undef SM_SET_H_ERRNO
+# define SM_SET_H_ERRNO(err)
# endif /* NAMED_BIND */
-# ifdef HESIOD
+# if HESIOD
# include <hesiod.h>
# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES)
# define HESIOD_INIT /* support for the new interface */
@@ -101,13 +117,10 @@ static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca
# endif /* HESIOD */
#if STARTTLS
-# if !SFIO && !_FFR_TLS_TOREK
- ERROR README: STARTTLS requires SFIO
-# endif /* !SFIO && !_FFR_TLS_TOREK */
-# if SFIO && _FFR_TLS_TOREK
- ERROR README: Can not do both SFIO and _FFR_TLS_TOREK
-# endif /* SFIO && _FFR_TLS_TOREK */
# include <openssl/ssl.h>
+# if !TLS_NO_RSA
+# define RSA_KEYLENGTH 512
+# endif /* !TLS_NO_RSA */
#endif /* STARTTLS */
#if SASL /* include the sasl include files if we have them */
@@ -165,11 +178,28 @@ static char SmailId[] = "@(#)$Id: sendmail.h,v 8.517.4.70 2001/08/14 23:08:12 ca
#endif /* ! INADDR_NONE */
+/*
+** An 'argument class' describes the storage allocation status
+** of an object pointed to by an argument to a function.
+*/
+
+typedef enum
+{
+ A_HEAP, /* the storage was allocated by malloc, and the
+ * ownership of the storage is ceded by the caller
+ * to the called function. */
+ A_TEMP, /* The storage is temporary, and is only guaranteed
+ * to be valid for the duration of the function call. */
+ A_PERM /* The storage is 'permanent': this might mean static
+ * storage, or rpool storage. */
+} ARGCLASS_T;
+
/* forward references for prototypes */
typedef struct envelope ENVELOPE;
typedef struct mailer MAILER;
+typedef struct queuegrp QUEUEGRP;
- /*
+/*
** Address structure.
** Addresses are stored internally in this structure.
*/
@@ -181,7 +211,7 @@ struct address
char *q_ruser; /* real user name, or NULL if q_user */
char *q_host; /* host name */
struct mailer *q_mailer; /* mailer to use */
- u_long q_flags; /* status flags, see below */
+ unsigned long q_flags; /* status flags, see below */
uid_t q_uid; /* user-id of receiver (if known) */
gid_t q_gid; /* group-id of receiver (if known) */
char *q_home; /* home dir (local mailer only) */
@@ -190,13 +220,20 @@ struct address
struct address *q_alias; /* address this results from */
char *q_owner; /* owner of q_alias */
struct address *q_tchain; /* temporary use chain */
+#if PIPELINING
+ struct address *q_pchain; /* chain for pipelining */
+#endif /* PIPELINING */
+ char *q_finalrcpt; /* Final-Recipient: DSN header */
char *q_orcpt; /* ORCPT parameter from RCPT TO: line */
char *q_status; /* status code for DSNs */
char *q_rstatus; /* remote status message for DSNs */
time_t q_statdate; /* date of status messages */
char *q_statmta; /* MTA generating q_rstatus */
short q_state; /* address state, see below */
- short q_specificity; /* how "specific" this address is */
+ char *q_signature; /* MX-based sorting value */
+ int q_qgrp; /* index into queue groups */
+ int q_qdir; /* queue directory inside group */
+ char *q_message; /* error message */
};
typedef struct address ADDRESS;
@@ -211,12 +248,15 @@ typedef struct address ADDRESS;
#define QPINGONSUCCESS 0x00000040 /* give return on successful delivery */
#define QPINGONFAILURE 0x00000080 /* give return on failure */
#define QPINGONDELAY 0x00000100 /* give return on message delay */
-#define QHASNOTIFY 0x00000200 /* propogate notify parameter */
+#define QHASNOTIFY 0x00000200 /* propagate notify parameter */
#define QRELAYED 0x00000400 /* DSN: relayed to non-DSN aware sys */
#define QEXPANDED 0x00000800 /* DSN: undergone list expansion */
#define QDELIVERED 0x00001000 /* DSN: successful final delivery */
#define QDELAYED 0x00002000 /* DSN: message delayed */
#define QALIAS 0x00004000 /* expanded alias */
+#define QBYTRACE 0x00008000 /* DeliverBy: trace */
+#define QBYNDELAY 0x00010000 /* DeliverBy: notify, delay */
+#define QBYNRELAY 0x00020000 /* DeliverBy: notify, relayed */
#define QTHISPASS 0x40000000 /* temp: address set this pass */
#define QRCPTOK 0x80000000 /* recipient() processed address */
@@ -227,41 +267,47 @@ typedef struct address ADDRESS;
#define QS_SENT 1 /* good address, delivery complete */
#define QS_BADADDR 2 /* illegal address */
#define QS_QUEUEUP 3 /* save address in queue */
-#define QS_VERIFIED 4 /* verified, but not expanded */
-#define QS_DONTSEND 5 /* don't send to this address */
-#define QS_EXPANDED 6 /* QS_DONTSEND: expanded */
-#define QS_SENDER 7 /* QS_DONTSEND: message sender (MeToo) */
-#define QS_CLONED 8 /* QS_DONTSEND: addr cloned to split envelope */
-#define QS_DISCARDED 9 /* QS_DONTSEND: rcpt discarded (EF_DISCARD) */
-#define QS_REPLACED 10 /* QS_DONTSEND: maplocaluser()/UserDB replaced */
-#define QS_REMOVED 11 /* QS_DONTSEND: removed (removefromlist()) */
-#define QS_DUPLICATE 12 /* QS_DONTSEND: duplicate suppressed */
-#define QS_INCLUDED 13 /* QS_DONTSEND: :include: delivery */
+#define QS_RETRY 4 /* retry delivery for next MX */
+#define QS_VERIFIED 5 /* verified, but not expanded */
+
+/*
+** Notice: all of the following values are variations of QS_DONTSEND.
+** If new states are added, they must be inserted in the proper place!
+** See the macro definition of QS_IS_DEAD() down below.
+*/
+
+#define QS_DONTSEND 6 /* don't send to this address */
+#define QS_EXPANDED 7 /* expanded */
+#define QS_SENDER 8 /* message sender (MeToo) */
+#define QS_CLONED 9 /* addr cloned to split envelope */
+#define QS_DISCARDED 10 /* rcpt discarded (EF_DISCARD) */
+#define QS_REPLACED 11 /* maplocaluser()/UserDB replaced */
+#define QS_REMOVED 12 /* removed (removefromlist()) */
+#define QS_DUPLICATE 13 /* duplicate suppressed */
+#define QS_INCLUDED 14 /* :include: delivery */
/* address state testing primitives */
#define QS_IS_OK(s) ((s) == QS_OK)
#define QS_IS_SENT(s) ((s) == QS_SENT)
#define QS_IS_BADADDR(s) ((s) == QS_BADADDR)
#define QS_IS_QUEUEUP(s) ((s) == QS_QUEUEUP)
+#define QS_IS_RETRY(s) ((s) == QS_RETRY)
#define QS_IS_VERIFIED(s) ((s) == QS_VERIFIED)
#define QS_IS_EXPANDED(s) ((s) == QS_EXPANDED)
#define QS_IS_REMOVED(s) ((s) == QS_REMOVED)
#define QS_IS_UNDELIVERED(s) ((s) == QS_OK || \
(s) == QS_QUEUEUP || \
+ (s) == QS_RETRY || \
(s) == QS_VERIFIED)
+#define QS_IS_UNMARKED(s) ((s) == QS_OK || \
+ (s) == QS_RETRY)
#define QS_IS_SENDABLE(s) ((s) == QS_OK || \
- (s) == QS_QUEUEUP)
+ (s) == QS_QUEUEUP || \
+ (s) == QS_RETRY)
#define QS_IS_ATTEMPTED(s) ((s) == QS_QUEUEUP || \
+ (s) == QS_RETRY || \
(s) == QS_SENT)
-#define QS_IS_DEAD(s) ((s) == QS_DONTSEND || \
- (s) == QS_CLONED || \
- (s) == QS_SENDER || \
- (s) == QS_DISCARDED || \
- (s) == QS_REPLACED || \
- (s) == QS_REMOVED || \
- (s) == QS_DUPLICATE || \
- (s) == QS_INCLUDED || \
- (s) == QS_EXPANDED)
+#define QS_IS_DEAD(s) ((s) >= QS_DONTSEND)
#define NULLADDR ((ADDRESS *) NULL)
@@ -274,19 +320,25 @@ extern char *crackaddr __P((char *));
extern bool emptyaddr __P((ADDRESS *));
extern ADDRESS *getctladdr __P((ADDRESS *));
extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern bool invalidaddr __P((char *, char *));
-extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *));
-extern char **prescan __P((char *, int, char[], int, char **, u_char *));
+extern bool invalidaddr __P((char *, char *, bool));
+extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **,
+ ENVELOPE *, bool));
+extern char **prescan __P((char *, int, char[], int, char **, unsigned char *));
extern void printaddr __P((ADDRESS *, bool));
extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
extern char *remotename __P((char *, MAILER *, int, int *, ENVELOPE *));
-extern int rewrite __P((char **, int, int, ENVELOPE *));
+extern int rewrite __P((char **, int, int, ENVELOPE *, int));
extern bool sameaddr __P((ADDRESS *, ADDRESS *));
extern int sendtolist __P((char *, ADDRESS *, ADDRESS **, int, ENVELOPE *));
+#if MILTER
extern int removefromlist __P((char *, ADDRESS **, ENVELOPE *));
+#endif /* MILTER */
extern void setsender __P((char *, ENVELOPE *, char **, int, bool));
- /*
+/* macro to simplify the common call to rewrite() */
+#define REWRITE(pvp, rs, env) rewrite(pvp, rs, 0, env, MAXATOM)
+
+/*
** Mailer definition structure.
** Every mailer known to the system is declared in this
** structure. It defines the pathname of the mailer, some
@@ -323,13 +375,12 @@ struct mailer
gid_t m_gid; /* GID to run as */
char *m_defcharset; /* default character set */
time_t m_wait; /* timeout to wait for end */
-#if _FFR_DYNAMIC_TOBUF
int m_maxrcpt; /* max recipients per envelope client-side */
-#endif /* _FFR_DYNAMIC_TOBUF */
+ short m_qgrp; /* queue group for this mailer */
};
/* bits for m_flags */
-#define M_ESMTP 'a' /* run Extended SMTP protocol */
+#define M_ESMTP 'a' /* run Extended SMTP */
#define M_ALIASABLE 'A' /* user can be LHS of an alias */
#define M_BLANKEND 'b' /* ensure blank line at end of message */
#define M_NOCOMMENT 'c' /* don't include comment part of address */
@@ -370,8 +421,10 @@ struct mailer
/* 'x' CF: include Full-Name: */
#define M_XDOT 'X' /* use hidden-dot algorithm */
#define M_LMTP 'z' /* run Local Mail Transport Protocol */
+#define M_DIALDELAY 'Z' /* apply dial delay sleeptime */
#define M_NOMX '0' /* turn off MX lookups */
#define M_NONULLS '1' /* don't send null bytes */
+#define M_FSMTP '2' /* force SMTP (no ESMTP even if offered) */
#define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */
#define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */
#define M_7BITHDRS '6' /* strip headers to 7 bits even in 8 bit path */
@@ -390,8 +443,162 @@ struct mailer
/* functions */
extern void initerrmailers __P((void));
extern void makemailer __P((char *));
+extern void makequeue __P((char *, bool));
+extern void runqueueevent __P((int));
+
+EXTERN MAILER *FileMailer; /* ptr to *file* mailer */
+EXTERN MAILER *InclMailer; /* ptr to *include* mailer */
+EXTERN MAILER *LocalMailer; /* ptr to local mailer */
+EXTERN MAILER *ProgMailer; /* ptr to program mailer */
+EXTERN MAILER *Mailer[MAXMAILERS + 1];
+
+/*
+** Queue group definition structure.
+** Every queue group known to the system is declared in this structure.
+** It defines the basic pathname of the queue group, some flags
+** associated with it, and the argument vector to pass to it.
+*/
+
+struct qpaths_s
+{
+ char *qp_name; /* name of queue dir, relative path */
+ short qp_subdirs; /* use subdirs? */
+ short qp_fsysidx; /* file system index of this directory */
+# if SM_CONF_SHM
+ int qp_idx; /* index into array for queue information */
+# endif /* SM_CONF_SHM */
+};
+
+typedef struct qpaths_s QPATHS;
+
+struct queuegrp
+{
+ char *qg_name; /* symbolic name of this queue group */
+
+ /*
+ ** For now this is the same across all queue groups.
+ ** Otherwise we have to play around with chdir().
+ */
+
+ char *qg_qdir; /* common component of queue directory */
+ short qg_index; /* queue number internally, index in Queue[] */
+ int qg_maxqrun; /* max # of jobs in 1 queuerun */
+ int qg_numqueues; /* number of queues in this queue */
+
+ /*
+ ** qg_queueintvl == 0 denotes that no individual value is used.
+ ** Whatever accesses this must deal with "<= 0" as
+ ** "not set, use appropriate default".
+ */
+
+ time_t qg_queueintvl; /* interval for queue runs */
+ QPATHS *qg_qpaths; /* list of queue directories */
+ BITMAP256 qg_flags; /* status flags, see below */
+ short qg_nice; /* niceness for queue run */
+ int qg_wgrp; /* Assigned to this work group */
+ int qg_maxlist; /* max items in work queue for this group */
+ int qg_curnum; /* current number of queue for queue runs */
+ int qg_maxrcpt; /* max recipients per envelope, 0==no limit */
+
+#if 0
+ short qg_sortorder; /* how do we sort this queuerun */
+ long qg_wkrcptfact; /* multiplier for # recipients -> priority */
+ long qg_qfactor; /* slope of queue function */
+ bool qg_doqueuerun; /* XXX flag is it time to do a queuerun */
+#endif /* 0 */
+};
+
+/* bits for qg_flags (XXX: unused as of now) */
+#define QD_DEFINED ((char) 1) /* queue group has been defined */
+#define QD_FORK 'f' /* fork queue runs */
+
+extern void filesys_update __P((void));
+#if _FFR_ANY_FREE_FS
+extern bool filesys_free __P((long));
+#endif /* _FFR_ANY_FREE_FS */
+
+#if SASL
+/*
+** SASL
+*/
+
+/* lines in authinfo file or index into SASL_AI_T */
+# define SASL_WRONG (-1)
+# define SASL_USER 0 /* authorization id (user) */
+# define SASL_AUTHID 1 /* authentication id */
+# define SASL_PASSWORD 2 /* password fuer authid */
+# define SASL_DEFREALM 3 /* realm to use */
+# define SASL_MECHLIST 4 /* list of mechanisms to try */
+# define SASL_ID_REALM 5 /* authid@defrealm */
+
+/*
+** Current mechanism; this is just used to convey information between
+** invocation of SASL callback functions.
+** It must be last in the list, because it's not allocated by us
+** and hence we don't free() it.
+*/
+# define SASL_MECH 6
+# define SASL_ENTRIES 7 /* number of entries in array */
+
+# define SASL_USER_BIT (1 << SASL_USER)
+# define SASL_AUTHID_BIT (1 << SASL_AUTHID)
+# define SASL_PASSWORD_BIT (1 << SASL_PASSWORD)
+# define SASL_DEFREALM_BIT (1 << SASL_DEFREALM)
+# define SASL_MECHLIST_BIT (1 << SASL_MECHLIST)
+
+/* authenticated? */
+# define SASL_NOT_AUTH 0 /* not authenticated */
+# define SASL_PROC_AUTH 1 /* in process of authenticating */
+# define SASL_IS_AUTH 2 /* authenticated */
+
+/* SASL options */
+# define SASL_AUTH_AUTH 0x1000 /* use auth= only if authenticated */
+# define SASL_SEC_MASK 0x0fff /* mask for SASL_SEC_* values: sasl.h */
+# if (SASL_SEC_NOPLAINTEXT & SASL_SEC_MASK) == 0 || \
+ (SASL_SEC_NOACTIVE & SASL_SEC_MASK) == 0 || \
+ (SASL_SEC_NODICTIONARY & SASL_SEC_MASK) == 0 || \
+ (SASL_SEC_FORWARD_SECRECY & SASL_SEC_MASK) == 0 || \
+ (SASL_SEC_NOANONYMOUS & SASL_SEC_MASK) == 0 || \
+ (SASL_SEC_PASS_CREDENTIALS & SASL_SEC_MASK) == 0
+ERROR: change SASL_SEC_MASK_ notify sendmail.org!
+# endif /* SASL_SEC_NOPLAINTEXT & SASL_SEC_MASK) == 0 ... */
+# define MAXOUTLEN 1024 /* length of output buffer */
+
+/* functions */
+extern char *intersect __P((char *, char *, SM_RPOOL_T *));
+extern char *iteminlist __P((char *, char *, char *));
+extern int proxy_policy __P((void *, const char *, const char *, const char **, const char **));
+# if SASL > 10515
+extern int safesaslfile __P((void *, char *, int));
+# else /* SASL > 10515 */
+extern int safesaslfile __P((void *, char *));
+# endif /* SASL > 10515 */
+extern int sasl_decode64 __P((const char *, unsigned, char *, unsigned *));
+extern int sasl_encode64 __P((const char *, unsigned, char *, unsigned, unsigned *));
+extern void stop_sasl_client __P((void));
+
+/* structure to store authinfo */
+typedef char *SASL_AI_T[SASL_ENTRIES];
+
+EXTERN char *AuthMechanisms; /* AUTH mechanisms */
+EXTERN char *SASLInfo; /* file with AUTH info */
+EXTERN int SASLOpts; /* options for SASL */
+EXTERN int MaxSLBits; /* max. encryption bits for SASL */
+#endif /* SASL */
- /*
+/*
+** Structure to store macros.
+*/
+typedef struct
+{
+ SM_RPOOL_T *mac_rpool; /* resource pool */
+ BITMAP256 mac_allocated; /* storage has been alloc()? */
+ char *mac_table[MAXMACROID + 1]; /* macros */
+} MACROS_T;
+
+EXTERN MACROS_T GlobalMacros;
+
+/*
** Information about currently open connections to mailers, or to
** hosts that we have looked up recently.
*/
@@ -400,20 +607,15 @@ extern void makemailer __P((char *));
MCI
{
- u_long mci_flags; /* flag bits, see below */
+ unsigned long mci_flags; /* flag bits, see below */
short mci_errno; /* error number on last connection */
short mci_herrno; /* h_errno from last DNS lookup */
short mci_exitstat; /* exit status from last connection */
short mci_state; /* SMTP state */
int mci_deliveries; /* delivery attempts for connection */
long mci_maxsize; /* max size this server will accept */
-#if SFIO
- Sfio_t *mci_in; /* input side of connection */
- Sfio_t *mci_out; /* output side of connection */
-#else /* SFIO */
- FILE *mci_in; /* input side of connection */
- FILE *mci_out; /* output side of connection */
-#endif /* SFIO */
+ SM_FILE_T *mci_in; /* input side of connection */
+ SM_FILE_T *mci_out; /* output side of connection */
pid_t mci_pid; /* process id of subordinate proc */
char *mci_phase; /* SMTP phase string */
struct mailer *mci_mailer; /* ptr to the mailer for this conn */
@@ -421,9 +623,18 @@ MCI
char *mci_status; /* DSN status to be copied to addrs */
char *mci_rstatus; /* SMTP status to be copied to addrs */
time_t mci_lastuse; /* last usage time */
- FILE *mci_statfile; /* long term status file */
+ SM_FILE_T *mci_statfile; /* long term status file */
char *mci_heloname; /* name to use as HELO arg */
+ long mci_min_by; /* minimum DELIVERBY */
+ bool mci_retryrcpt; /* tempfail for at least one rcpt */
+ char *mci_tolist; /* list of valid recipients */
+ SM_RPOOL_T *mci_rpool; /* resource pool */
+#if PIPELINING
+ int mci_okrcpts; /* number of valid recipients */
+ ADDRESS *mci_nextaddr; /* next address for pipelined status */
+#endif /* PIPELINING */
#if SASL
+ SASL_AI_T mci_sai; /* authentication info */
bool mci_sasl_auth; /* authenticated? */
int mci_sasl_string_len;
char *mci_sasl_string; /* sasl reply string */
@@ -433,12 +644,13 @@ MCI
#if STARTTLS
SSL *mci_ssl; /* SSL connection */
#endif /* STARTTLS */
+ MACROS_T mci_macro; /* macro definitions */
};
/* flag bits */
#define MCIF_VALID 0x00000001 /* this entry is valid */
-#define MCIF_TEMP 0x00000002 /* don't cache this connection */
+/* 0x00000002 unused, was MCIF_TEMP */
#define MCIF_CACHED 0x00000004 /* currently in open cache */
#define MCIF_ESMTP 0x00000008 /* this host speaks ESMTP */
#define MCIF_EXPN 0x00000010 /* EXPN command supported */
@@ -455,6 +667,7 @@ MCI
#define MCIF_AUTH 0x00008000 /* AUTH= supported */
#define MCIF_AUTHACT 0x00010000 /* SASL (AUTH) active */
#define MCIF_ENHSTAT 0x00020000 /* ENHANCEDSTATUSCODES supported */
+#define MCIF_PIPELINED 0x00040000 /* PIPELINING supported */
#if STARTTLS
#define MCIF_TLS 0x00100000 /* STARTTLS supported */
#define MCIF_TLSACT 0x00200000 /* STARTTLS active */
@@ -462,17 +675,22 @@ MCI
#else /* STARTTLS */
#define MCIF_EXTENS (MCIF_EXPN | MCIF_SIZE | MCIF_8BITMIME | MCIF_DSN | MCIF_8BITOK | MCIF_AUTH | MCIF_ENHSTAT)
#endif /* STARTTLS */
+#define MCIF_DLVR_BY 0x00400000 /* DELIVERBY */
+#if _FFR_IGNORE_EXT_ON_HELO
+# define MCIF_HELO 0x00800000 /* we used HELO: ignore extensions */
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
#define MCIF_ONLY_EHLO 0x10000000 /* use only EHLO in smtpinit */
-
/* states */
#define MCIS_CLOSED 0 /* no traffic on this connection */
#define MCIS_OPENING 1 /* sending initial protocol */
#define MCIS_OPEN 2 /* open, initial protocol sent */
-#define MCIS_ACTIVE 3 /* message being sent */
-#define MCIS_QUITING 4 /* running quit protocol */
-#define MCIS_SSD 5 /* service shutting down */
-#define MCIS_ERROR 6 /* I/O error on connection */
+#define MCIS_MAIL 3 /* MAIL command sent */
+#define MCIS_RCPT 4 /* RCPT commands being sent */
+#define MCIS_DATA 5 /* DATA command sent */
+#define MCIS_QUITING 6 /* running quit protocol */
+#define MCIS_SSD 7 /* service shutting down */
+#define MCIS_ERROR 8 /* I/O error on connection */
/* functions */
extern void mci_cache __P((MCI *));
@@ -490,7 +708,11 @@ extern void mci_store_persistent __P((MCI *));
extern int mci_traverse_persistent __P((int (*)(), char *));
extern void mci_unlock_host __P((MCI *));
- /*
+EXTERN int MaxMciCache; /* maximum entries in MCI cache */
+EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */
+EXTERN time_t MciInfoTimeout; /* how long 'til we retry down hosts */
+
+/*
** Header structure.
** This structure is used internally to store header items.
*/
@@ -500,8 +722,8 @@ struct header
char *h_field; /* the name of the field */
char *h_value; /* the value of that field */
struct header *h_link; /* the next header */
- u_char h_macro; /* include header if macro defined */
- u_long h_flags; /* status bits, see below */
+ unsigned char h_macro; /* include header if macro defined */
+ unsigned long h_flags; /* status bits, see below */
BITMAP256 h_mflags; /* m_flags bits needed */
};
@@ -515,9 +737,9 @@ typedef struct header HDR;
struct hdrinfo
{
- char *hi_field; /* the name of the field */
- u_long hi_flags; /* status bits, see below */
- char *hi_ruleset; /* validity check ruleset */
+ char *hi_field; /* the name of the field */
+ unsigned long hi_flags; /* status bits, see below */
+ char *hi_ruleset; /* validity check ruleset */
};
extern struct hdrinfo HdrInfo[];
@@ -547,20 +769,20 @@ extern struct hdrinfo HdrInfo[];
#define CHHDR_DEF 0x0001 /* default header */
#define CHHDR_CHECK 0x0002 /* call ruleset for header */
#define CHHDR_USER 0x0004 /* header from user */
-#define CHHDR_QUEUE 0x0008 /* header from qf file */
+#define CHHDR_QUEUE 0x0008 /* header from queue file */
/* functions */
-extern void addheader __P((char *, char *, int, HDR **));
-extern u_long chompheader __P((char *, int, HDR **, ENVELOPE *));
+extern void addheader __P((char *, char *, int, ENVELOPE *));
+extern unsigned long chompheader __P((char *, int, HDR **, ENVELOPE *));
extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *));
-extern HDR *copyheader __P((HDR *));
-extern void eatheader __P((ENVELOPE *, bool));
+extern HDR *copyheader __P((HDR *, SM_RPOOL_T *));
+extern void eatheader __P((ENVELOPE *, bool, bool));
extern char *hvalue __P((char *, HDR *));
extern bool isheader __P((char *));
extern void putfromline __P((MCI *, ENVELOPE *));
extern void setupheaders __P((void));
- /*
+/*
** Performance monitoring
*/
@@ -575,7 +797,7 @@ TIMERS
#define PUSHTIMER(l, t) { if (tTd(98, l)) pushtimer(&t); }
#define POPTIMER(l, t) { if (tTd(98, l)) poptimer(&t); }
- /*
+/*
** Envelope structure.
** This structure defines the message itself. There is usually
** only one of these -- for the message that we originally read
@@ -589,7 +811,7 @@ struct envelope
HDR *e_header; /* head of header list */
long e_msgpriority; /* adjusted priority of this message */
time_t e_ctime; /* time message appeared in the queue */
- char *e_to; /* the target person */
+ char *e_to; /* (list of) target person(s) */
ADDRESS e_from; /* the person it is from */
char *e_sender; /* e_from.q_paddr w comments stripped */
char **e_fromdomain; /* the domain part of the sender */
@@ -601,8 +823,10 @@ struct envelope
** to unsigned. We don't use unsigned and == ULONG_MAX because
** some libc's don't have strtoul(), see mail_esmtp_args().
*/
+
long e_msgsize; /* size of the message in bytes */
- long e_flags; /* flags, see below */
+ char *e_msgid; /* message id (for logging) */
+ unsigned long e_flags; /* flags, see below */
int e_nrcpts; /* number of recipients */
short e_class; /* msg class (priority, junk, etc.) */
short e_hopcount; /* number of times processed */
@@ -617,29 +841,46 @@ struct envelope
ENVELOPE *e_parent; /* the message this one encloses */
ENVELOPE *e_sibling; /* the next envelope of interest */
char *e_bodytype; /* type of message body */
- FILE *e_dfp; /* data file */
+ SM_FILE_T *e_dfp; /* data file */
char *e_id; /* code for this entry in queue */
- int e_queuedir; /* index into queue directories */
- FILE *e_xfp; /* transcript file */
- FILE *e_lockfp; /* the lock file for this message */
- char *e_message; /* error message */
- char *e_statmsg; /* stat msg (changes per delivery) */
+ int e_qgrp; /* queue group (index into queues) */
+ int e_qdir; /* index into queue directories */
+ int e_dfqgrp; /* data file queue group index */
+ int e_dfqdir; /* data file queue directory index */
+ int e_xfqgrp; /* queue group (index into queues) */
+ int e_xfqdir; /* index into queue directories (xf) */
+ SM_FILE_T *e_xfp; /* transcript file */
+ SM_FILE_T *e_lockfp; /* the lock file for this message */
+ char *e_message; /* error message; readonly; NULL, or
+ * static storage, or allocated from
+ * e_rpool */
+ char *e_statmsg; /* stat msg (changes per delivery).
+ * readonly. NULL or allocated from
+ * e_rpool. */
+#if _FFR_QUARANTINE
+ char *e_quarmsg; /* why envelope is quarantined */
+ char e_qfletter; /* queue file letter on disk */
+#endif /* _FFR_QUARANTINE */
char *e_msgboundary; /* MIME-style message part boundary */
char *e_origrcpt; /* original recipient (one only) */
char *e_envid; /* envelope id from MAIL FROM: line */
char *e_status; /* DSN status for this message */
time_t e_dtime; /* time of last delivery attempt */
int e_ntries; /* number of delivery attempts */
- dev_t e_dfdev; /* df file's device, for crash recov */
- ino_t e_dfino; /* df file's ino, for crash recovery */
- char *e_macro[MAXMACROID + 1]; /* macro definitions */
- char *e_if_macros[2]; /* HACK: incoming interface info */
- char *e_auth_param;
+ dev_t e_dfdev; /* data file device (crash recovery) */
+ ino_t e_dfino; /* data file inode (crash recovery) */
+ MACROS_T e_macro; /* macro definitions */
+ MCI *e_mci; /* connection info */
+ char *e_auth_param; /* readonly; NULL or static storage or
+ * allocated from e_rpool */
TIMERS e_timers; /* per job timers */
#if _FFR_QUEUEDELAY
int e_queuealg; /* algorithm for queue delay */
time_t e_queuedelay; /* current delay */
#endif /* _FFR_QUEUEDELAY */
+ long e_deliver_by; /* deliver by */
+ int e_dlvr_flag; /* deliver by flag */
+ SM_RPOOL_T *e_rpool; /* resource pool for this envelope */
};
/* values for e_flags */
@@ -664,24 +905,39 @@ struct envelope
#define EF_NL_NOT_EOL 0x0040000L /* don't accept raw NL as EOLine */
#define EF_CRLF_NOT_EOL 0x0080000L /* don't accept CR-LF as EOLine */
#define EF_RET_PARAM 0x0100000L /* RCPT command had RET argument */
-#define EF_HAS_DF 0x0200000L /* set when df file is instantiated */
+#define EF_HAS_DF 0x0200000L /* set when data file is instantiated */
#define EF_IS_MIME 0x0400000L /* really is a MIME message */
#define EF_DONT_MIME 0x0800000L /* never MIME this message */
#define EF_DISCARD 0x1000000L /* discard the message */
#define EF_TOOBIG 0x2000000L /* message is too big */
+#define EF_SPLIT 0x4000000L /* envelope has been split */
+#define EF_UNSAFE 0x8000000L /* unsafe: read from untrusted source */
-/* values for e_if_macros */
-#define EIF_ADDR 0 /* ${if_addr} */
+#define DLVR_NOTIFY 0x01
+#define DLVR_RETURN 0x02
+#define DLVR_TRACE 0x10
+#define IS_DLVR_NOTIFY(e) (((e)->e_dlvr_flag & DLVR_NOTIFY) != 0)
+#define IS_DLVR_RETURN(e) (((e)->e_dlvr_flag & DLVR_RETURN) != 0)
+#define IS_DLVR_TRACE(e) (((e)->e_dlvr_flag & DLVR_TRACE) != 0)
+#define IS_DLVR_BY(e) ((e)->e_dlvr_flag != 0)
+
+#define BODYTYPE_NONE (0)
+#define BODYTYPE_7BIT (1)
+#define BODYTYPE_8BITMIME (2)
+#define BODYTYPE_ILLEGAL (-1)
+#define BODYTYPE_VALID(b) ((b) == BODYTYPE_7BIT || (b) == BODYTYPE_8BITMIME)
+
+extern ENVELOPE BlankEnvelope;
/* functions */
-extern void clearenvelope __P((ENVELOPE *, bool));
-extern void dropenvelope __P((ENVELOPE *, bool));
-extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *));
+extern void clearenvelope __P((ENVELOPE *, bool, SM_RPOOL_T *));
+extern void dropenvelope __P((ENVELOPE *, bool, bool));
+extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *, SM_RPOOL_T *));
extern void printenvflags __P((ENVELOPE *));
extern void putbody __P((MCI *, ENVELOPE *, char *));
extern void putheader __P((MCI *, HDR *, ENVELOPE *, int));
- /*
+/*
** Message priority classes.
**
** The message class is read directly from the Priority: header
@@ -711,7 +967,10 @@ struct priority
int pri_val; /* internal value for same */
};
- /*
+EXTERN int NumPriorities; /* pointer into Priorities */
+EXTERN struct priority Priorities[MAXPRIORITIES];
+
+/*
** Rewrite rules.
*/
@@ -732,35 +991,35 @@ struct rewrite
*/
/* left hand side items */
-#define MATCHZANY ((u_char)0220) /* match zero or more tokens */
-#define MATCHANY ((u_char)0221) /* match one or more tokens */
-#define MATCHONE ((u_char)0222) /* match exactly one token */
-#define MATCHCLASS ((u_char)0223) /* match one token in a class */
-#define MATCHNCLASS ((u_char)0224) /* match anything not in class */
-#define MATCHREPL ((u_char)0225) /* replacement on RHS for above */
+#define MATCHZANY ((unsigned char)0220) /* match zero or more tokens */
+#define MATCHANY ((unsigned char)0221) /* match one or more tokens */
+#define MATCHONE ((unsigned char)0222) /* match exactly one token */
+#define MATCHCLASS ((unsigned char)0223) /* match one token in a class */
+#define MATCHNCLASS ((unsigned char)0224) /* match anything not in class */
+#define MATCHREPL ((unsigned char)0225) /* replacement on RHS for above */
/* right hand side items */
-#define CANONNET ((u_char)0226) /* canonical net, next token */
-#define CANONHOST ((u_char)0227) /* canonical host, next token */
-#define CANONUSER ((u_char)0230) /* canonical user, next N tokens */
-#define CALLSUBR ((u_char)0231) /* call another rewriting set */
+#define CANONNET ((unsigned char)0226) /* canonical net, next token */
+#define CANONHOST ((unsigned char)0227) /* canonical host, next token */
+#define CANONUSER ((unsigned char)0230) /* canonical user, next N tokens */
+#define CALLSUBR ((unsigned char)0231) /* call another rewriting set */
/* conditionals in macros */
-#define CONDIF ((u_char)0232) /* conditional if-then */
-#define CONDELSE ((u_char)0233) /* conditional else */
-#define CONDFI ((u_char)0234) /* conditional fi */
+#define CONDIF ((unsigned char)0232) /* conditional if-then */
+#define CONDELSE ((unsigned char)0233) /* conditional else */
+#define CONDFI ((unsigned char)0234) /* conditional fi */
/* bracket characters for host name lookup */
-#define HOSTBEGIN ((u_char)0235) /* hostname lookup begin */
-#define HOSTEND ((u_char)0236) /* hostname lookup end */
+#define HOSTBEGIN ((unsigned char)0235) /* hostname lookup begin */
+#define HOSTEND ((unsigned char)0236) /* hostname lookup end */
/* bracket characters for generalized lookup */
-#define LOOKUPBEGIN ((u_char)0205) /* generalized lookup begin */
-#define LOOKUPEND ((u_char)0206) /* generalized lookup end */
+#define LOOKUPBEGIN ((unsigned char)0205) /* generalized lookup begin */
+#define LOOKUPEND ((unsigned char)0206) /* generalized lookup end */
/* macro substitution character */
-#define MACROEXPAND ((u_char)0201) /* macro expansion */
-#define MACRODEXPAND ((u_char)0202) /* deferred macro expansion */
+#define MACROEXPAND ((unsigned char)0201) /* macro expansion */
+#define MACRODEXPAND ((unsigned char)0202) /* deferred macro expansion */
/* to make the code clearer */
#define MATCHZERO CANONHOST
@@ -770,26 +1029,50 @@ struct rewrite
/* external <==> internal mapping table */
struct metamac
{
- char metaname; /* external code (after $) */
- u_char metaval; /* internal code (as above) */
+ char metaname; /* external code (after $) */
+ unsigned char metaval; /* internal code (as above) */
};
/* values for macros with external names only */
#define MID_OPMODE 0202 /* operation mode */
/* functions */
-extern void define __P((int, char *, ENVELOPE *));
+#if SM_HEAP_CHECK
+extern void
+macdefine_tagged __P((
+ MACROS_T *_mac,
+ ARGCLASS_T _vclass,
+ int _id,
+ char *_value,
+ char *_file,
+ int _line,
+ int _group));
+# define macdefine(mac,c,id,v) \
+ macdefine_tagged(mac,c,id,v,__FILE__,__LINE__,sm_heap_group())
+#else /* SM_HEAP_CHECK */
+extern void
+macdefine __P((
+ MACROS_T *_mac,
+ ARGCLASS_T _vclass,
+ int _id,
+ char *_value));
+# define macdefine_tagged(mac,c,id,v,file,line,grp) macdefine(mac,c,id,v)
+#endif /* SM_HEAP_CHECK */
+extern void macset __P((MACROS_T *, int, char *));
+#define macget(mac, i) (mac)->mac_table[i]
extern void expand __P((char *, char *, size_t, ENVELOPE *));
-extern int macid __P((char *, char **));
+extern int macid_parse __P((char *, char **));
+#define macid(name) macid_parse(name, NULL)
extern char *macname __P((int));
extern char *macvalue __P((int, ENVELOPE *));
-extern int rscheck __P((char *, char *, char *, ENVELOPE *, bool, bool, int, char *));
+extern int rscheck __P((char *, char *, char *, ENVELOPE *, bool, bool, int, char *, char *));
+extern int rscap __P((char *, char *, char *, ENVELOPE *, char ***, char *, int));
extern void setclass __P((int, char *));
extern int strtorwset __P((char *, char **, int));
extern void translate_dollars __P((char *));
extern bool wordinclass __P((char *, int));
- /*
+/*
** Name canonification short circuit.
**
** If the name server for a host is down, the process of trying to
@@ -808,16 +1091,29 @@ NAMECANON
short nc_stat; /* cached exit status code */
short nc_flags; /* flag bits */
char *nc_cname; /* the canonical name */
+ time_t nc_exp; /* entry expires at */
};
/* values for nc_flags */
#define NCF_VALID 0x0001 /* entry valid */
+/* hostsignature structure */
+
+struct hostsig_t
+{
+ char *hs_sig; /* hostsignature */
+ time_t hs_exp; /* entry expires at */
+};
+
+typedef struct hostsig_t HOSTSIG_T;
+
/* functions */
-extern bool getcanonname __P((char *, int, bool));
-extern int getmxrr __P((char *, char **, u_short *, bool, int *));
+extern bool getcanonname __P((char *, int, bool, int *));
+extern int getmxrr __P((char *, char **, unsigned short *, bool, int *, bool, int *));
+extern char *hostsignature __P((MAILER *, char *));
+extern int getfallbackmxrr __P((char *));
- /*
+/*
** Mapping functions
**
** These allow arbitrary mappings in the config file. The idea
@@ -836,6 +1132,7 @@ extern int getmxrr __P((char *, char **, u_short *, bool, int *));
MAP
{
MAPCLASS *map_class; /* the class of this map */
+ MAPCLASS *map_orgclass; /* the original class of this map */
char *map_mname; /* name of this map */
long map_mflags; /* flags, see below */
char *map_file; /* the (nominal) filename */
@@ -843,8 +1140,8 @@ MAP
ARBPTR_T map_db2; /* an "extra" database pointer */
char *map_keycolnm; /* key column name */
char *map_valcolnm; /* value column name */
- u_char map_keycolno; /* key column number */
- u_char map_valcolno; /* value column number */
+ unsigned char map_keycolno; /* key column number */
+ unsigned char map_valcolno; /* value column number */
char map_coldelim; /* column delimiter */
char map_spacesub; /* spacesub */
char *map_app; /* to append to successful matches */
@@ -852,6 +1149,8 @@ MAP
char *map_domain; /* the (nominal) NIS domain */
char *map_rebuild; /* program to run to do auto-rebuild */
time_t map_mtime; /* last database modification time */
+ time_t map_timeout; /* timeout for map accesses */
+ int map_retry; /* # of retries for map accesses */
pid_t map_pid; /* PID of process which opened map */
int map_lockfd; /* auxiliary lock file descriptor */
short map_specificity; /* specificity of aliases */
@@ -875,15 +1174,17 @@ MAP
#define MF_ALIASWAIT 0x00000800 /* alias map in aliaswait state */
#define MF_IMPL_HASH 0x00001000 /* implicit: underlying hash database */
#define MF_IMPL_NDBM 0x00002000 /* implicit: underlying NDBM database */
-#define MF_UNSAFEDB 0x00004000 /* this map is world writable */
+/* 0x00004000 */
#define MF_APPEND 0x00008000 /* append new entry on rebuild */
#define MF_KEEPQUOTES 0x00010000 /* don't dequote key before lookup */
#define MF_NODEFER 0x00020000 /* don't defer if map lookup fails */
#define MF_REGEX_NOT 0x00040000 /* regular expression negation */
#define MF_DEFER 0x00080000 /* don't lookup map in defer mode */
#define MF_SINGLEMATCH 0x00100000 /* successful only if match one key */
-#define MF_NOREWRITE 0x00200000 /* don't rewrite result, return as-is */
-#define MF_CLOSING 0x00400000 /* map is being closed */
+/* 0x00200000 available for use */
+#define MF_FILECLASS 0x00400000 /* this is a file class map */
+#define MF_OPENBOGUS 0x00800000 /* open failed, don't call map_close */
+#define MF_CLOSING 0x01000000 /* map is being closed */
#define DYNOPENMAP(map) if (!bitset(MF_OPEN, (map)->map_mflags)) \
{ \
@@ -897,6 +1198,15 @@ MAP
#define MA_UNAVAIL 1 /* member map is not available */
#define MA_TRYAGAIN 2 /* member map returns temp failure */
+/* macros to handle MapTempFail */
+#define BIT_IS_MTP 0x01 /* temp.failure occurred */
+#define BIT_ASK_MTP 0x02 /* do we care about MapTempFail? */
+#define RESET_MAPTEMPFAIL MapTempFail = 0
+#define INIT_MAPTEMPFAIL MapTempFail = BIT_ASK_MTP
+#define SET_MAPTEMPFAIL MapTempFail |= BIT_IS_MTP
+#define IS_MAPTEMPFAIL bitset(BIT_IS_MTP, MapTempFail)
+#define ASK_MAPTEMPFAIL bitset(BIT_ASK_MTP, MapTempFail)
+
/*
** The class of a map -- essentially the functions to call
*/
@@ -923,9 +1233,10 @@ MAPCLASS
#define MCF_ALIASONLY 0x0002 /* usable only for aliases */
#define MCF_REBUILDABLE 0x0004 /* can rebuild alias files */
#define MCF_OPTFILE 0x0008 /* file name is optional */
+#define MCF_NOTPERSIST 0x0010 /* don't keep map open all the time */
/* functions */
-extern void closemaps __P((void));
+extern void closemaps __P((bool));
extern bool impl_map_open __P((MAP *, int));
extern void initmaps __P((void));
extern MAP *makemapentry __P((char *));
@@ -938,47 +1249,13 @@ extern bool openmap __P((MAP *));
#if USERDB
extern void _udbx_close __P((void));
extern int udbexpand __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern char *udbsender __P((char *));
+extern char *udbsender __P((char *, SM_RPOOL_T *));
#endif /* USERDB */
- /*
+
+/*
** LDAP related items
*/
-#ifdef LDAPMAP
-struct ldapmap_struct
-{
- /* needed for ldap_open or ldap_init */
- char *ldap_host;
- int ldap_port;
-
- /* options set in ld struct before ldap_bind_s */
- int ldap_deref;
- time_t ldap_timelimit;
- int ldap_sizelimit;
- int ldap_options;
-
- /* args for ldap_bind_s */
- LDAP *ldap_ld;
- char *ldap_binddn;
- char *ldap_secret;
- int ldap_method;
-
- /* args for ldap_search */
- char *ldap_base;
- int ldap_scope;
- char *ldap_filter;
- char *ldap_attr[LDAPMAP_MAX_ATTR + 1];
- bool ldap_attrsonly;
-
- /* args for ldap_result */
- struct timeval ldap_timeout;
- LDAPMessage *ldap_res;
-
- /* Linked list of maps sharing the same LDAP binding */
- MAP *ldap_next;
-};
-
-typedef struct ldapmap_struct LDAPMAP_STRUCT;
-
+#if LDAPMAP
/* struct defining LDAP Auth Methods */
struct lamvalues
{
@@ -1005,35 +1282,29 @@ extern bool ldapmap_parseargs __P((MAP *, char *));
extern void ldapmap_set_defaults __P((char *));
#endif /* LDAPMAP */
- /*
+/*
** PH related items
*/
-#ifdef PH_MAP
+#if PH_MAP
+
+# include <phclient.h>
+
struct ph_map_struct
{
- char *ph_servers; /* list of ph servers */
- char *ph_field_list; /* list of fields to search for match */
- FILE *ph_to_server;
- FILE *ph_from_server;
- int ph_sockfd;
- time_t ph_timeout;
+ char *ph_servers; /* list of ph servers */
+ char *ph_field_list; /* list of fields to search for match */
+ PH *ph; /* PH server handle */
+ int ph_fastclose; /* send "quit" command on close */
+ time_t ph_timeout; /* timeout interval */
};
typedef struct ph_map_struct PH_MAP_STRUCT;
-# define DEFAULT_PH_MAP_FIELDS "alias callsign name spacedname"
#endif /* PH_MAP */
- /*
+/*
** Process List (proclist)
*/
-struct procs
-{
- pid_t proc_pid;
- char *proc_task;
- int proc_type;
-};
-
#define NO_PID ((pid_t) 0)
#ifndef PROC_LIST_SEG
# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */
@@ -1049,22 +1320,22 @@ struct procs
#define PROC_CONTROL_CHILD 5
/* functions */
-extern void proc_list_add __P((pid_t, char *, int));
+extern void proc_list_add __P((pid_t, char *, int, int, int));
extern void proc_list_clear __P((void));
-extern void proc_list_display __P((FILE *));
-extern int proc_list_drop __P((pid_t));
+extern void proc_list_display __P((SM_FILE_T *, char *));
+extern void proc_list_drop __P((pid_t, int, int *));
extern void proc_list_probe __P((void));
extern void proc_list_set __P((pid_t, char *));
+extern void proc_list_signal __P((int, int));
- /*
+/*
** Symbol table definitions
*/
struct symtab
{
char *s_name; /* name to be entered */
- short s_type; /* general type (see below) */
- short s_len; /* length of this entry */
+ short s_symtype; /* general type (see below) */
struct symtab *s_next; /* pointer to next in chain */
union
{
@@ -1074,19 +1345,20 @@ struct symtab
char *sv_alias; /* alias */
MAPCLASS sv_mapclass; /* mapping function class */
MAP sv_map; /* mapping function */
- char *sv_hostsig; /* host signature */
+ HOSTSIG_T sv_hostsig; /* host signature */
MCI sv_mci; /* mailer connection info */
NAMECANON sv_namecanon; /* canonical name cache */
int sv_macro; /* macro name => id mapping */
int sv_ruleset; /* ruleset index */
struct hdrinfo sv_header; /* header metainfo */
char *sv_service[MAXMAPSTACK]; /* service switch */
-#ifdef LDAPMAP
+#if LDAPMAP
MAP *sv_lmap; /* Maps for LDAP connection */
#endif /* LDAPMAP */
-#if _FFR_MILTER
+#if MILTER
struct milter *sv_milter; /* milter filter name */
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
+ QUEUEGRP *sv_queue; /* pointer to queue */
} s_value;
};
@@ -1106,12 +1378,15 @@ typedef struct symtab STAB;
#define ST_RULESET 10 /* ruleset index */
#define ST_SERVICE 11 /* service switch entry */
#define ST_HEADER 12 /* special header flags */
-#ifdef LDAPMAP
+#if LDAPMAP
# define ST_LMAP 13 /* List head of maps for LDAP connection */
#endif /* LDAPMAP */
-#if _FFR_MILTER
+#if MILTER
# define ST_MILTER 14 /* milter filter */
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
+#define ST_QUEUE 15 /* a queue entry */
+
+/* This entry must be last */
#define ST_MCI 16 /* mailer connection info (offset) */
#define s_class s_value.sv_class
@@ -1127,12 +1402,13 @@ typedef struct symtab STAB;
#define s_ruleset s_value.sv_ruleset
#define s_service s_value.sv_service
#define s_header s_value.sv_header
-#ifdef LDAPMAP
+#if LDAPMAP
# define s_lmap s_value.sv_lmap
#endif /* LDAPMAP */
-#if _FFR_MILTER
+#if MILTER
# define s_milter s_value.sv_milter
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
+#define s_quegrp s_value.sv_queue
/* opcodes to stab */
#define ST_FIND 0 /* find entry */
@@ -1142,34 +1418,7 @@ typedef struct symtab STAB;
extern STAB *stab __P((char *, int, int));
extern void stabapply __P((void (*)(STAB *, int), int));
- /*
-** STRUCT EVENT -- event queue.
-**
-** Maintained in sorted order.
-**
-** We store the pid of the process that set this event to insure
-** that when we fork we will not take events intended for the parent.
-*/
-
-struct event
-{
- time_t ev_time; /* time of the function call */
- void (*ev_func)__P((int));
- /* function to call */
- int ev_arg; /* argument to ev_func */
- pid_t ev_pid; /* pid that set this event */
- struct event *ev_link; /* link to next item */
-};
-
-typedef struct event EVENT;
-
-/* functions */
-extern void clrevent __P((EVENT *));
-extern void clear_events __P((void));
-extern EVENT *setevent __P((time_t, void(*)(), int));
-extern EVENT *sigsafe_setevent __P((time_t, void(*)(), int));
-
- /*
+/*
** Operation, send, error, and MIME modes
**
** The operation mode describes the basic operation of sendmail.
@@ -1177,7 +1426,7 @@ extern EVENT *sigsafe_setevent __P((time_t, void(*)(), int));
** default.
**
** The send mode tells how to send mail. It can be set in the
-** configuration file. It's setting determines how quickly the
+** configuration file. Its setting determines how quickly the
** mail will be delivered versus the load on your system. If the
** -v (verbose) flag is given, it will be forced to SM_DELIVER
** mode.
@@ -1194,11 +1443,14 @@ extern EVENT *sigsafe_setevent __P((time_t, void(*)(), int));
#define MD_TEST 't' /* test mode: resolve addrs only */
#define MD_INITALIAS 'i' /* initialize alias database */
#define MD_PRINT 'p' /* print the queue */
+#define MD_PRINTNQE 'P' /* print number of entries in queue */
#define MD_FREEZE 'z' /* freeze the configuration file */
#define MD_HOSTSTAT 'h' /* print persistent host stat info */
#define MD_PURGESTAT 'H' /* purge persistent host stat info */
#define MD_QUEUERUN 'q' /* queue run */
+/* Note: see also include/sendmail/pathnames.h: GET_CLIENT_CF */
+
/* values for e_sendmode -- send modes */
#define SM_DELIVER 'i' /* interactive delivery */
#define SM_FORK 'b' /* deliver in background */
@@ -1206,6 +1458,7 @@ extern EVENT *sigsafe_setevent __P((time_t, void(*)(), int));
#define SM_DEFER 'd' /* defer map lookups as well as queue */
#define SM_VERIFY 'v' /* verify only (used internally) */
+#define WILL_BE_QUEUED(m) ((m) == SM_QUEUE || (m) == SM_DEFER)
/* used only as a parameter to sendall */
#define SM_DEFAULT '\0' /* unspecified, use SendMode */
@@ -1246,30 +1499,33 @@ extern void set_delivery_mode __P((int, ENVELOPE *));
** These are bit values for the PrivacyFlags word.
*/
-#define PRIV_PUBLIC 0 /* what have I got to hide? */
-#define PRIV_NEEDMAILHELO 0x0001 /* insist on HELO for MAIL, at least */
-#define PRIV_NEEDEXPNHELO 0x0002 /* insist on HELO for EXPN */
-#define PRIV_NEEDVRFYHELO 0x0004 /* insist on HELO for VRFY */
-#define PRIV_NOEXPN 0x0008 /* disallow EXPN command entirely */
-#define PRIV_NOVRFY 0x0010 /* disallow VRFY command entirely */
-#define PRIV_AUTHWARNINGS 0x0020 /* flag possible authorization probs */
-#define PRIV_NORECEIPTS 0x0040 /* disallow return receipts */
-#define PRIV_NOVERB 0x0100 /* disallow VERB command entirely */
-#define PRIV_RESTRICTMAILQ 0x1000 /* restrict mailq command */
-#define PRIV_RESTRICTQRUN 0x2000 /* restrict queue run */
-#define PRIV_NOETRN 0x4000 /* disallow ETRN command entirely */
-#define PRIV_NOBODYRETN 0x8000 /* do not return bodies on bounces */
+#define PRIV_PUBLIC 0 /* what have I got to hide? */
+#define PRIV_NEEDMAILHELO 0x00000001 /* insist on HELO for MAIL */
+#define PRIV_NEEDEXPNHELO 0x00000002 /* insist on HELO for EXPN */
+#define PRIV_NEEDVRFYHELO 0x00000004 /* insist on HELO for VRFY */
+#define PRIV_NOEXPN 0x00000008 /* disallow EXPN command */
+#define PRIV_NOVRFY 0x00000010 /* disallow VRFY command */
+#define PRIV_AUTHWARNINGS 0x00000020 /* flag possible auth probs */
+#define PRIV_NOVERB 0x00000040 /* disallow VERB command */
+#define PRIV_RESTRICTMAILQ 0x00010000 /* restrict mailq command */
+#define PRIV_RESTRICTQRUN 0x00020000 /* restrict queue run */
+#define PRIV_RESTRICTEXPAND 0x00040000 /* restrict alias/forward expansion */
+#define PRIV_NOETRN 0x00080000 /* disallow ETRN command */
+#define PRIV_NOBODYRETN 0x00100000 /* do not return bodies on bounces */
+#define PRIV_NORECEIPTS 0x00200000 /* disallow return receipts */
/* don't give no info, anyway, anyhow */
-#define PRIV_GOAWAY (0x0fff & ~PRIV_NORECEIPTS)
+#define PRIV_GOAWAY 0x0000ffff
/* struct defining such things */
struct prival
{
- char *pv_name; /* name of privacy flag */
- u_short pv_flag; /* numeric level */
+ char *pv_name; /* name of privacy flag */
+ unsigned long pv_flag; /* numeric level */
};
+EXTERN unsigned long PrivacyFlags; /* privacy flags */
+
/*
** Flags passed to remotename, parseaddr, allocaddr, and buildaddr.
@@ -1344,35 +1600,32 @@ union bigsockaddr
extern char *anynet_ntoa __P((SOCKADDR *));
# if NETINET6
extern char *anynet_ntop __P((struct in6_addr *, char *, size_t));
+extern int anynet_pton __P((int, const char *, void *));
# endif /* NETINET6 */
extern char *hostnamebyanyaddr __P((SOCKADDR *));
-# if DAEMON
extern char *validate_connection __P((SOCKADDR *, char *, ENVELOPE *));
-# endif /* DAEMON */
#endif /* NETINET || NETINET6 || NETUNIX || NETISO || NETNS || NETX25 */
-#if _FFR_MILTER
- /*
+#if MILTER
+/*
** Mail Filters (milter)
*/
-#include <libmilter/milter.h>
-
-#define SMFTO_WRITE 0 /* Timeout for sending information */
-#define SMFTO_READ 1 /* Timeout waiting for a response */
-#define SMFTO_EOM 2 /* Timeout for ACK/NAK to EOM */
-#define SMFTO_CONNECT 3 /* Timeout for connect() */
+# define SMFTO_WRITE 0 /* Timeout for sending information */
+# define SMFTO_READ 1 /* Timeout waiting for a response */
+# define SMFTO_EOM 2 /* Timeout for ACK/NAK to EOM */
+# define SMFTO_CONNECT 3 /* Timeout for connect() */
-#define SMFTO_NUM_TO 4 /* Total number of timeouts */
+# define SMFTO_NUM_TO 4 /* Total number of timeouts */
struct milter
{
char *mf_name; /* filter name */
BITMAP256 mf_flags; /* MTA flags */
- u_long mf_fvers; /* filter version */
- u_long mf_fflags; /* filter flags */
- u_long mf_pflags; /* protocol flags */
+ unsigned long mf_fvers; /* filter version */
+ unsigned long mf_fflags; /* filter flags */
+ unsigned long mf_pflags; /* protocol flags */
char *mf_conn; /* connection info */
int mf_sock; /* connected socket */
char mf_state; /* state of filter */
@@ -1392,12 +1645,22 @@ struct milter
# define SMFS_ERROR 'E' /* error state */
# define SMFS_READY 'R' /* ready for action */
-/* 32-bit type used by milter */
-typedef SM_INT32 mi_int32;
-
EXTERN struct milter *InputFilters[MAXFILTERS];
EXTERN char *InputFilterList;
-#endif /* _FFR_MILTER */
+EXTERN int MilterLogLevel;
+
+# if _FFR_MILTER_PERDAEMON
+/* functions */
+extern void setup_daemon_milters __P(());
+# endif /* _FFR_MILTER_PERDAEMON */
+#endif /* MILTER */
+
+/*
+** 32-bit type used by milter
+** (needed by libmilter even if MILTER isn't defined)
+*/
+
+typedef SM_INT32 mi_int32;
/*
** Vendor codes
@@ -1419,6 +1682,7 @@ EXTERN char *InputFilterList;
#define VENDOR_HP 3 /* Hewlett-Packard specific config syntax */
#define VENDOR_IBM 4 /* IBM specific config syntax */
#define VENDOR_SENDMAIL 5 /* Sendmail, Inc. specific config syntax */
+#define VENDOR_DEC 6 /* Compaq, DEC, Digital */
/* prototypes for vendor-specific hook routines */
extern void vendor_daemon_setup __P((ENVELOPE *));
@@ -1437,60 +1701,36 @@ struct termescape
char *te_rv_off; /* turn reverse-video off */
};
- /*
+/*
** Additional definitions
*/
-/* d_flags, see daemon.c */
-/* general rule: lower case: required, upper case: No */
+/*
+** d_flags, see daemon.c
+** general rule: lower case: required, upper case: No
+*/
+
#define D_AUTHREQ 'a' /* authentication required */
#define D_BINDIF 'b' /* use if_addr for outgoing connection */
#define D_CANONREQ 'c' /* canonification required (cf) */
#define D_IFNHELO 'h' /* use if name for HELO */
#define D_FQMAIL 'f' /* fq sender address required (cf) */
-#if _FFR_TLS_CLT1
-#define D_CLTNOTLS 'S' /* don't use STARTTLS in client */
-#endif /* _FFR_TLS_CLT1 */
#define D_FQRCPT 'r' /* fq recipient address required (cf) */
+#if _FFR_SMTP_SSL
+# define D_SMTPS 's' /* SMTP over SSL (smtps) */
+#endif /* _FFR_SMTP_SSL */
#define D_UNQUALOK 'u' /* unqualified address is ok (cf) */
+#define D_NOAUTH 'A' /* no AUTH */
#define D_NOCANON 'C' /* no canonification (cf) */
#define D_NOETRN 'E' /* no ETRN (MSA) */
+#define D_NOTLS 'S' /* don't use STARTTLS */
#define D_ETRNONLY ((char)0x01) /* allow only ETRN (disk low) */
-
-/* Flags for submitmode */
-#define SUBMIT_UNKNOWN 0x0000 /* unknown agent type */
-#define SUBMIT_MTA 0x0001 /* act like a message transfer agent */
-#define SUBMIT_MSA 0x0002 /* act like a message submission agent */
-
-#if SASL
- /*
-** SASL
-*/
-
-/* authenticated? */
-# define SASL_NOT_AUTH 0 /* not authenticated */
-# define SASL_PROC_AUTH 1 /* in process of authenticating */
-# define SASL_IS_AUTH 2 /* authenticated */
-
-/* SASL options */
-# define SASL_AUTH_AUTH 0x1000 /* use auth= only if authenticated */
-# if _FFR_SASL_OPTS
-# define SASL_SEC_MASK 0x0fff /* mask for SASL_SEC_* values: sasl.h */
-# if (SASL_SEC_NOPLAINTEXT & SASL_SEC_MASK) == 0 || \
- (SASL_SEC_NOACTIVE & SASL_SEC_MASK) == 0 || \
- (SASL_SEC_NODICTIONARY & SASL_SEC_MASK) == 0 || \
- (SASL_SEC_FORWARD_SECRECY & SASL_SEC_MASK) == 0 || \
- (SASL_SEC_NOANONYMOUS & SASL_SEC_MASK) == 0 || \
- (SASL_SEC_PASS_CREDENTIALS & SASL_SEC_MASK) == 0
-ERROR: change SASL_SEC_MASK_ notify sendmail.org!
-# endif
-# endif /* _FFR_SASL_OPTS */
-
-# define MAXOUTLEN 1024 /* length of output buffer */
-#endif /* SASL */
+#define D_OPTIONAL 'O' /* optional socket */
+#define D_DISABLE ((char)0x02) /* optional socket disabled */
+#define D_ISSET ((char)0x03) /* this client struct is set */
#if STARTTLS
- /*
+/*
** TLS
*/
@@ -1517,65 +1757,178 @@ ERROR: change SASL_SEC_MASK_ notify sendmail.org!
#define TLS_I_DH512 0x00040000 /* generate 512bit DH param */
#define TLS_I_DH1024 0x00080000 /* generate 1024bit DH param */
#define TLS_I_DH2048 0x00100000 /* generate 2048bit DH param */
+#define TLS_I_NO_VRFY 0x00200000 /* do not require authentication */
+#define TLS_I_KEY_OUNR 0x00400000 /* KEY must be o unreadable */
+
+/* require server cert */
+#define TLS_I_SRV_CERT (TLS_I_CERT_EX | TLS_I_KEY_EX | \
+ TLS_I_KEY_UNR | TLS_I_KEY_OUNR | \
+ TLS_I_CERTP_EX | TLS_I_CERTF_EX | \
+ TLS_I_USE_KEY | TLS_I_USE_CERT)
/* server requirements */
-#define TLS_I_SRV (TLS_I_CERT_EX | TLS_I_KEY_EX | TLS_I_KEY_UNR | \
- TLS_I_CERTP_EX | TLS_I_CERTF_EX | TLS_I_RSA_TMP | \
- TLS_I_USE_KEY | TLS_I_USE_CERT | TLS_I_VRFY_PATH | \
- TLS_I_VRFY_LOC | TLS_I_TRY_DH | \
- TLS_I_DH512)
+#define TLS_I_SRV (TLS_I_SRV_CERT | TLS_I_RSA_TMP | TLS_I_VRFY_PATH | \
+ TLS_I_VRFY_LOC | TLS_I_TRY_DH | TLS_I_DH512)
/* client requirements */
-#define TLS_I_CLT (TLS_I_KEY_UNR)
+#define TLS_I_CLT (TLS_I_KEY_UNR | TLS_I_KEY_OUNR)
#define TLS_AUTH_OK 0
#define TLS_AUTH_NO 1
#define TLS_AUTH_FAIL (-1)
-#endif /* STARTTLS */
+
+/* functions */
+extern bool init_tls_library __P((void));
+extern bool inittls __P((SSL_CTX **, unsigned long, bool, char *, char *, char *, char *, char *));
+extern bool initclttls __P((bool));
+extern void setclttls __P((bool));
+extern bool initsrvtls __P((bool));
+extern int tls_get_info __P((SSL *, bool, char *, MACROS_T *, bool));
+extern int endtls __P((SSL *, char *));
+extern void tlslogerr __P((char *));
- /*
+EXTERN char *CACERTpath; /* path to CA certificates (dir. with hashes) */
+EXTERN char *CACERTfile; /* file with CA certificate */
+EXTERN char *CltCERTfile; /* file with client certificate */
+EXTERN char *Cltkeyfile; /* file with client private key */
+# if _FFR_TLS_1
+EXTERN char *CipherList; /* list of ciphers */
+EXTERN char *DHParams5; /* file with DH parameters (512) */
+# endif /* _FFR_TLS_1 */
+EXTERN char *DHParams; /* file with DH parameters */
+EXTERN char *RandFile; /* source of random data */
+EXTERN char *SrvCERTfile; /* file with server certificate */
+EXTERN char *Srvkeyfile; /* file with server private key */
+EXTERN unsigned long TLS_Srv_Opts; /* TLS server options */
+#endif /* STARTTLS */
+
+/*
** Queue related items
*/
+/* queue file names */
+#if _FFR_QUARANTINE
+# define ANYQFL_LETTER '?'
+# define QUARQF_LETTER 'h'
+#else /* _FFR_QUARANTINE */
+/* Before quarantining, ANYQF == NORMQF */
+# define ANYQFL_LETTER 'q'
+#endif /* _FFR_QUARANTINE */
+#define DATAFL_LETTER 'd'
+#define XSCRPT_LETTER 'x'
+#define NORMQF_LETTER 'q'
+#define NEWQFL_LETTER 't'
+
+# define TEMPQF_LETTER 'T'
+# define LOSEQF_LETTER 'Q'
+
/* queue sort order */
#define QSO_BYPRIORITY 0 /* sort by message priority */
#define QSO_BYHOST 1 /* sort by first host name */
#define QSO_BYTIME 2 /* sort by submission time */
#define QSO_BYFILENAME 3 /* sort by file name only */
+#define QSO_RANDOM 4 /* sort in random order */
+#define QSO_BYMODTIME 5 /* sort by modification time */
+#if _FFR_RHS
+# define QSO_BYSHUFFLE 6 /* sort by shuffled host name */
+#endif /* _FFR_RHS */
#if _FFR_QUEUEDELAY
-#define QD_LINEAR 0 /* linear (old) delay alg */
-#define QD_EXP 1 /* exponential delay alg */
+# define QD_LINEAR 0 /* linear (old) delay alg */
+# define QD_EXP 1 /* exponential delay alg */
#endif /* _FFR_QUEUEDELAY */
-#define NOQDIR (-1) /* no queue directory (yet) */
-
-#define NOW ((time_t) (-1)) /* queue return: now */
+#define NOQGRP (-1) /* no queue group (yet) */
+#define ENVQGRP (-2) /* use queue group of envelope */
+#define NOAQGRP (-3) /* no queue group in addr (yet) */
+#define ISVALIDQGRP(x) ((x) >= 0) /* valid queue group? */
+#define NOQDIR (-1) /* no queue directory (yet) */
+#define ENVQDIR (-2) /* use queue directory of envelope */
+#define NOAQDIR (-3) /* no queue directory in addr (yet) */
+#define ISVALIDQDIR(x) ((x) >= 0) /* valid queue directory? */
+#define RS_QUEUEGROUP "queuegroup" /* ruleset for queue group selection */
+
+#define NOW ((time_t) (-1)) /* queue return: now */
+
+/* SuperSafe values */
+#define SAFE_NO 0 /* no fsync(): don't use... */
+#define SAFE_INTERACTIVE 1 /* limit fsync() in -odi */
+#define SAFE_REALLY 2 /* always fsync() */
+
+#if _FFR_QUARANTINE
+/* QueueMode bits */
+# define QM_NORMAL ' '
+# define QM_QUARANTINE 'Q'
+# define QM_LOST 'L'
+#endif /* _FFR_QUARANTINE */
/* Queue Run Limitations */
struct queue_char
{
- char *queue_match; /* string to match */
- struct queue_char *queue_next;
+ char *queue_match; /* string to match */
+ bool queue_negate; /* or not match, if set */
+ struct queue_char *queue_next;
};
-typedef struct queue_char QUEUE_CHAR;
+typedef struct queue_char QUEUE_CHAR;
+
+EXTERN int volatile CurRunners; /* current number of runner children */
+EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */
+EXTERN int MaxQueueChildren; /* max # of forked queue children */
+EXTERN int MaxRunnersPerQueue; /* max # proc's active in queue group */
+EXTERN int NiceQueueRun; /* nice queue runs to this value */
+EXTERN int NumQueue; /* number of queue groups */
+EXTERN int QueueFileMode; /* mode on files in mail queue */
+#if _FFR_QUARANTINE
+EXTERN int QueueMode; /* which queue items to act upon */
+#endif /* _FFR_QUARANTINE */
+EXTERN int QueueSortOrder; /* queue sorting order algorithm */
+EXTERN time_t MinQueueAge; /* min delivery interval */
+EXTERN time_t QueueIntvl; /* intervals between running the queue */
+EXTERN char *QueueDir; /* location of queue directory */
+#if _FFR_QUEUEDELAY
+EXTERN int QueueAlg; /* algorithm for queue delays */
+EXTERN time_t QueueInitDelay; /* initial queue delay */
+EXTERN time_t QueueMaxDelay; /* maximum queue delay */
+#endif /* _FFR_QUEUEDELAY */
+EXTERN QUEUE_CHAR *QueueLimitId; /* limit queue run to id */
+#if _FFR_QUARANTINE
+EXTERN QUEUE_CHAR *QueueLimitQuarantine; /* limit queue run to quarantine reason */
+#endif /* _FFR_QUARANTINE */
+EXTERN QUEUE_CHAR *QueueLimitRecipient; /* limit queue run to rcpt */
+EXTERN QUEUE_CHAR *QueueLimitSender; /* limit queue run to sender */
+EXTERN QUEUEGRP *Queue[MAXQUEUEGROUPS + 1]; /* queue groups */
/* functions */
extern void assign_queueid __P((ENVELOPE *));
-extern ADDRESS *copyqueue __P((ADDRESS *));
+extern ADDRESS *copyqueue __P((ADDRESS *, SM_RPOOL_T *));
+extern void cleanup_queues __P((void));
+extern bool doqueuerun __P((void));
extern void initsys __P((ENVELOPE *));
extern void loseqfile __P((ENVELOPE *, char *));
-extern void multiqueue_cache __P((void));
+extern int name2qid __P((char *));
extern char *qid_printname __P((ENVELOPE *));
-extern char *qid_printqueue __P((int));
+extern char *qid_printqueue __P((int, int));
+#if _FFR_QUARANTINE
+extern void quarantine_queue __P((char *, int));
+#endif /* _FFR_QUARANTINE */
extern char *queuename __P((ENVELOPE *, int));
-extern void queueup __P((ENVELOPE *, bool));
-extern bool runqueue __P((bool, bool));
-extern void setnewqueue __P((ENVELOPE *));
+extern void queueup __P((ENVELOPE *, bool, bool));
+extern bool runqueue __P((bool, bool, bool, bool));
+extern int run_work_group __P((int, bool, bool, bool, bool));
+extern void set_def_queueval __P((QUEUEGRP *, bool));
+extern void setup_queues __P((bool));
+extern bool setnewqueue __P((ENVELOPE *));
extern bool shouldqueue __P((long, time_t));
extern void sync_queue_time __P((void));
+extern int print_single_queue __P((int, int));
+#if REQUIRES_DIR_FSYNC
+# define SYNC_DIR(path, panic) sync_dir(path, panic)
+extern void sync_dir __P((char *, bool));
+#else /* REQUIRES_DIR_FSYNC */
+# define SYNC_DIR(path, panic) ((void) 0)
+#endif /* REQUIRES_DIR_FSYNC */
/*
** Timeouts
@@ -1596,6 +1949,7 @@ EXTERN struct
/* following timeouts are not mentioned in RFC 1123 */
time_t to_iconnect; /* initial connection timeout (first try) */
time_t to_connect; /* initial connection timeout (later tries) */
+ time_t to_aconnect; /* all connections timeout (MX and A records) */
time_t to_rset; /* RSET command */
time_t to_helo; /* HELO command */
time_t to_quit; /* QUIT command */
@@ -1603,6 +1957,13 @@ EXTERN struct
time_t to_ident; /* IDENT protocol requests */
time_t to_fileopen; /* opening :include: and .forward files */
time_t to_control; /* process a control socket command */
+ time_t to_lhlo; /* LMTP: LHLO command */
+#if SASL
+ time_t to_auth; /* AUTH dialogue [10m] */
+#endif /* SASL */
+#if STARTTLS
+ time_t to_starttls; /* STARTTLS dialogue [10m] */
+#endif /* STARTTLS */
/* following are per message */
time_t to_q_return[MAXTOCLASS]; /* queue return timeouts */
time_t to_q_warning[MAXTOCLASS]; /* queue warning timeouts */
@@ -1624,62 +1985,25 @@ EXTERN struct
extern void inittimeouts __P((char *, bool));
/*
-** Trace information
+** Interface probing
*/
-/* macros for debugging flags */
-#define tTd(flag, level) (tTdvect[flag] >= (u_char)level)
-#define tTdlevel(flag) (tTdvect[flag])
+#define DPI_PROBENONE 0 /* Don't probe any interfaces */
+#define DPI_PROBEALL 1 /* Probe all interfaces */
+#define DPI_SKIPLOOPBACK 2 /* Don't probe loopback interfaces */
-/* variables */
-extern u_char tTdvect[100]; /* trace vector */
- /*
-** Critical signal sections
+/*
+** Trace information
*/
-#define PEND_SIGHUP 0x0001
-#define PEND_SIGINT 0x0002
-#define PEND_SIGTERM 0x0004
-#define PEND_SIGUSR1 0x0008
-
-#define ENTER_CRITICAL() InCriticalSection++
-
-#define LEAVE_CRITICAL() \
-do \
-{ \
- if (InCriticalSection > 0) \
- InCriticalSection--; \
-} while (0)
-
-#define CHECK_CRITICAL(sig) \
-do \
-{ \
- if (InCriticalSection > 0 && (sig) != 0) \
- { \
- pend_signal((sig)); \
- return SIGFUNC_RETURN; \
- } \
-} while (0)
-
-/* reset signal in case System V semantics */
-#ifdef SYS5SIGNALS
-# define FIX_SYSV_SIGNAL(sig, handler) \
-{ \
- if ((sig) != 0) \
- (void) setsignal((sig), (handler)); \
-}
-#else /* SYS5SIGNALS */
-# define FIX_SYSV_SIGNAL(sig, handler) { /* EMPTY */ }
-#endif /* SYS5SIGNALS */
+/* macros for debugging flags */
+#define tTd(flag, level) (tTdvect[flag] >= (unsigned char)level)
+#define tTdlevel(flag) (tTdvect[flag])
/* variables */
-EXTERN u_int volatile InCriticalSection; /* >0 if in a critical section */
-EXTERN int volatile PendingSignal; /* pending signal to resend */
-
-/* functions */
-extern void pend_signal __P((int));
+extern unsigned char tTdvect[100]; /* trace vector */
- /*
+/*
** Miscellaneous information.
*/
@@ -1689,6 +2013,10 @@ extern void pend_signal __P((int));
#define NOQID "*~*"
+/* use id or NOQID (to avoid NOQUEUE in logfile) */
+#define E_ID(id) ((id) == NULL ? NOQID : (id))
+
+#define CURHOSTNAME (CurHostName == NULL ? "local" : CurHostName)
/*
** Some in-line functions
@@ -1704,25 +2032,59 @@ extern void pend_signal __P((int));
#define newstr(s) strcpy(xalloc(strlen(s) + 1), s)
#define STRUCTCOPY(s, d) d = s
- /*
+
+/* free a pointer if it isn't NULL and set it to NULL */
+#define SM_FREE_CLR(p) \
+ if ((p) != NULL) \
+ { \
+ sm_free(p); \
+ (p) = NULL; \
+ } \
+ else
+
+/*
+** Update a permanent string variable with a new value.
+** The old value is freed, the new value is strdup'ed.
+**
+** We use sm_pstrdup_x to duplicate the string because it raises
+** an exception on error, and because it allocates "permanent storage"
+** which is not expected to be freed before process exit.
+** The latter is important for memory leak analysis.
+**
+** If an exception occurs while strdup'ing the new value,
+** then the variable remains set to the old value.
+** That's why the strdup must occur before we free the old value.
+**
+** The macro uses a do loop so that this idiom will work:
+** if (...)
+** PSTRSET(var, val1);
+** else
+** PSTRSET(var, val2);
+*/
+#define PSTRSET(var, val) \
+ do \
+ { \
+ char *_newval = sm_pstrdup_x(val); \
+ if (var != NULL) \
+ sm_free(var); \
+ var = _newval; \
+ } while (0)
+
+/*
** Global variables.
*/
EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */
-#if !_FFR_REMOVE_AUTOREBUILD
-EXTERN bool AutoRebuild; /* auto-rebuild the alias database as needed */
-#endif /* !_FFR_REMOVE_AUTOREBUILD */
EXTERN bool CheckAliases; /* parse addresses during newaliases */
-EXTERN bool ChownAlwaysSafe; /* treat chown(2) as safe */
EXTERN bool ColonOkInAddr; /* single colon legal in address */
+#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
EXTERN bool ConfigFileRead; /* configuration file has been read */
+#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
EXTERN bool volatile DataProgress; /* have we sent anything since last check */
-EXTERN bool DisConnected; /* running with OutChannel redirected to xf */
-EXTERN bool volatile DoQueueRun; /* non-interrupt time queue run needed */
+EXTERN bool DisConnected; /* running with OutChannel redirect to transcript file */
EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */
EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */
EXTERN bool DontLockReadFiles; /* don't read lock support files */
-EXTERN bool DontProbeInterfaces; /* don't probe interfaces for names */
EXTERN bool DontPruneRoutes; /* don't prune source routes */
EXTERN bool ForkQueueRuns; /* fork for each job when running the queue */
EXTERN bool FromFlag; /* if set, "From" person is explicit */
@@ -1732,42 +2094,46 @@ EXTERN bool HasWildcardMX; /* don't use MX records when canonifying */
EXTERN bool HoldErrs; /* only output errors to transcript */
EXTERN bool IgnoreHostStatus; /* ignore long term host status files */
EXTERN bool IgnrDot; /* don't let dot end messages */
-EXTERN bool InChild; /* true if running in an SMTP subprocess */
EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */
-EXTERN bool MapOpenErr; /* error opening a non-optional map */
EXTERN bool MatchGecos; /* look for user names in gecos field */
EXTERN bool MeToo; /* send to the sender also */
EXTERN bool NoAlias; /* suppress aliasing */
EXTERN bool NoConnect; /* don't connect to non-local mailers */
EXTERN bool OnlyOneError; /* .... or only want to give one SMTP reply */
EXTERN bool QuickAbort; /* .... but only if we want a quick abort */
+EXTERN bool ResNoAliases; /* don't use $HOSTALIASES */
+EXTERN bool volatile RestartWorkGroup; /* daemon needs to restart some work groups */
EXTERN bool RrtImpliesDsn; /* turn Return-Receipt-To: into DSN */
EXTERN bool SaveFrom; /* save leading "From" lines */
EXTERN bool SendMIMEErrors; /* send error messages in MIME format */
EXTERN bool SevenBitInput; /* force 7-bit data on input */
EXTERN bool SingleLineFromHeader; /* force From: header to be one line */
EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */
+#if _FFR_SOFT_BOUNCE
+EXTERN bool SoftBounce; /* replace 5xy by 4xy (for testing) */
+#endif /* _FFR_SOFT_BOUNCE */
EXTERN bool volatile StopRequest; /* stop sending output */
-EXTERN bool SuperSafe; /* be extra careful, even if expensive */
EXTERN bool SuprErrs; /* set if we are suppressing errors */
EXTERN bool TryNullMXList; /* if we are the best MX, try host directly */
-#if _FFR_WORKAROUND_BROKEN_NAMESERVERS
+EXTERN bool UseMSP; /* mail submission: group writable queue ok? */
EXTERN bool WorkAroundBrokenAAAA; /* some nameservers return SERVFAIL on AAAA queries */
-#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */
EXTERN bool UseErrorsTo; /* use Errors-To: header (back compat) */
-EXTERN bool UseHesiod; /* using Hesiod -- interpret Hesiod errors */
EXTERN bool UseNameServer; /* using DNS -- interpret h_errno & MX RRs */
EXTERN char InetMode; /* default network for daemon mode */
EXTERN char OpMode; /* operation mode, see below */
EXTERN char SpaceSub; /* substitution for <lwsp> */
+EXTERN int BadRcptThrottle; /* Throttle rejected RCPTs per SMTP message */
EXTERN int CheckpointInterval; /* queue file checkpoint interval */
EXTERN int ConfigLevel; /* config file level */
EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */
EXTERN int volatile CurChildren; /* current number of daemonic children */
EXTERN int CurrentLA; /* current load average */
EXTERN int DefaultNotify; /* default DSN notification flags */
+EXTERN int DelayLA; /* load average to delay connections */
+EXTERN int DontProbeInterfaces; /* don't probe interfaces for names */
EXTERN int Errors; /* set if errors (local to single pass) */
EXTERN int ExitStat; /* exit status code */
+EXTERN int FastSplit; /* fast initial splitting of envelopes */
EXTERN int FileMode; /* mode on files */
EXTERN int LineNumber; /* line number in current input */
EXTERN int LogLevel; /* level of logging to perform */
@@ -1777,43 +2143,46 @@ EXTERN int MaxForwardEntries; /* maximum number of forward entries */
EXTERN int MaxHeadersLength; /* max length of headers */
EXTERN int MaxHopCount; /* max # of hops until bounce */
EXTERN int MaxMacroRecursion; /* maximum depth of macro recursion */
-EXTERN int MaxMciCache; /* maximum entries in MCI cache */
EXTERN int MaxMimeFieldLength; /* maximum MIME field length */
EXTERN int MaxMimeHeaderLength; /* maximum MIME header length */
-
-EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */
EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */
EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */
EXTERN int MimeMode; /* MIME processing mode */
EXTERN int NoRecipientAction;
-EXTERN int NumPriorities; /* pointer into Priorities */
-EXTERN u_short PrivacyFlags; /* privacy flags */
-#if _FFR_QUEUE_FILE_MODE
-EXTERN int QueueFileMode; /* mode on qf/tf/df files */
-#endif /* _FFR_QUEUE_FILE_MODE */
+
+#if SM_CONF_SHM
+EXTERN int Numfilesys; /* number of queue file systems */
+EXTERN int *PNumFileSys;
+# define NumFileSys (*PNumFileSys)
+# else /* SM_CONF_SHM */
+EXTERN int NumFileSys; /* number of queue file systems */
+# endif /* SM_CONF_SHM */
+
EXTERN int QueueLA; /* load average starting forced queueing */
-EXTERN int QueueSortOrder; /* queue sorting order algorithm */
-EXTERN int RefuseLA; /* load average refusing connections are */
+EXTERN int RefuseLA; /* load average refusing connections */
+EXTERN int SuperSafe; /* be extra careful, even if expensive */
EXTERN int VendorCode; /* vendor-specific operation enhancements */
EXTERN int Verbose; /* set if blow-by-blow desired */
EXTERN gid_t DefGid; /* default gid to run as */
EXTERN gid_t RealGid; /* real gid of caller */
EXTERN gid_t RunAsGid; /* GID to become for bulk of run */
+EXTERN gid_t EffGid; /* effective gid */
+#if SM_CONF_SHM
+EXTERN key_t ShmKey; /* shared memory key */
+#endif /* SM_CONF_SHM */
+EXTERN pid_t CurrentPid; /* current process id */
+EXTERN pid_t DaemonPid; /* process id of daemon */
EXTERN uid_t DefUid; /* default uid to run as */
EXTERN uid_t RealUid; /* real uid of caller */
EXTERN uid_t RunAsUid; /* UID to become for bulk of run */
EXTERN uid_t TrustedUid; /* uid of trusted user for files and startup */
-EXTERN size_t DataFileBufferSize; /* size of buffer for in-core df */
-EXTERN size_t XscriptFileBufferSize; /* size of buffer for in-core xf */
+EXTERN size_t DataFileBufferSize; /* size of buf for in-core data file */
+EXTERN time_t DeliverByMin; /* deliver by minimum time */
EXTERN time_t DialDelay; /* delay between dial-on-demand tries */
-EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */
-EXTERN time_t MciInfoTimeout; /* how long 'til we retry down hosts */
-EXTERN time_t MinQueueAge; /* min delivery interval */
-EXTERN time_t QueueIntvl; /* intervals between running the queue */
EXTERN time_t SafeAlias; /* interval to wait until @:@ in alias file */
EXTERN time_t ServiceCacheMaxAge; /* refresh interval for cache */
-EXTERN time_t ServiceCacheTime; /* time service switch was cached */
+EXTERN size_t XscriptFileBufferSize; /* size of buf for in-core transcript file */
EXTERN MODE_T OldUmask; /* umask when sendmail starts up */
EXTERN long MaxMessageSize; /* advertised max size we will accept */
EXTERN long MinBlocksFree; /* min # of blocks free on queue fs */
@@ -1821,26 +2190,6 @@ EXTERN long QueueFactor; /* slope of queue function */
EXTERN long WkClassFact; /* multiplier for message class -> priority */
EXTERN long WkRecipFact; /* multiplier for # of recipients -> priority */
EXTERN long WkTimeFact; /* priority offset each time this job is run */
-#if SASL
-EXTERN char *AuthMechanisms; /* AUTH mechanisms */
-EXTERN char *SASLInfo; /* file with AUTH info */
-#endif /* SASL */
-EXTERN int SASLOpts; /* options for SASL */
-#if STARTTLS
-EXTERN char *CACERTpath; /* path to CA certificates (dir. with hashes) */
-EXTERN char *CACERTfile; /* file with CA certificate */
-EXTERN char *SrvCERTfile; /* file with server certificate */
-EXTERN char *Srvkeyfile; /* file with server private key */
-EXTERN char *CltCERTfile; /* file with client certificate */
-EXTERN char *Cltkeyfile; /* file with client private key */
-EXTERN char *DHParams; /* file with DH parameters */
-EXTERN char *RandFile; /* source of random data */
-# if _FFR_TLS_1
-EXTERN char *DHParams5; /* file with DH parameters (512) */
-EXTERN char *CipherList; /* list of ciphers */
-# endif /* _FFR_TLS_1 */
-#endif /* STARTTLS */
-EXTERN char *ConfFile; /* location of configuration file [conf.c] */
EXTERN char *ControlSocketName; /* control socket filename [control.c] */
EXTERN char *CurHostName; /* current host we are dealing with */
EXTERN char *DeadLetterDrop; /* path to dead letter office */
@@ -1854,18 +2203,13 @@ EXTERN char *ForwardPath; /* path to search for .forward files */
EXTERN char *HelpFile; /* location of SMTP help file */
EXTERN char *HostStatDir; /* location of host status information */
EXTERN char *HostsFile; /* path to /etc/hosts file */
+extern char *Mbdb; /* mailbox database type */
EXTERN char *MustQuoteChars; /* quote these characters in phrases */
EXTERN char *MyHostName; /* name of this host for SMTP messages */
EXTERN char *OperatorChars; /* operators (old $o macro) */
EXTERN char *PidFile; /* location of proc id file [conf.c] */
EXTERN char *PostMasterCopy; /* address to get errs cc's */
EXTERN char *ProcTitlePrefix; /* process title prefix */
-EXTERN char *QueueDir; /* location of queue directory */
-#if _FFR_QUEUEDELAY
-EXTERN int QueueAlg; /* algorithm for queue delays */
-EXTERN time_t QueueInitDelay; /* initial queue delay */
-EXTERN time_t QueueMaxDelay; /* maximum queue delay */
-#endif /* _FFR_QUEUEDELAY */
EXTERN char *RealHostName; /* name of host we are talking to */
EXTERN char *RealUserName; /* real user name of caller */
EXTERN char *volatile RestartRequest;/* a sendmail restart has been requested */
@@ -1880,70 +2224,30 @@ EXTERN char *StatFile; /* location of statistics summary */
EXTERN char *TimeZoneSpec; /* override time zone specification */
EXTERN char *UdbSpec; /* user database source spec */
EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */
-EXTERN char **ExternalEnviron; /* input environment */
- /* saved user environment */
+EXTERN char **ExternalEnviron; /* saved user (input) environment */
EXTERN char **SaveArgv; /* argument vector for re-execing */
EXTERN BITMAP256 DontBlameSendmail; /* DontBlameSendmail bits */
-#if SFIO
-EXTERN Sfio_t *InChannel; /* input connection */
-EXTERN Sfio_t *OutChannel; /* output connection */
-#else /* SFIO */
-EXTERN FILE *InChannel; /* input connection */
-EXTERN FILE *OutChannel; /* output connection */
-#endif /* SFIO */
-EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */
-#ifdef HESIOD
+EXTERN SM_FILE_T *InChannel; /* input connection */
+EXTERN SM_FILE_T *OutChannel; /* output connection */
+EXTERN SM_FILE_T *TrafficLogFile; /* file in which to log all traffic */
+#if HESIOD
EXTERN void *HesiodContext;
#endif /* HESIOD */
EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
-EXTERN MAILER *LocalMailer; /* ptr to local mailer */
-EXTERN MAILER *ProgMailer; /* ptr to program mailer */
-EXTERN MAILER *FileMailer; /* ptr to *file* mailer */
-EXTERN MAILER *InclMailer; /* ptr to *include* mailer */
-EXTERN QUEUE_CHAR *QueueLimitRecipient; /* limit queue run to rcpt */
-EXTERN QUEUE_CHAR *QueueLimitSender; /* limit queue run to sender */
-EXTERN QUEUE_CHAR *QueueLimitId; /* limit queue run to id */
-EXTERN MAILER *Mailer[MAXMAILERS + 1];
-EXTERN struct rewrite *RewriteRules[MAXRWSETS];
EXTERN char *RuleSetNames[MAXRWSETS]; /* ruleset number to name */
EXTERN char *UserEnviron[MAXUSERENVIRON + 1];
-EXTERN struct priority Priorities[MAXPRIORITIES];
+EXTERN struct rewrite *RewriteRules[MAXRWSETS];
EXTERN struct termescape TermEscape; /* terminal escape codes */
EXTERN SOCKADDR ConnectOnlyTo; /* override connection address (for testing) */
EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */
-EXTERN jmp_buf TopFrame; /* branch-to-top-of-loop-on-error frame */
-EXTERN TIMERS Timers;
+extern const SM_EXC_TYPE_T EtypeQuickAbort; /* type of a QuickAbort exception */
+
+
/*
** Declarations of useful functions
*/
-#if SASL
-extern char *intersect __P((char *, char *));
-extern char *iteminlist __P((char *, char *, char *));
-extern int proxy_policy __P((void *, const char *, const char *, const char **, const char **));
-# if SASL > 10515
-extern int safesaslfile __P((void *, char *, int));
-# else /* SASL > 10515 */
-extern int safesaslfile __P((void *, char *));
-# endif /* SASL > 10515 */
-extern int sasl_decode64 __P((const char *, unsigned, char *, unsigned *));
-extern int sasl_encode64 __P((const char *, unsigned, char *, unsigned, unsigned *));
-#endif /* SASL */
-
-#if STARTTLS
-extern void apps_ssl_info_cb __P((SSL *, int , int));
-extern bool init_tls_library __P((void));
-extern bool inittls __P((SSL_CTX **, u_long, bool, char *, char *, char *, char *, char *));
-extern bool initclttls __P((void));
-extern bool initsrvtls __P((void));
-extern int tls_get_info __P((SSL *, ENVELOPE *, bool, char *, bool));
-extern int endtls __P((SSL *, char *));
-extern int endtlsclt __P((MCI *));
-extern void tlslogerr __P((void));
-extern bool tls_rand_init __P((char *, int));
-#endif /* STARTTLS */
-
/* Transcript file */
extern void closexscript __P((ENVELOPE *));
extern void openxscript __P((ENVELOPE *));
@@ -1951,11 +2255,11 @@ extern void openxscript __P((ENVELOPE *));
/* error related */
extern void buffer_errors __P((void));
extern void flush_errors __P((bool));
-extern void message __P((const char *, ...));
-extern void nmessage __P((const char *, ...));
-extern void syserr __P((const char *, ...));
-extern void usrerrenh __P((char *, const char *, ...));
-extern void usrerr __P((const char *, ...));
+extern void PRINTFLIKE(1, 2) message __P((const char *, ...));
+extern void PRINTFLIKE(1, 2) nmessage __P((const char *, ...));
+extern void PRINTFLIKE(1, 2) syserr __P((const char *, ...));
+extern void PRINTFLIKE(2, 3) usrerrenh __P((char *, const char *, ...));
+extern void PRINTFLIKE(1, 2) usrerr __P((const char *, ...));
extern int isenhsc __P((const char *, int));
extern int extenhsc __P((const char *, int, char *));
@@ -1963,23 +2267,23 @@ extern int extenhsc __P((const char *, int, char *));
extern void alias __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
extern bool aliaswait __P((MAP *, char *, bool));
extern void forward __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern void readaliases __P((MAP *, FILE *, bool, bool));
+extern void readaliases __P((MAP *, SM_FILE_T *, bool, bool));
extern bool rebuildaliases __P((MAP *, bool));
extern void setalias __P((char *));
/* logging */
extern void logdelivery __P((MAILER *, MCI *, char *, const char *, ADDRESS *, time_t, ENVELOPE *));
extern void logsender __P((ENVELOPE *, char *));
-extern void sm_syslog __P((int, const char *, const char *, ...));
+extern void PRINTFLIKE(3, 4) sm_syslog __P((int, const char *, const char *, ...));
/* SMTP */
-extern void giveresponse __P((int, char *, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *));
+extern void giveresponse __P((int, char *, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *, ADDRESS *));
extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)(), char **));
extern void smtp __P((char *volatile, BITMAP256, ENVELOPE *volatile));
#if SASL
extern int smtpauth __P((MAILER *, MCI *, ENVELOPE *));
#endif /* SASL */
-extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *));
+extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *, ADDRESS *, time_t));
extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *));
extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *));
extern void smtpmessage __P((char *, MAILER *, MCI *, ...));
@@ -1987,7 +2291,7 @@ extern void smtpinit __P((MAILER *, MCI *, ENVELOPE *, bool));
extern char *smtptodsn __P((int));
extern int smtpprobe __P((MCI *));
extern void smtpquit __P((MAILER *, MCI *, ENVELOPE *));
-extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
+extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *, ADDRESS *, time_t));
extern void smtprset __P((MAILER *, MCI *, ENVELOPE *));
#define ISSMTPCODE(c) (isascii(c[0]) && isdigit(c[0]) && \
@@ -1997,13 +2301,20 @@ extern void smtprset __P((MAILER *, MCI *, ENVELOPE *));
(c[3] == ' ' || c[3] == '-' || c[3] == '\0'))
/* delivery */
-extern pid_t dowork __P((int, char *, bool, bool, ENVELOPE *));
+extern pid_t dowork __P((int, int, char *, bool, bool, ENVELOPE *));
+extern pid_t doworklist __P((ENVELOPE *, bool, bool));
extern int endmailer __P((MCI *, ENVELOPE *, char **));
extern int mailfile __P((char *volatile, MAILER *volatile, ADDRESS *, volatile long, ENVELOPE *));
extern void sendall __P((ENVELOPE *, int));
/* stats */
-extern void markstats __P((ENVELOPE *, ADDRESS *, bool));
+#define STATS_NORMAL 'n'
+#if _FFR_QUARANTINE
+# define STATS_QUARANTINE 'q'
+#endif /* _FFR_QUARANTINE */
+#define STATS_REJECT 'r'
+
+extern void markstats __P((ENVELOPE *, ADDRESS *, int));
extern void clearstats __P((void));
extern void poststats __P((char *));
@@ -2013,13 +2324,13 @@ extern void clrcontrol __P((void));
extern void control_command __P((int, ENVELOPE *));
extern int opencontrolsocket __P((void));
-#if _FFR_MILTER
+#if MILTER
/* milter functions */
-extern void milter_parse_list __P((char *, struct milter **, int));
+extern void milter_config __P((char *, struct milter **, int));
extern void milter_setup __P((char *));
extern void milter_set_option __P((char *, char *, bool));
extern bool milter_can_delrcpts __P((void));
-extern void milter_init __P((ENVELOPE *, char *));
+extern bool milter_init __P((ENVELOPE *, char *));
extern void milter_quit __P((ENVELOPE *));
extern void milter_abort __P((ENVELOPE *));
extern char *milter_connect __P((char *, SOCKADDR, ENVELOPE *, char *));
@@ -2027,10 +2338,9 @@ extern char *milter_helo __P((char *, ENVELOPE *, char *));
extern char *milter_envfrom __P((char **, ENVELOPE *, char *));
extern char *milter_envrcpt __P((char **, ENVELOPE *, char *));
extern char *milter_data __P((ENVELOPE *, char *));
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
-extern char *addquotes __P((char *));
-extern void allsignals __P((bool));
+extern char *addquotes __P((char *, SM_RPOOL_T *));
extern char *arpadate __P((char *));
extern bool atobool __P((char *));
extern int atooct __P((char *));
@@ -2038,7 +2348,10 @@ extern void auth_warning __P((ENVELOPE *, const char *, ...));
extern int blocksignal __P((int));
extern bool bitintersect __P((BITMAP256, BITMAP256));
extern bool bitzerop __P((BITMAP256));
+extern int check_bodytype __P((char *));
extern void buildfname __P((char *, char *, char *, int));
+extern bool chkclientmodifiers __P((int));
+extern bool chkdaemonmodifiers __P((int));
extern int checkcompat __P((ADDRESS *, ENVELOPE *));
#ifdef XDEBUG
extern void checkfd012 __P((char *));
@@ -2047,40 +2360,45 @@ extern void checkfdopen __P((int, char *));
extern void checkfds __P((char *));
extern bool chownsafe __P((int, bool));
extern void cleanstrcpy __P((char *, char *, int));
+#if SM_CONF_SHM
+extern void cleanup_shm __P((bool));
+#endif /* SM_CONF_SHM */
extern void clrdaemon __P((void));
-extern void collect __P((FILE *, bool, HDR **, ENVELOPE *));
+extern void collect __P((SM_FILE_T *, bool, HDR **, ENVELOPE *));
extern time_t convtime __P((char *, int));
-extern char **copyplist __P((char **, bool));
+extern char **copyplist __P((char **, bool, SM_RPOOL_T *));
extern void copy_class __P((int, int));
extern time_t curtime __P((void));
extern char *defcharset __P((ENVELOPE *));
extern char *denlstring __P((char *, bool, bool));
extern void disconnect __P((int, ENVELOPE *));
-extern bool dns_getcanonname __P((char *, int, bool, int *));
+#if _FFR_CONTROL_MSTAT
+extern void disk_status __P((SM_FILE_T *, char *));
+#endif /* _FFR_CONTROL_MSTAT */
+extern bool dns_getcanonname __P((char *, int, bool, int *, int *));
extern pid_t dofork __P((void));
extern int drop_privileges __P((bool));
extern int dsntoexitstat __P((char *));
extern void dumpfd __P((int, bool, bool));
extern void dumpstate __P((char *));
-extern bool enoughdiskspace __P((long, bool));
+extern bool enoughdiskspace __P((long, ENVELOPE *));
extern char *exitstat __P((char *));
-extern char *fgetfolded __P((char *, int, FILE *));
+extern void fatal_error __P((SM_EXC_T *));
+extern char *fgetfolded __P((char *, int, SM_FILE_T *));
extern void fill_fd __P((int, char *));
extern char *find_character __P((char *, int));
-extern struct passwd *finduser __P((char *, bool *));
-extern void finis __P((bool, volatile int));
+extern int finduser __P((char *, bool *, SM_MBDB_T *));
+extern void finis __P((bool, bool, volatile int));
extern void fixcrlf __P((char *, bool));
extern long freediskspace __P((char *, long *));
#if NETINET6 && NEEDSGETIPNODE
-# if _FFR_FREEHOSTENT
extern void freehostent __P((struct hostent *));
-# endif /* _FFR_FREEHOSTENT */
-#endif /* NEEDSGETIPNODE && NETINET6 */
+#endif /* NETINET6 && NEEDSGETIPNODE */
extern char *get_column __P((char *, int, int, char *, int));
extern char *getauthinfo __P((int, bool *));
-extern char *getcfname __P((void));
-extern char *getextenv __P((const char *));
extern int getdtsize __P((void));
+extern int getla __P((void));
+extern char *getmodifiers __P((char *, BITMAP256));
extern BITMAP256 *getrequests __P((ENVELOPE *));
extern char *getvendor __P((int));
extern void help __P((char *, ENVELOPE *));
@@ -2095,31 +2413,37 @@ extern bool isloopback __P((SOCKADDR sa));
extern void load_if_names __P((void));
extern bool lockfile __P((int, char *, char *, int));
extern void log_sendmail_pid __P((ENVELOPE *));
+extern void logundelrcpts __P((ENVELOPE *, char *, int, bool));
extern char lower __P((int));
extern void makelower __P((char *));
extern int makeconnection_ds __P((char *, MCI *));
-extern int makeconnection __P((char *, volatile u_int, MCI *, ENVELOPE *));
+extern int makeconnection __P((char *, volatile unsigned int, MCI *, ENVELOPE *, time_t));
+extern void makeworkgroups __P((void));
+extern void mark_work_group_restart __P((int, int));
extern char * munchstring __P((char *, char **, int));
extern struct hostent *myhostname __P((char *, int));
extern char *nisplus_default_domain __P((void)); /* extern for Sun */
extern bool path_is_dir __P((char *, bool));
+extern int pickqdir __P((QUEUEGRP *qg, long fsize, ENVELOPE *e));
extern char *pintvl __P((time_t, bool));
extern void printav __P((char **));
extern void printmailer __P((MAILER *));
+extern void printnqe __P((SM_FILE_T *, char *));
extern void printopenfds __P((bool));
extern void printqueue __P((void));
extern void printrules __P((void));
extern pid_t prog_open __P((char **, int *, ENVELOPE *));
extern void putline __P((char *, MCI *));
extern void putxline __P((char *, size_t, MCI *, int));
-extern void queueup_macros __P((int, FILE *, ENVELOPE *));
+extern void queueup_macros __P((int, SM_FILE_T *, ENVELOPE *));
extern void readcf __P((char *, bool, ENVELOPE *));
extern SIGFUNC_DECL reapchild __P((int));
extern int releasesignal __P((int));
extern void resetlimits __P((void));
+extern void restart_daemon __P((void));
+extern void restart_marked_work_groups __P(());
extern bool rfc822_string __P((char *));
-extern FILE *safefopen __P((char *, int, int, long));
-extern void savemail __P((ENVELOPE *, bool));
+extern bool savemail __P((ENVELOPE *, bool));
extern void seed_random __P((void));
extern void sendtoargv __P((char **, ENVELOPE *));
extern void setclientoptions __P((char *));
@@ -2127,49 +2451,66 @@ extern bool setdaemonoptions __P((char *));
extern void setdefaults __P((ENVELOPE *));
extern void setdefuser __P((void));
extern bool setvendor __P((char *));
+extern void set_op_mode __P((int));
extern void setoption __P((int, char *, bool, bool, ENVELOPE *));
extern sigfunc_t setsignal __P((int, sigfunc_t));
extern void setuserenv __P((const char *, const char *));
extern void settime __P((ENVELOPE *));
-extern char *sfgets __P((char *, int, FILE *, time_t, char *));
-extern char *shortenstring __P((const char *, int));
+extern char *sfgets __P((char *, int, SM_FILE_T *, time_t, char *));
+extern char *shortenstring __P((const char *, size_t));
extern char *shorten_hostname __P((char []));
extern bool shorten_rfc822_string __P((char *, size_t));
extern void shutdown_daemon __P((void));
-extern void sm_dopr __P((char *, const char *, va_list));
-extern void sm_free __P((void *));
extern struct hostent *sm_gethostbyname __P((char *, int));
extern struct hostent *sm_gethostbyaddr __P((char *, int, int));
-extern int sm_getla __P((ENVELOPE *));
+extern void sm_getla __P((void));
extern struct passwd *sm_getpwnam __P((char *));
extern struct passwd *sm_getpwuid __P((UID_T));
extern void sm_setproctitle __P((bool, ENVELOPE *, const char *, ...));
-extern SIGFUNC_DECL sm_signal_noop __P((int));
-extern int sm_strcasecmp __P((const char *, const char *));
+extern pid_t sm_wait __P((int *));
+extern bool split_by_recipient __P((ENVELOPE *e));
extern void stop_sendmail __P((void));
-extern bool strcontainedin __P((char *, char *));
-extern void stripquotes __P((char *));
+extern char *str2prt __P((char *));
+extern bool strcontainedin __P((bool, char *, char *));
extern int switch_map_find __P((char *, char *[], short []));
extern bool transienterror __P((int));
+#if _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI
+extern void truncate_at_delim __P((char *, size_t, int));
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI */
extern void tTflag __P((char *));
-extern void tTsetup __P((u_char *, int, char *));
+extern void tTsetup __P((unsigned char *, unsigned int, char *));
+extern SIGFUNC_DECL tick __P((int));
extern char *ttypath __P((void));
extern void unlockqueue __P((ENVELOPE *));
#if !HASUNSETENV
extern void unsetenv __P((char *));
#endif /* !HASUNSETENV */
+
+/* update file system information: +/- some blocks */
+#if SM_CONF_SHM
+extern void upd_qs __P((ENVELOPE *, bool, bool));
+# define updfs(e, delete, avail) upd_qs(e, delete, avail)
+#else /* SM_CONF_SHM */
+# define updfs(e, delete, avail)
+#endif /* SM_CONF_SHM */
+
extern char *username __P((void));
extern bool usershellok __P((char *, char *));
extern void vendor_post_defaults __P((ENVELOPE *));
extern void vendor_pre_defaults __P((ENVELOPE *));
extern int waitfor __P((pid_t));
extern bool writable __P((char *, ADDRESS *, long));
-extern char *xalloc __P((int));
-extern char *xcalloc __P((size_t, size_t));
-extern char *xrealloc __P((void *, size_t));
+#if SM_HEAP_CHECK
+# define xalloc(size) xalloc_tagged(size, __FILE__, __LINE__)
+extern char *xalloc_tagged __P((int, char*, int));
+#else /* SM_HEAP_CHECK */
+extern char *xalloc __P((int));
+#endif /* SM_HEAP_CHECK */
extern void xputs __P((const char *));
extern char *xtextify __P((char *, char *));
extern bool xtextok __P((char *));
-extern void xunlink __P((char *));
+extern int xunlink __P((char *));
extern char *xuntextify __P((char *));
-#endif /* _SENDMAIL_H */
+
+
+#endif /* ! _SENDMAIL_H */
diff --git a/contrib/sendmail/src/sfsasl.c b/contrib/sendmail/src/sfsasl.c
index 8ac3428..c6f63fb 100644
--- a/contrib/sendmail/src/sfsasl.c
+++ b/contrib/sendmail/src/sfsasl.c
@@ -8,40 +8,179 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: sfsasl.c,v 8.17.4.15 2001/07/11 17:37:07 gshapiro Exp $";
-#endif /* ! lint */
-
-#if SFIO
-# include <sfio/stdio.h>
-#endif /* SFIO */
-
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: sfsasl.c,v 8.86 2001/09/11 04:05:16 gshapiro Exp $")
#include <stdlib.h>
#include <sendmail.h>
+#include <errno.h>
+#if SASL
+# include <sasl.h>
+# include "sfsasl.h"
+
+/* Structure used by the "sasl" file type */
+struct sasl_obj
+{
+ SM_FILE_T *fp;
+ sasl_conn_t *conn;
+};
+
+struct sasl_info
+{
+ SM_FILE_T *fp;
+ sasl_conn_t *conn;
+};
-#if SASL && SFIO
/*
-** SASL
+** SASL_GETINFO - returns requested information about a "sasl" file
+** descriptor.
+**
+** Parameters:
+** fp -- the file descriptor
+** what -- the type of information requested
+** valp -- the thang to return the information in
+**
+** Returns:
+** -1 for unknown requests
+** >=0 on success with valp filled in (if possible).
*/
-# include <sasl.h>
-# include "sfsasl.h"
+static int sasl_getinfo __P((SM_FILE_T *, int, void *));
+
+static int
+sasl_getinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
+
+ switch (what)
+ {
+ case SM_IO_WHAT_FD:
+ if (so->fp == NULL)
+ return -1;
+ return so->fp->f_file; /* for stdio fileno() compatability */
+
+ case SM_IO_IS_READABLE:
+ if (so->fp == NULL)
+ return 0;
+
+ /* get info from underlying file */
+ return sm_io_getinfo(so->fp, what, valp);
+
+ default:
+ return -1;
+ }
+}
+
+/*
+** SASL_OPEN -- creates the sasl specific information for opening a
+** file of the sasl type.
+**
+** Parameters:
+** fp -- the file pointer associated with the new open
+** info -- contains the sasl connection information pointer and
+** the original SM_FILE_T that holds the open
+** flags -- ignored
+** rpool -- ignored
+**
+** Returns:
+** 0 on success
+*/
+
+static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
+
+/* ARGSUSED2 */
+static int
+sasl_open(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ struct sasl_obj *so;
+ struct sasl_info *si = (struct sasl_info *) info;
+
+ so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
+ so->fp = si->fp;
+ so->conn = si->conn;
+
+ /*
+ ** The underlying 'fp' is set to SM_IO_NOW so that the entire
+ ** encoded string is written in one chunk. Otherwise there is
+ ** the possibility that it may appear illegal, bogus or
+ ** mangled to the other side of the connection.
+ ** We will read or write through 'fp' since it is the opaque
+ ** connection for the communications. We need to treat it this
+ ** way in case the encoded string is to be sent down a TLS
+ ** connection rather than, say, sm_io's stdio.
+ */
+
+ (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
+ fp->f_cookie = so;
+ return 0;
+}
+
+/*
+** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
+**
+** Parameters:
+** fp -- the file pointer to close
+**
+** Returns:
+** 0 on success
+*/
+
+static int sasl_close __P((SM_FILE_T *));
+
+static int
+sasl_close(fp)
+ SM_FILE_T *fp;
+{
+ struct sasl_obj *so;
+
+ so = (struct sasl_obj *) fp->f_cookie;
+ if (so->fp != NULL)
+ {
+ sm_io_close(so->fp, SM_TIME_DEFAULT);
+ so->fp = NULL;
+ }
+ sm_free(so);
+ so = NULL;
+ return 0;
+}
/* how to deallocate a buffer allocated by SASL */
-# define SASL_DEALLOC(b) sm_free(b)
+extern void sm_sasl_free __P((void *));
+# define SASL_DEALLOC(b) sm_sasl_free(b)
+
+/*
+** SASL_READ -- read encrypted information and decrypt it for the caller
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- the location to place the decrypted information
+** size -- the number of bytes to read after decryption
+**
+** Results:
+** -1 on error
+** otherwise the number of bytes read
+*/
+
+static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
static ssize_t
-sasl_read(f, buf, size, disc)
- Sfio_t *f;
- Void_t *buf;
+sasl_read(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
size_t size;
- Sfdisc_t *disc;
{
- int len, result;
+ int result;
+ ssize_t len;
static char *outbuf = NULL;
static unsigned int outlen = 0;
static unsigned int offset = 0;
- Sasldisc_t *sd = (Sasldisc_t *) disc;
+ struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
/*
** sasl_decode() may require more data than a single read() returns.
@@ -54,10 +193,11 @@ sasl_read(f, buf, size, disc)
while (outbuf == NULL && outlen == 0)
{
- len = sfrd(f, buf, size, disc);
+ len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
if (len <= 0)
return len;
- result = sasl_decode(sd->conn, buf, len, &outbuf, &outlen);
+ result = sasl_decode(so->conn, buf,
+ (unsigned int) len, &outbuf, &outlen);
if (result != SASL_OK)
{
outbuf = NULL;
@@ -67,66 +207,108 @@ sasl_read(f, buf, size, disc)
}
}
- if (outbuf != NULL)
+ if (outbuf == NULL)
{
- if (outlen - offset > size)
- {
- /* return another part of the buffer */
- (void) memcpy(buf, outbuf + offset, (size_t) size);
- offset += size;
- result = size;
- }
- else
- {
- /* return the rest of the buffer */
- result = outlen - offset;
- (void) memcpy(buf, outbuf + offset, (size_t) result);
- SASL_DEALLOC(outbuf);
- outbuf = NULL;
- offset = 0;
- outlen = 0;
- }
+ /* be paranoid: outbuf == NULL but outlen != 0 */
+ syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
+ /* NOTREACHED */
+ }
+ if (outlen - offset > size)
+ {
+ /* return another part of the buffer */
+ (void) memcpy(buf, outbuf + offset, size);
+ offset += size;
+ len = size;
}
else
{
- /* be paranoid: outbuf == NULL but outlen != 0 */
- syserr("!sasl_read failure: outbuf == NULL but outlen != 0");
+ /* return the rest of the buffer */
+ len = outlen - offset;
+ (void) memcpy(buf, outbuf + offset, (size_t) len);
+ SASL_DEALLOC(outbuf);
+ outbuf = NULL;
+ offset = 0;
+ outlen = 0;
}
- return result;
+ return len;
}
+/*
+** SASL_WRITE -- write information out after encrypting it
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- holds the data to be encrypted and written
+** size -- the number of bytes to have encrypted and written
+**
+** Returns:
+** -1 on error
+** otherwise number of bytes written
+*/
+
+static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
+
static ssize_t
-sasl_write(f, buf, size, disc)
- Sfio_t *f;
- const Void_t *buf;
+sasl_write(fp, buf, size)
+ SM_FILE_T *fp;
+ const char *buf;
size_t size;
- Sfdisc_t *disc;
{
int result;
char *outbuf;
unsigned int outlen;
- Sasldisc_t *sd = (Sasldisc_t *) disc;
+ size_t ret = 0, total = 0;
+ struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
- result = sasl_encode(sd->conn, buf, size, &outbuf, &outlen);
+ result = sasl_encode(so->conn, buf,
+ (unsigned int) size, &outbuf, &outlen);
if (result != SASL_OK)
return -1;
if (outbuf != NULL)
{
- sfwr(f, outbuf, outlen, disc);
+ while (outlen > 0)
+ {
+ ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
+ &outbuf[total], outlen);
+ outlen -= ret;
+ total += ret;
+ }
SASL_DEALLOC(outbuf);
}
return size;
}
+/*
+** SFDCSASL -- create sasl file type and open in and out file pointers
+** for sendmail to read from and write to.
+**
+** Parameters:
+** fin -- the sm_io file encrypted data to be read from
+** fout -- the sm_io file encrypted data to be writen to
+** conn -- the sasl connection pointer
+**
+** Returns:
+** -1 on error
+** 0 on success
+**
+** Side effects:
+** The arguments "fin" and "fout" are replaced with the new
+** SM_FILE_T pointers.
+*/
+
int
sfdcsasl(fin, fout, conn)
- Sfio_t *fin;
- Sfio_t *fout;
+ SM_FILE_T **fin;
+ SM_FILE_T **fout;
sasl_conn_t *conn;
{
- Sasldisc_t *saslin, *saslout;
+ SM_FILE_T *newin, *newout;
+ SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
+ sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
+ SM_TIME_FOREVER);
+ struct sasl_info info;
if (conn == NULL)
{
@@ -134,265 +316,392 @@ sfdcsasl(fin, fout, conn)
return 0;
}
- saslin = (Sasldisc_t *) xalloc(sizeof(Sasldisc_t));
- saslout = (Sasldisc_t *) xalloc(sizeof(Sasldisc_t));
- saslin->disc.readf = sasl_read;
- saslin->disc.writef = sasl_write;
- saslin->disc.seekf = NULL;
- saslin->disc.exceptf = NULL;
+ SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
+ sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
+ SM_TIME_FOREVER);
+ info.fp = *fin;
+ info.conn = conn;
+ newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
+ NULL);
- saslout->disc.readf = sasl_read;
- saslout->disc.writef = sasl_write;
- saslout->disc.seekf = NULL;
- saslout->disc.exceptf = NULL;
+ if (newin == NULL)
+ return -1;
- saslin->conn = conn;
- saslout->conn = conn;
+ info.fp = *fout;
+ info.conn = conn;
+ newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
+ NULL);
- if (sfdisc(fin, (Sfdisc_t *) saslin) != (Sfdisc_t *) saslin ||
- sfdisc(fout, (Sfdisc_t *) saslout) != (Sfdisc_t *) saslout)
+ if (newout == NULL)
{
- sm_free(saslin);
- sm_free(saslout);
+ (void) sm_io_close(newin, SM_TIME_DEFAULT);
return -1;
}
+ sm_io_automode(newin, newout);
+
+ *fin = newin;
+ *fout = newout;
return 0;
}
-#endif /* SASL && SFIO */
+#endif /* SASL */
+
+#if STARTTLS
+# include "sfsasl.h"
+# include <openssl/err.h>
+
+/* Structure used by the "tls" file type */
+struct tls_obj
+{
+ SM_FILE_T *fp;
+ SSL *con;
+};
+
+struct tls_info
+{
+ SM_FILE_T *fp;
+ SSL *con;
+};
-#if STARTTLS && (SFIO || _FFR_TLS_TOREK)
/*
-** STARTTLS
+** TLS_GETINFO - returns requested information about a "tls" file
+** descriptor.
+**
+** Parameters:
+** fp -- the file descriptor
+** what -- the type of information requested
+** valp -- the thang to return the information in (unused)
+**
+** Returns:
+** -1 for unknown requests
+** >=0 on success with valp filled in (if possible).
*/
-# include "sfsasl.h"
-# include <openssl/err.h>
+static int tls_getinfo __P((SM_FILE_T *, int, void *));
-# if SFIO
-static ssize_t
-tls_read(f, buf, size, disc)
- Sfio_t *f;
- Void_t *buf;
- size_t size;
- Sfdisc_t *disc;
-# else /* SFIO */
+/* ARGSUSED2 */
static int
-tls_read(disc, buf, size)
- void *disc;
- char *buf;
- int size;
-# endif /* SFIO */
+tls_getinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
{
- int r;
- Tlsdisc_t *sd;
+ struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
- /* Cast back to correct type */
- sd = (Tlsdisc_t *) disc;
-
- r = SSL_read(sd->con, (char *) buf, size);
- if (r < 0 && LogLevel > 7)
+ switch (what)
{
- char *err;
+ case SM_IO_WHAT_FD:
+ if (so->fp == NULL)
+ return -1;
+ return so->fp->f_file; /* for stdio fileno() compatability */
+
+ case SM_IO_IS_READABLE:
+ return SSL_pending(so->con) > 0;
+
+ default:
+ return -1;
+ }
+}
- err = NULL;
- switch (SSL_get_error(sd->con, r))
- {
- case SSL_ERROR_NONE:
- break;
- case SSL_ERROR_WANT_WRITE:
- err = "write W BLOCK";
- break;
- case SSL_ERROR_WANT_READ:
- err = "write R BLOCK";
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- err = "write X BLOCK";
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- case SSL_ERROR_SYSCALL:
- err = "syscall error";
/*
- get_last_socket_error());
+** TLS_OPEN -- creates the tls specific information for opening a
+** file of the tls type.
+**
+** Parameters:
+** fp -- the file pointer associated with the new open
+** info -- the sm_io file pointer holding the open and the
+** TLS encryption connection to be read from or written to
+** flags -- ignored
+** rpool -- ignored
+**
+** Returns:
+** 0 on success
*/
- break;
- case SSL_ERROR_SSL:
- err = "generic SSL error";
- break;
- }
- if (err != NULL)
- sm_syslog(LOG_WARNING, NOQID, "TLS: read error: %s",
- err);
+
+static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
+
+/* ARGSUSED2 */
+static int
+tls_open(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ struct tls_obj *so;
+ struct tls_info *ti = (struct tls_info *) info;
+
+ so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
+ so->fp = ti->fp;
+ so->con = ti->con;
+
+ /*
+ ** We try to get the "raw" file descriptor that TLS uses to
+ ** do the actual read/write with. This is to allow us control
+ ** over the file descriptor being a blocking or non-blocking type.
+ ** Under the covers TLS handles the change and this allows us
+ ** to do timeouts with sm_io.
+ */
+
+ fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
+ (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
+ fp->f_cookie = so;
+ return 0;
+}
+
+/*
+** TLS_CLOSE -- close the tls specific parts of the tls file pointer
+**
+** Parameters:
+** fp -- the file pointer to close
+**
+** Returns:
+** 0 on success
+*/
+
+static int tls_close __P((SM_FILE_T *));
+
+static int
+tls_close(fp)
+ SM_FILE_T *fp;
+{
+ struct tls_obj *so;
+
+ so = (struct tls_obj *) fp->f_cookie;
+ if (so->fp != NULL)
+ {
+ sm_io_close(so->fp, SM_TIME_DEFAULT);
+ so->fp = NULL;
}
- return r;
+ sm_free(so);
+ so = NULL;
+ return 0;
}
-# if SFIO
+/* maximum number of retries for TLS related I/O due to handshakes */
+# define MAX_TLS_IOS 4
+
+/*
+** TLS_READ -- read secured information for the caller
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- the location to place the data
+** size -- the number of bytes to read from connection
+**
+** Results:
+** -1 on error
+** otherwise the number of bytes read
+*/
+
+static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
+
static ssize_t
-tls_write(f, buf, size, disc)
- Sfio_t *f;
- const Void_t *buf;
+tls_read(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
size_t size;
- Sfdisc_t *disc;
-# else /* SFIO */
-static int
-tls_write(disc, buf, size)
- void *disc;
- const char *buf;
- int size;
-# endif /* SFIO */
{
int r;
- Tlsdisc_t *sd;
+ static int again = MAX_TLS_IOS;
+ struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
+ char *err;
- /* Cast back to correct type */
- sd = (Tlsdisc_t *) disc;
+ r = SSL_read(so->con, (char *) buf, size);
- r = SSL_write(sd->con, (char *)buf, size);
- if (r < 0 && LogLevel > 7)
+ if (r > 0)
{
- char *err;
+ again = MAX_TLS_IOS;
+ return r;
+ }
- err = NULL;
- switch (SSL_get_error(sd->con, r))
- {
- case SSL_ERROR_NONE:
- break;
- case SSL_ERROR_WANT_WRITE:
- err = "write W BLOCK";
- break;
- case SSL_ERROR_WANT_READ:
- err = "write R BLOCK";
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- err = "write X BLOCK";
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- case SSL_ERROR_SYSCALL:
- err = "syscall error";
-/*
- get_last_socket_error());
-*/
- break;
- case SSL_ERROR_SSL:
- err = "generic SSL error";
+ err = NULL;
+ switch (SSL_get_error(so->con, r))
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_ZERO_RETURN:
+ again = MAX_TLS_IOS;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ if (--again <= 0)
+ err = "read W BLOCK";
+ else
+ errno = EAGAIN;
+ break;
+ case SSL_ERROR_WANT_READ:
+ if (--again <= 0)
+ err = "read R BLOCK";
+ else
+ errno = EAGAIN;
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ err = "write X BLOCK";
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (r == 0 && errno == 0) /* out of protocol EOF found */
+ break;
+ err = "syscall error";
/*
- ERR_GET_REASON(ERR_peek_error()));
+ get_last_socket_error());
*/
- break;
- }
- if (err != NULL)
- sm_syslog(LOG_WARNING, NOQID, "TLS: write error: %s",
- err);
+ break;
+ case SSL_ERROR_SSL:
+ err = "generic SSL error";
+ if (LogLevel > 9)
+ tlslogerr("read");
+ break;
+ }
+ if (err != NULL)
+ {
+ again = MAX_TLS_IOS;
+ if (errno == 0)
+ errno = EIO;
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: read error=%s (%d)", err, r);
}
return r;
}
-# if !SFIO
-static int
-tls_close(cookie)
- void *cookie;
+/*
+** TLS_WRITE -- write information out through secure connection
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- holds the data to be securely written
+** size -- the number of bytes to write
+**
+** Returns:
+** -1 on error
+** otherwise number of bytes written
+*/
+
+static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
+
+static ssize_t
+tls_write(fp, buf, size)
+ SM_FILE_T *fp;
+ const char *buf;
+ size_t size;
{
- int retval = 0;
- Tlsdisc_t *tc;
+ int r;
+ static int again = MAX_TLS_IOS;
+ struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
+ char *err;
- /* Cast back to correct type */
- tc = (Tlsdisc_t *)cookie;
+ r = SSL_write(so->con, (char *) buf, size);
- if (tc->fp != NULL)
+ if (r > 0)
{
- retval = fclose(tc->fp);
- tc->fp = NULL;
+ again = MAX_TLS_IOS;
+ return r;
}
-
- sm_free(tc);
- return retval;
+ err = NULL;
+ switch (SSL_get_error(so->con, r))
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_ZERO_RETURN:
+ again = MAX_TLS_IOS;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ if (--again <= 0)
+ err = "write W BLOCK";
+ else
+ errno = EAGAIN;
+ break;
+ case SSL_ERROR_WANT_READ:
+ if (--again <= 0)
+ err = "write R BLOCK";
+ else
+ errno = EAGAIN;
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ err = "write X BLOCK";
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (r == 0 && errno == 0) /* out of protocol EOF found */
+ break;
+ err = "syscall error";
+/*
+ get_last_socket_error());
+*/
+ break;
+ case SSL_ERROR_SSL:
+ err = "generic SSL error";
+/*
+ ERR_GET_REASON(ERR_peek_error()));
+*/
+ if (LogLevel > 9)
+ tlslogerr("write");
+ break;
+ }
+ if (err != NULL)
+ {
+ again = MAX_TLS_IOS;
+ if (errno == 0)
+ errno = EIO;
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: write error=%s (%d)", err, r);
+ }
+ return r;
}
-# endif /* !SFIO */
+
+/*
+** SFDCTLS -- create tls file type and open in and out file pointers
+** for sendmail to read from and write to.
+**
+** Parameters:
+** fin -- data input source being replaced
+** fout -- data output source being replaced
+** conn -- the tls connection pointer
+**
+** Returns:
+** -1 on error
+** 0 on success
+**
+** Side effects:
+** The arguments "fin" and "fout" are replaced with the new
+** SM_FILE_T pointers.
+** The original "fin" and "fout" are preserved in the tls file
+** type but are not actually used because of the design of TLS.
+*/
int
sfdctls(fin, fout, con)
-# if SFIO
- Sfio_t *fin;
- Sfio_t *fout;
-# else /* SFIO */
- FILE **fin;
- FILE **fout;
-# endif /* SFIO */
+ SM_FILE_T **fin;
+ SM_FILE_T **fout;
SSL *con;
{
- Tlsdisc_t *tlsin, *tlsout;
-# if !SFIO
- FILE *fp;
-# else /* !SFIO */
- int rfd, wfd;
-# endif /* !SFIO */
-
- if (con == NULL)
- return 0;
-
- tlsin = (Tlsdisc_t *) xalloc(sizeof(Tlsdisc_t));
- tlsout = (Tlsdisc_t *) xalloc(sizeof(Tlsdisc_t));
-# if SFIO
- tlsin->disc.readf = tls_read;
- tlsin->disc.writef = tls_write;
- tlsin->disc.seekf = NULL;
- tlsin->disc.exceptf = NULL;
- tlsin->con = con;
-
- tlsout->disc.readf = tls_read;
- tlsout->disc.writef = tls_write;
- tlsout->disc.seekf = NULL;
- tlsout->disc.exceptf = NULL;
- tlsout->con = con;
-
- rfd = fileno(fin);
- wfd = fileno(fout);
- if (rfd < 0 || wfd < 0 ||
- SSL_set_rfd(con, rfd) <= 0 || SSL_set_wfd(con, wfd) <= 0)
- {
- sm_free(tlsin);
- sm_free(tlsout);
- return -1;
- }
- if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin ||
- sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout)
- {
- sm_free(tlsin);
- sm_free(tlsout);
+ SM_FILE_T *tlsin, *tlsout;
+ SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
+ tls_read, tls_write, NULL, tls_getinfo, NULL,
+ SM_TIME_FOREVER);
+ struct tls_info info;
+
+ SM_ASSERT(con != NULL);
+
+ SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
+ tls_read, tls_write, NULL, tls_getinfo, NULL,
+ SM_TIME_FOREVER);
+ info.fp = *fin;
+ info.con = con;
+ tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
+ NULL);
+ if (tlsin == NULL)
return -1;
- }
-# else /* SFIO */
- tlsin->fp = *fin;
- tlsin->con = con;
- fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close);
- if (fp == NULL)
- {
- sm_free(tlsin);
- return -1;
- }
- *fin = fp;
- tlsout->fp = *fout;
- tlsout->con = con;
- fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close);
- if (fp == NULL)
+ info.fp = *fout;
+ tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
+ NULL);
+ if (tlsout == NULL)
{
- FILE *save;
-
- /* Hack: Don't close underlying fp */
- save = tlsin->fp;
- tlsin->fp = NULL;
- fclose(*fin);
- *fin = save;
- sm_free(tlsout);
+ (void) sm_io_close(tlsin, SM_TIME_DEFAULT);
return -1;
}
- *fout = fp;
- SSL_set_rfd(con, fileno(tlsin->fp));
- SSL_set_wfd(con, fileno(tlsout->fp));
-# endif /* SFIO */
+ sm_io_automode(tlsin, tlsout);
+
+ *fin = tlsin;
+ *fout = tlsout;
return 0;
}
-#endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */
+#endif /* STARTTLS */
diff --git a/contrib/sendmail/src/sfsasl.h b/contrib/sendmail/src/sfsasl.h
index b276e27..c75418a 100644
--- a/contrib/sendmail/src/sfsasl.h
+++ b/contrib/sendmail/src/sfsasl.h
@@ -6,55 +6,18 @@
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
- * $Id: sfsasl.h,v 8.13.4.4 2000/07/18 18:44:51 gshapiro Exp $"
+ * $Id: sfsasl.h,v 8.17 2000/09/19 21:30:49 ca Exp $"
*/
#ifndef SFSASL_H
# define SFSASL_H
-# if SFIO
-# include <sfio.h>
-# endif /* SFIO */
-
-# if SASL
-# if SFIO
-
-/* sf discipline to add sasl */
-typedef struct _sasldisc
-{
- Sfdisc_t disc;
- sasl_conn_t *conn;
-} Sasldisc_t;
-
-extern int sfdcsasl __P((Sfio_t *, Sfio_t *, sasl_conn_t *));
-
-# endif /* SFIO */
-# endif /* SASL */
+#if SASL
+extern int sfdcsasl __P((SM_FILE_T **, SM_FILE_T **, sasl_conn_t *));
+#endif /* SASL */
# if STARTTLS
-# if SFIO
-
-/* sf discipline to add tls */
-typedef struct _tlsdisc
-{
- Sfdisc_t disc;
- SSL *con;
-} Tlsdisc_t;
-
-extern int sfdctls __P((Sfio_t *, Sfio_t *, SSL *));
-
-# else /* SFIO */
-# if _FFR_TLS_TOREK
-
-typedef struct tls_conn
-{
- FILE *fp; /* original FILE * */
- SSL *con; /* SSL context */
-} Tlsdisc_t;
-
-extern int sfdctls __P((FILE **, FILE **, SSL *));
-
-# endif /* _FFR_TLS_TOREK */
-# endif /* SFIO */
+extern int sfdctls __P((SM_FILE_T **, SM_FILE_T **, SSL *));
# endif /* STARTTLS */
+
#endif /* ! SFSASL_H */
diff --git a/contrib/sendmail/src/shmticklib.c b/contrib/sendmail/src/shmticklib.c
index a3e1ad5..6f5e301 100644
--- a/contrib/sendmail/src/shmticklib.c
+++ b/contrib/sendmail/src/shmticklib.c
@@ -10,23 +10,17 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: shmticklib.c,v 8.6 2000/02/26 01:32:27 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: shmticklib.c,v 8.14 2001/09/11 04:05:16 gshapiro Exp $")
#if _FFR_SHM_STATUS
-# if SFIO
-# include <sfio/stdio.h>
-# else /* !SFIO */
-# include <stdio.h>
-# endif /* SFIO */
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/shm.h>
# include "statusd_shm.h"
- /*
+/*
** SHMTICK -- increment a shared memory variable
**
** Parameters:
@@ -54,10 +48,10 @@ shmtick(inc_me, what)
if (shmid < 0)
return;
}
- if ((unsigned long *)sp == (unsigned long *)-1)
+ if ((unsigned long *) sp == (unsigned long *)-1)
{
- sp = (STATUSD_SHM *)shmat(shmid, NULL, 0);
- if ((unsigned long *)sp == (unsigned long *)-1)
+ sp = (STATUSD_SHM *) shmat(shmid, NULL, 0);
+ if ((unsigned long *) sp == (unsigned long *) -1)
return;
}
if (sp->magic != STATUSD_MAGIC)
diff --git a/contrib/sendmail/src/sm_resolve.c b/contrib/sendmail/src/sm_resolve.c
new file mode 100644
index 0000000..e3eb77f
--- /dev/null
+++ b/contrib/sendmail/src/sm_resolve.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sendmail.h>
+#if DNSMAP
+# if NAMED_BIND
+# include "sm_resolve.h"
+
+SM_RCSID("$Id: sm_resolve.c,v 8.24 2001/09/11 04:05:16 gshapiro Exp $")
+
+static struct stot
+{
+ const char *st_name;
+ int st_type;
+} stot[] =
+{
+# if NETINET
+ { "A", T_A },
+# endif /* NETINET */
+# if NETINET6
+ { "AAAA", T_AAAA },
+# endif /* NETINET6 */
+ { "NS", T_NS },
+ { "CNAME", T_CNAME },
+ { "PTR", T_PTR },
+ { "MX", T_MX },
+ { "TXT", T_TXT },
+ { "AFSDB", T_AFSDB },
+ { "SRV", T_SRV },
+ { NULL, 0 }
+};
+
+/*
+** DNS_STRING_TO_TYPE -- convert resource record name into type
+**
+** Parameters:
+** name -- name of resource record type
+**
+** Returns:
+** type if succeeded.
+** -1 otherwise.
+*/
+
+int
+dns_string_to_type(name)
+ const char *name;
+{
+ struct stot *p = stot;
+
+ for (p = stot; p->st_name != NULL; p++)
+ if (sm_strcasecmp(name, p->st_name) == 0)
+ return p->st_type;
+ return -1;
+}
+
+/*
+** DNS_TYPE_TO_STRING -- convert resource record type into name
+**
+** Parameters:
+** type -- resource record type
+**
+** Returns:
+** name if succeeded.
+** NULL otherwise.
+*/
+
+const char *
+dns_type_to_string(type)
+ int type;
+{
+ struct stot *p = stot;
+
+ for (p = stot; p->st_name != NULL; p++)
+ if (type == p->st_type)
+ return p->st_name;
+ return NULL;
+}
+
+/*
+** DNS_FREE_DATA -- free all components of a DNS_REPLY_T
+**
+** Parameters:
+** r -- pointer to DNS_REPLY_T
+**
+** Returns:
+** none.
+*/
+
+void
+dns_free_data(r)
+ DNS_REPLY_T *r;
+{
+ RESOURCE_RECORD_T *rr;
+
+ if (r->dns_r_q.dns_q_domain != NULL)
+ sm_free(r->dns_r_q.dns_q_domain);
+ for (rr = r->dns_r_head; rr != NULL; )
+ {
+ RESOURCE_RECORD_T *tmp = rr;
+
+ if (rr->rr_domain != NULL)
+ sm_free(rr->rr_domain);
+ if (rr->rr_u.rr_data != NULL)
+ sm_free(rr->rr_u.rr_data);
+ rr = rr->rr_next;
+ sm_free(tmp);
+ }
+ sm_free(r);
+}
+
+/*
+** PARSE_DNS_REPLY -- parse DNS reply data.
+**
+** Parameters:
+** data -- pointer to dns data
+** len -- len of data
+**
+** Returns:
+** pointer to DNS_REPLY_T if succeeded.
+** NULL otherwise.
+*/
+
+static DNS_REPLY_T *
+parse_dns_reply(data, len)
+ unsigned char *data;
+ int len;
+{
+ unsigned char *p;
+ int status;
+ size_t l;
+ char host[MAXHOSTNAMELEN];
+ DNS_REPLY_T *r;
+ RESOURCE_RECORD_T **rr;
+
+ r = (DNS_REPLY_T *) xalloc(sizeof(*r));
+ memset(r, 0, sizeof(*r));
+ if (r == NULL)
+ return NULL;
+
+ p = data;
+
+ /* doesn't work on Crays? */
+ memcpy(&r->dns_r_h, p, sizeof(HEADER));
+ p += sizeof(HEADER);
+ status = dn_expand(data, data + len, p, host, sizeof host);
+ if (status < 0)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ r->dns_r_q.dns_q_domain = sm_strdup(host);
+ if (r->dns_r_q.dns_q_domain == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ p += status;
+ GETSHORT(r->dns_r_q.dns_q_type, p);
+ GETSHORT(r->dns_r_q.dns_q_class, p);
+ rr = &r->dns_r_head;
+ while (p < data + len)
+ {
+ int type, class, ttl, size;
+
+ status = dn_expand(data, data + len, p, host, sizeof host);
+ if (status < 0)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ p += status;
+ GETSHORT(type, p);
+ GETSHORT(class, p);
+ GETLONG(ttl, p);
+ GETSHORT(size, p);
+ *rr = (RESOURCE_RECORD_T *) xalloc(sizeof(RESOURCE_RECORD_T));
+ if (*rr == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (*rr)->rr_domain = sm_strdup(host);
+ if ((*rr)->rr_domain == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (*rr)->rr_type = type;
+ (*rr)->rr_class = class;
+ (*rr)->rr_ttl = ttl;
+ (*rr)->rr_size = size;
+ switch (type)
+ {
+ case T_NS:
+ case T_CNAME:
+ case T_PTR:
+ status = dn_expand(data, data + len, p, host,
+ sizeof host);
+ if (status < 0)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (*rr)->rr_u.rr_txt = sm_strdup(host);
+ if ((*rr)->rr_u.rr_txt == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ status = dn_expand(data, data + len, p + 2, host,
+ sizeof host);
+ if (status < 0)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ l = strlen(host) + 1;
+ (*rr)->rr_u.rr_mx = (MX_RECORD_T *)
+ xalloc(sizeof(MX_RECORD_T) + l);
+ if ((*rr)->rr_u.rr_mx == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
+ (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
+ host, l);
+ break;
+
+ case T_SRV:
+ status = dn_expand(data, data + len, p + 6, host,
+ sizeof host);
+ if (status < 0)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ l = strlen(host) + 1;
+ (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
+ xalloc(sizeof(SRV_RECORDT_T) + l);
+ if ((*rr)->rr_u.rr_srv == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
+ (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
+ (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
+ (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target,
+ host, l);
+ break;
+
+ case T_TXT:
+ (*rr)->rr_u.rr_txt = (char *) xalloc(size + 1);
+ if ((*rr)->rr_u.rr_txt == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (void) strncpy((*rr)->rr_u.rr_txt, (char*) p + 1, *p);
+ (*rr)->rr_u.rr_txt[*p] = 0;
+ break;
+
+ default:
+ (*rr)->rr_u.rr_data = (unsigned char*) xalloc(size);
+ if (size != 0 && (*rr)->rr_u.rr_data == NULL)
+ {
+ dns_free_data(r);
+ return NULL;
+ }
+ (void) memcpy((*rr)->rr_u.rr_data, p, size);
+ }
+ p += size;
+ rr = &(*rr)->rr_next;
+ }
+ *rr = NULL;
+ return r;
+}
+
+/*
+** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine)
+**
+** Parameters:
+** domain -- name to lookup
+** rr_class -- resource record class
+** rr_type -- resource record type
+** retrans -- retransmission timeout
+** retry -- number of retries
+**
+** Returns:
+** result of lookup if succeeded.
+** NULL otherwise.
+*/
+
+DNS_REPLY_T *
+dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
+ const char *domain;
+ int rr_class;
+ int rr_type;
+ time_t retrans;
+ int retry;
+{
+ int len;
+ unsigned long old_options = 0;
+ time_t save_retrans = 0;
+ int save_retry = 0;
+ DNS_REPLY_T *r = NULL;
+ unsigned char reply[1024];
+
+ if (tTd(8, 16))
+ {
+ old_options = _res.options;
+ _res.options |= RES_DEBUG;
+ sm_dprintf("dns_lookup(%s, %d, %s)\n", domain,
+ rr_class, dns_type_to_string(rr_type));
+ }
+ if (retrans > 0)
+ {
+ save_retrans = _res.retrans;
+ _res.retrans = retrans;
+ }
+ if (retry > 0)
+ {
+ save_retry = _res.retry;
+ _res.retry = retry;
+ }
+ errno = 0;
+ SM_SET_H_ERRNO(0);
+ len = res_search(domain, rr_class, rr_type, reply, sizeof reply);
+ if (tTd(8, 16))
+ {
+ _res.options = old_options;
+ sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
+ domain, rr_class, dns_type_to_string(rr_type), len);
+ }
+ if (len >= 0)
+ r = parse_dns_reply(reply, len);
+ if (retrans > 0)
+ _res.retrans = save_retrans;
+ if (retry > 0)
+ _res.retry = save_retry;
+ return r;
+}
+
+# if 0
+DNS_REPLY_T *
+dns_lookup(domain, type_name, retrans, retry)
+ const char *domain;
+ const char *type_name;
+ time_t retrans;
+ int retry;
+{
+ int type;
+
+ type = dns_string_to_type(type_name);
+ if (type == -1)
+ {
+ if (tTd(8, 16))
+ sm_dprintf("dns_lookup: unknown resource type: `%s'\n",
+ type_name);
+ return NULL;
+ }
+ return dns_lookup_int(domain, C_IN, type, retrans, retry);
+}
+# endif /* 0 */
+# endif /* NAMED_BIND */
+#endif /* DNSMAP */
diff --git a/contrib/sendmail/src/sm_resolve.h b/contrib/sendmail/src/sm_resolve.h
new file mode 100644
index 0000000..7f169ba
--- /dev/null
+++ b/contrib/sendmail/src/sm_resolve.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: sm_resolve.h,v 8.8 2001/09/01 00:06:02 gshapiro Exp $ */
+
+#if DNSMAP
+# ifndef __ROKEN_RESOLVE_H__
+# define __ROKEN_RESOLVE_H__
+
+/* We use these, but they are not always present in <arpa/nameser.h> */
+
+# ifndef T_TXT
+# define T_TXT 16
+# endif /* ! T_TXT */
+# ifndef T_AFSDB
+# define T_AFSDB 18
+# endif /* ! T_AFSDB */
+# ifndef T_SRV
+# define T_SRV 33
+# endif /* ! T_SRV */
+# ifndef T_NAPTR
+# define T_NAPTR 35
+# endif /* ! T_NAPTR */
+
+typedef struct
+{
+ char *dns_q_domain;
+ unsigned int dns_q_type;
+ unsigned int dns_q_class;
+} DNS_QUERY_T;
+
+typedef struct
+{
+ unsigned int mx_r_preference;
+ char mx_r_domain[1];
+} MX_RECORD_T;
+
+typedef struct
+{
+ unsigned int srv_r_priority;
+ unsigned int srv_r_weight;
+ unsigned int srv_r_port;
+ char srv_r_target[1];
+} SRV_RECORDT_T;
+
+
+typedef struct resource_record RESOURCE_RECORD_T;
+
+struct resource_record
+{
+ char *rr_domain;
+ unsigned int rr_type;
+ unsigned int rr_class;
+ unsigned int rr_ttl;
+ unsigned int rr_size;
+ union
+ {
+ void *rr_data;
+ MX_RECORD_T *rr_mx;
+ MX_RECORD_T *rr_afsdb; /* mx and afsdb are identical */
+ SRV_RECORDT_T *rr_srv;
+# if NETINET
+ struct in_addr *rr_a;
+# endif /* NETINET */
+# if NETINET6
+ struct in6_addr *rr_aaaa;
+# endif /* NETINET6 */
+ char *rr_txt;
+ } rr_u;
+ RESOURCE_RECORD_T *rr_next;
+};
+
+# if !defined(T_A) && !defined(T_AAAA)
+/* XXX if <arpa/nameser.h> isn't included */
+typedef int HEADER; /* will never be used */
+# endif /* !defined(T_A) && !defined(T_AAAA) */
+
+typedef struct
+{
+ HEADER dns_r_h;
+ DNS_QUERY_T dns_r_q;
+ RESOURCE_RECORD_T *dns_r_head;
+} DNS_REPLY_T;
+
+
+extern void dns_free_data __P((DNS_REPLY_T *));
+extern int dns_string_to_type __P((const char *));
+extern const char *dns_type_to_string __P((int));
+extern DNS_REPLY_T *dns_lookup_int __P((const char *,
+ int,
+ int,
+ time_t,
+ int));
+# if 0
+extern DNS_REPLY_T *dns_lookup __P((const char *domain,
+ const char *type_name,
+ time_t retrans,
+ int retry));
+# endif /* 0 */
+
+# endif /* ! __ROKEN_RESOLVE_H__ */
+#endif /* DNSMAP */
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c
index 89bcb0c..ab5d4ee 100644
--- a/contrib/sendmail/src/srvrsmtp.c
+++ b/contrib/sendmail/src/srvrsmtp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,69 +11,88 @@
*
*/
-
#include <sendmail.h>
-
-#ifndef lint
-# if SMTP
-static char id[] = "@(#)$Id: srvrsmtp.c,v 8.471.2.2.2.78 2001/06/26 18:52:21 gshapiro Exp $ (with SMTP)";
-# else /* SMTP */
-static char id[] = "@(#)$Id: srvrsmtp.c,v 8.471.2.2.2.78 2001/06/26 18:52:21 gshapiro Exp $ (without SMTP)";
-# endif /* SMTP */
-#endif /* ! lint */
-
-#if SMTP
-# if SASL || STARTTLS
-# include "sfsasl.h"
-# endif /* SASL || STARTTLS */
-# if SASL
-# define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1)
+#if MILTER
+# include <libmilter/mfdef.h>
+#endif /* MILTER */
+
+SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.814 2002/01/08 00:56:22 ca Exp $")
+
+#if SASL || STARTTLS
+# include <sys/time.h>
+# include "sfsasl.h"
+#endif /* SASL || STARTTLS */
+#if SASL
+# define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1)
static int saslmechs __P((sasl_conn_t *, char **));
-# endif /* SASL */
-# if STARTTLS
-# include <sysexits.h>
-# include <openssl/err.h>
-# include <openssl/bio.h>
-# include <openssl/pem.h>
-# ifndef HASURANDOMDEV
-# include <openssl/rand.h>
-# endif /* !HASURANDOMDEV */
-
-static SSL *srv_ssl = NULL;
-static SSL_CTX *srv_ctx = NULL;
-# if !TLS_NO_RSA
-static RSA *rsa = NULL;
-# endif /* !TLS_NO_RSA */
-static bool tls_ok_srv = FALSE;
-static int tls_verify_cb __P((X509_STORE_CTX *));
-# if !TLS_NO_RSA
-# define RSA_KEYLENGTH 512
-# endif /* !TLS_NO_RSA */
-# endif /* STARTTLS */
-
-static time_t checksmtpattack __P((volatile int *, int, bool,
+#endif /* SASL */
+#if STARTTLS
+# include <sysexits.h>
+
+static SSL_CTX *srv_ctx = NULL; /* TLS server context */
+static SSL *srv_ssl = NULL; /* per connection context */
+
+static bool tls_ok_srv = false;
+
+extern void tls_set_verify __P((SSL_CTX *, SSL *, bool));
+# define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \
+ bitset(SRV_VRFY_CLT, features))
+#endif /* STARTTLS */
+
+/* server features */
+#define SRV_NONE 0x0000 /* none... */
+#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */
+#define SRV_VRFY_CLT 0x0002 /* request a cert */
+#define SRV_OFFER_AUTH 0x0004 /* offer AUTH */
+#define SRV_OFFER_ETRN 0x0008 /* offer ETRN */
+#define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */
+#define SRV_OFFER_EXPN 0x0020 /* offer EXPN */
+#define SRV_OFFER_VERB 0x0040 /* offer VERB */
+#define SRV_OFFER_DSN 0x0080 /* offer DSN */
+#if PIPELINING
+# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */
+# if _FFR_NO_PIPE
+# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */
+# endif /* _FFR_NO_PIPE */
+#endif /* PIPELINING */
+#define SRV_REQ_AUTH 0x0400 /* require AUTH */
+#define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */
+
+static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int));
+
+static time_t checksmtpattack __P((volatile unsigned int *, int, bool,
char *, ENVELOPE *));
static void mail_esmtp_args __P((char *, char *, ENVELOPE *));
static void printvrfyaddr __P((ADDRESS *, bool, bool));
static void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *));
-static int runinchild __P((char *, ENVELOPE *));
static char *skipword __P((char *volatile, char *));
+static void setup_smtpd_io __P((void));
extern ENVELOPE BlankEnvelope;
+#define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \
+ (s)++
+
/*
** SMTP -- run the SMTP protocol.
**
** Parameters:
** nullserver -- if non-NULL, rejection message for
-** all SMTP commands.
+** (almost) all SMTP commands.
+** d_flags -- daemon flags
** e -- the envelope.
**
** Returns:
** never.
**
** Side Effects:
-** Reads commands from the input channel and processes
-** them.
+** Reads commands from the input channel and processes them.
+*/
+
+/*
+** Notice: The smtp server doesn't have a session context like the client
+** side has (mci). Therefore some data (session oriented) is allocated
+** or assigned to the "wrong" structure (esp. STARTTLS, AUTH).
+** This should be fixed in a successor version.
*/
struct cmd
@@ -83,40 +102,37 @@ struct cmd
};
/* values for cmd_code */
-# define CMDERROR 0 /* bad command */
-# define CMDMAIL 1 /* mail -- designate sender */
-# define CMDRCPT 2 /* rcpt -- designate recipient */
-# define CMDDATA 3 /* data -- send message text */
-# define CMDRSET 4 /* rset -- reset state */
-# define CMDVRFY 5 /* vrfy -- verify address */
-# define CMDEXPN 6 /* expn -- expand address */
-# define CMDNOOP 7 /* noop -- do nothing */
-# define CMDQUIT 8 /* quit -- close connection and die */
-# define CMDHELO 9 /* helo -- be polite */
-# define CMDHELP 10 /* help -- give usage info */
-# define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */
-# define CMDETRN 12 /* etrn -- flush queue */
-# if SASL
-# define CMDAUTH 13 /* auth -- SASL authenticate */
-# endif /* SASL */
-# if STARTTLS
-# define CMDSTLS 14 /* STARTTLS -- start TLS session */
-# endif /* STARTTLS */
+#define CMDERROR 0 /* bad command */
+#define CMDMAIL 1 /* mail -- designate sender */
+#define CMDRCPT 2 /* rcpt -- designate recipient */
+#define CMDDATA 3 /* data -- send message text */
+#define CMDRSET 4 /* rset -- reset state */
+#define CMDVRFY 5 /* vrfy -- verify address */
+#define CMDEXPN 6 /* expn -- expand address */
+#define CMDNOOP 7 /* noop -- do nothing */
+#define CMDQUIT 8 /* quit -- close connection and die */
+#define CMDHELO 9 /* helo -- be polite */
+#define CMDHELP 10 /* help -- give usage info */
+#define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */
+#define CMDETRN 12 /* etrn -- flush queue */
+#if SASL
+# define CMDAUTH 13 /* auth -- SASL authenticate */
+#endif /* SASL */
+#if STARTTLS
+# define CMDSTLS 14 /* STARTTLS -- start TLS session */
+#endif /* STARTTLS */
/* non-standard commands */
-# define CMDONEX 16 /* onex -- sending one transaction only */
-# define CMDVERB 17 /* verb -- go into verbose mode */
-# define CMDXUSR 18 /* xusr -- initial (user) submission */
+#define CMDVERB 17 /* verb -- go into verbose mode */
/* unimplemented commands from RFC 821 */
-# define CMDUNIMPL 19 /* unimplemented rfc821 commands */
+#define CMDUNIMPL 19 /* unimplemented rfc821 commands */
/* use this to catch and log "door handle" attempts on your system */
-# define CMDLOGBOGUS 23 /* bogus command that should be logged */
+#define CMDLOGBOGUS 23 /* bogus command that should be logged */
/* debugging-only commands, only enabled if SMTPDEBUG is defined */
-# define CMDDBGQSHOW 24 /* showq -- show send queue */
-# define CMDDBGDEBUG 25 /* debug -- set debug mode */
+#define CMDDBGQSHOW 24 /* showq -- show send queue */
+#define CMDDBGDEBUG 25 /* debug -- set debug mode */
/*
-** Note: If you change this list,
-** remember to update 'helpfile'
+** Note: If you change this list, remember to update 'helpfile'
*/
static struct cmd CmdTab[] =
@@ -134,18 +150,16 @@ static struct cmd CmdTab[] =
{ "ehlo", CMDEHLO },
{ "etrn", CMDETRN },
{ "verb", CMDVERB },
- { "onex", CMDONEX },
- { "xusr", CMDXUSR },
{ "send", CMDUNIMPL },
{ "saml", CMDUNIMPL },
{ "soml", CMDUNIMPL },
{ "turn", CMDUNIMPL },
-# if SASL
+#if SASL
{ "auth", CMDAUTH, },
-# endif /* SASL */
-# if STARTTLS
+#endif /* SASL */
+#if STARTTLS
{ "starttls", CMDSTLS, },
-# endif /* STARTTLS */
+#endif /* STARTTLS */
/* remaining commands are here only to trap and log attempts to use them */
{ "showq", CMDDBGQSHOW },
{ "debug", CMDDBGDEBUG },
@@ -154,20 +168,167 @@ static struct cmd CmdTab[] =
{ NULL, CMDERROR }
};
-static bool OneXact = FALSE; /* one xaction only this run */
static char *CurSmtpClient; /* who's at the other end of channel */
-# define MAXBADCOMMANDS 25 /* maximum number of bad commands */
-# define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */
-# define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */
-# define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */
-# define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */
-# define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */
+#ifndef MAXBADCOMMANDS
+# define MAXBADCOMMANDS 25 /* maximum number of bad commands */
+#endif
+#ifndef MAXNOOPCOMMANDS
+# define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */
+#endif
+#ifndef MAXHELOCOMMANDS
+# define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */
+#endif
+#ifndef MAXVRFYCOMMANDS
+# define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */
+#endif
+#ifndef MAXETRNCOMMANDS
+# define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */
+#endif
+#ifndef MAXTIMEOUT
+# define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */
+#endif
+
+#if SM_HEAP_CHECK
+static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp",
+ "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $");
+#endif /* SM_HEAP_CHECK */
+
+typedef struct
+{
+ bool sm_gotmail; /* mail command received */
+ unsigned int sm_nrcpts; /* number of successful RCPT commands */
+#if _FFR_ADAPTIVE_EOL
+WARNING: do NOT use this FFR, it is most likely broken
+ bool sm_crlf; /* input in CRLF form? */
+#endif /* _FFR_ADAPTIVE_EOL */
+ bool sm_discard;
+#if MILTER
+ bool sm_milterize;
+ bool sm_milterlist; /* any filters in the list? */
+#endif /* MILTER */
+#if _FFR_QUARANTINE
+ char *sm_quarmsg; /* carry quarantining across messages */
+#endif /* _FFR_QUARANTINE */
+} SMTP_T;
+
+static void smtp_data __P((SMTP_T *, ENVELOPE *));
+
+#define MSG_TEMPFAIL "451 4.7.1 Please try again later"
+
+#if MILTER
+# define MILTER_ABORT(e) milter_abort((e))
+# define MILTER_REPLY(str) \
+ { \
+ int savelogusrerrs = LogUsrErrs; \
+ \
+ switch (state) \
+ { \
+ case SMFIR_REPLYCODE: \
+ if (MilterLogLevel > 3) \
+ { \
+ sm_syslog(LOG_INFO, e->e_id, \
+ "Milter: %s=%s, reject=%s", \
+ str, addr, response); \
+ LogUsrErrs = false; \
+ } \
+ usrerr(response); \
+ break; \
+ \
+ case SMFIR_REJECT: \
+ if (MilterLogLevel > 3) \
+ { \
+ sm_syslog(LOG_INFO, e->e_id, \
+ "Milter: %s=%s, reject=550 5.7.1 Command rejected", \
+ str, addr); \
+ LogUsrErrs = false; \
+ } \
+ usrerr("550 5.7.1 Command rejected"); \
+ break; \
+ \
+ case SMFIR_DISCARD: \
+ if (MilterLogLevel > 3) \
+ sm_syslog(LOG_INFO, e->e_id, \
+ "Milter: %s=%s, discard", \
+ str, addr); \
+ e->e_flags |= EF_DISCARD; \
+ break; \
+ \
+ case SMFIR_TEMPFAIL: \
+ if (MilterLogLevel > 3) \
+ { \
+ sm_syslog(LOG_INFO, e->e_id, \
+ "Milter: %s=%s, reject=%s", \
+ str, addr, MSG_TEMPFAIL); \
+ LogUsrErrs = false; \
+ } \
+ usrerr(MSG_TEMPFAIL); \
+ break; \
+ } \
+ LogUsrErrs = savelogusrerrs; \
+ if (response != NULL) \
+ sm_free(response); /* XXX */ \
+ }
+
+#else /* MILTER */
+# define MILTER_ABORT(e)
+#endif /* MILTER */
+
+/* clear all SMTP state (for HELO/EHLO/RSET) */
+#define CLEAR_STATE(cmd) \
+{ \
+ /* abort milter filters */ \
+ MILTER_ABORT(e); \
+ \
+ if (smtp.sm_nrcpts > 0) \
+ { \
+ logundelrcpts(e, cmd, 10, false); \
+ smtp.sm_nrcpts = 0; \
+ macdefine(&e->e_macro, A_PERM, \
+ macid("{nrcpts}"), "0"); \
+ } \
+ \
+ e->e_sendqueue = NULL; \
+ e->e_flags |= EF_CLRQUEUE; \
+ \
+ if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) \
+ logsender(e, NULL); \
+ e->e_flags &= ~EF_LOGSENDER; \
+ \
+ /* clean up a bit */ \
+ smtp.sm_gotmail = false; \
+ SuprErrs = true; \
+ dropenvelope(e, true, false); \
+ sm_rpool_free(e->e_rpool); \
+ e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \
+ CurEnv = e; \
+}
+
+/* sleep to flatten out connection load */
+#define MIN_DELAY_LOG 15 /* wait before logging this again */
+
+/* is it worth setting the process title for 1s? */
+#define DELAY_CONN(cmd) \
+ if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA) \
+ { \
+ time_t dnow; \
+ \
+ sm_setproctitle(true, e, \
+ "%s: %s: delaying %s: load average: %d", \
+ qid_printname(e), CurSmtpClient, \
+ cmd, DelayLA); \
+ if (LogLevel > 8 && (dnow = curtime()) > log_delay) \
+ { \
+ sm_syslog(LOG_INFO, e->e_id, \
+ "delaying=%s, load average=%d >= %d", \
+ cmd, CurrentLA, DelayLA); \
+ log_delay = dnow + MIN_DELAY_LOG; \
+ } \
+ (void) sleep(1); \
+ sm_setproctitle(true, e, "%s %s: %.80s", \
+ qid_printname(e), CurSmtpClient, inp); \
+ }
-/* runinchild() returns */
-# define RIC_INCHILD 0 /* in a child process */
-# define RIC_INPARENT 1 /* still in parent process */
-# define RIC_TEMPFAIL 2 /* temporary failure occurred */
void
smtp(nullserver, d_flags, e)
@@ -180,7 +341,6 @@ smtp(nullserver, d_flags, e)
char *cmd;
auto ADDRESS *vrfyqueue;
ADDRESS *a;
- volatile bool gotmail; /* mail command received */
volatile bool gothello; /* helo command received */
bool vrfy; /* set if this is a vrfy command */
char *volatile protocol; /* sending protocol */
@@ -188,72 +348,92 @@ smtp(nullserver, d_flags, e)
char *volatile peerhostname; /* name of SMTP peer or "localhost" */
auto char *delimptr;
char *id;
- volatile int nrcpts = 0; /* number of RCPT commands */
- int ric;
- bool doublequeue;
- volatile bool discard;
- volatile int badcommands = 0; /* count of bad commands */
- volatile int nverifies = 0; /* count of VRFY/EXPN commands */
- volatile int n_etrn = 0; /* count of ETRN commands */
- volatile int n_noop = 0; /* count of NOOP/VERB/ONEX etc cmds */
- volatile int n_helo = 0; /* count of HELO/EHLO commands */
- volatile int delay = 1; /* timeout for bad commands */
+ volatile unsigned int n_badcmds = 0; /* count of bad commands */
+ volatile unsigned int n_badrcpts = 0; /* number of rejected RCPT */
+ volatile unsigned int n_verifies = 0; /* count of VRFY/EXPN */
+ volatile unsigned int n_etrn = 0; /* count of ETRN */
+ volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */
+ volatile unsigned int n_helo = 0; /* count of HELO/EHLO */
bool ok;
- volatile bool tempfail = FALSE;
-# if _FFR_MILTER
- volatile bool milterize = (nullserver == NULL);
-# endif /* _FFR_MILTER */
+#if _FFR_ADAPTIVE_EOL
+ volatile bool first;
+#endif /* _FFR_ADAPTIVE_EOL */
+ volatile bool tempfail = false;
volatile time_t wt; /* timeout after too many commands */
volatile time_t previous; /* time after checksmtpattack() */
- volatile bool lognullconnection = TRUE;
+ volatile bool lognullconnection = true;
register char *q;
+ SMTP_T smtp;
char *addr;
char *greetcode = "220";
+ char *hostname; /* my hostname ($j) */
QUEUE_CHAR *new;
int argno;
char *args[MAXSMTPARGS];
char inp[MAXLINE];
char cmdbuf[MAXLINE];
-# if SASL
+#if SASL
sasl_conn_t *conn;
volatile bool sasl_ok;
- volatile int n_auth = 0; /* count of AUTH commands */
+ volatile unsigned int n_auth = 0; /* count of AUTH commands */
bool ismore;
int result;
volatile int authenticating;
- char *hostname;
char *user;
char *in, *out, *out2;
const char *errstr;
- int inlen, out2len;
+ unsigned int inlen, out2len;
unsigned int outlen;
char *volatile auth_type;
char *mechlist;
- volatile int n_mechs;
- int len;
+ volatile unsigned int n_mechs;
+ unsigned int len;
sasl_security_properties_t ssp;
sasl_external_properties_t ext_ssf;
-# if SFIO
sasl_ssf_t *ssf;
-# endif /* SFIO */
-# endif /* SASL */
-# if STARTTLS
+#endif /* SASL */
+#if STARTTLS
int r;
int rfd, wfd;
- volatile bool usetls = TRUE;
- volatile bool tls_active = FALSE;
+ volatile bool tls_active = false;
+# if _FFR_SMTP_SSL
+ volatile bool smtps = false;
+# endif /* _FFR_SMTP_SSL */
bool saveQuickAbort;
bool saveSuprErrs;
-# endif /* STARTTLS */
-
- if (fileno(OutChannel) != fileno(stdout))
+ time_t tlsstart;
+#endif /* STARTTLS */
+ volatile unsigned int features;
+#if PIPELINING
+# if _FFR_NO_PIPE
+ int np_log = 0;
+# endif /* _FFR_NO_PIPE */
+#endif /* PIPELINING */
+ volatile time_t log_delay = (time_t) 0;
+
+ smtp.sm_nrcpts = 0;
+#if MILTER
+ smtp.sm_milterize = (nullserver == NULL);
+ smtp.sm_milterlist = false;
+#endif /* MILTER */
+
+ /* setup I/O fd correctly for the SMTP server */
+ setup_smtpd_io();
+
+#if SM_HEAP_CHECK
+ if (sm_debug_active(&DebugLeakSmtp, 1))
{
- /* arrange for debugging output to go to remote host */
- (void) dup2(fileno(OutChannel), fileno(stdout));
+ sm_heap_newgroup();
+ sm_dprintf("smtp() heap group #%d\n", sm_heap_group());
}
+#endif /* SM_HEAP_CHECK */
+
+ /* XXX the rpool should be set when e is initialized in main() */
+ e->e_rpool = sm_rpool_new_x(NULL);
+ e->e_macro.mac_rpool = e->e_rpool;
settime(e);
- (void)sm_getla(e);
+ sm_getla();
peerhostname = RealHostName;
if (peerhostname == NULL)
peerhostname = "localhost";
@@ -263,27 +443,89 @@ smtp(nullserver, d_flags, e)
CurSmtpClient = CurHostName;
/* check_relay may have set discard bit, save for later */
- discard = bitset(EF_DISCARD, e->e_flags);
+ smtp.sm_discard = bitset(EF_DISCARD, e->e_flags);
+
+#if PIPELINING
+ /* auto-flush output when reading input */
+ (void) sm_io_autoflush(InChannel, OutChannel);
+#endif /* PIPELINING */
+
+ sm_setproctitle(true, e, "server %s startup", CurSmtpClient);
+
+ /* Set default features for server. */
+ features = ((bitset(PRIV_NOETRN, PrivacyFlags) ||
+ bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN)
+ | (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE)
+ | (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE
+ : (SRV_OFFER_EXPN
+ | (bitset(PRIV_NOVERB, PrivacyFlags)
+ ? SRV_NONE : SRV_OFFER_VERB)))
+ | (bitset(PRIV_NORECEIPTS, PrivacyFlags) ? SRV_NONE
+ : SRV_OFFER_DSN)
+#if SASL
+ | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH)
+#endif /* SASL */
+#if PIPELINING
+ | SRV_OFFER_PIPE
+#endif /* PIPELINING */
+#if STARTTLS
+ | (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS)
+ | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
+ : SRV_VRFY_CLT)
+#endif /* STARTTLS */
+ ;
+ if (nullserver == NULL)
+ {
+ features = srvfeatures(e, CurSmtpClient, features);
+ if (bitset(SRV_TMP_FAIL, features))
+ {
+ if (LogLevel > 4)
+ sm_syslog(LOG_ERR, NOQID,
+ "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled",
+ CurSmtpClient);
+ nullserver = "450 4.3.0 Please try again later.";
+ }
+#if PIPELINING
+# if _FFR_NO_PIPE
+ else if (bitset(SRV_NO_PIPE, features))
+ {
+ /* for consistency */
+ features &= ~SRV_OFFER_PIPE;
+ }
+# endif /* _FFR_NO_PIPE */
+#endif /* PIPELINING */
+ }
- sm_setproctitle(TRUE, e, "server %s startup", CurSmtpClient);
+ hostname = macvalue('j', e);
-# if SASL
- sasl_ok = FALSE; /* SASL can't be used (yet) */
+
+#if SASL
+ sasl_ok = bitset(SRV_OFFER_AUTH, features);
n_mechs = 0;
+ authenticating = SASL_NOT_AUTH;
/* SASL server new connection */
- hostname = macvalue('j', e);
-# if SASL > 10505
- /* use empty realm: only works in SASL > 1.5.5 */
- result = sasl_server_new("smtp", hostname, "", NULL, 0, &conn);
-# else /* SASL > 10505 */
- /* use no realm -> realm is set to hostname by SASL lib */
- result = sasl_server_new("smtp", hostname, NULL, NULL, 0, &conn);
-# endif /* SASL > 10505 */
- if (result == SASL_OK)
+ if (sasl_ok)
+ {
+# if SASL > 10505
+ /* use empty realm: only works in SASL > 1.5.5 */
+ result = sasl_server_new("smtp", hostname, "", NULL, 0, &conn);
+# else /* SASL > 10505 */
+ /* use no realm -> realm is set to hostname by SASL lib */
+ result = sasl_server_new("smtp", hostname, NULL, NULL, 0,
+ &conn);
+# endif /* SASL > 10505 */
+ sasl_ok = result == SASL_OK;
+ if (!sasl_ok)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "AUTH error: sasl_server_new failed=%d",
+ result);
+ }
+ }
+ if (sasl_ok)
{
- sasl_ok = TRUE;
-
/*
** SASL set properties for sasl
** set local/remote IP
@@ -293,8 +535,8 @@ smtp(nullserver, d_flags, e)
** Kerberos_v4
*/
-# if NETINET
- in = macvalue(macid("{daemon_family}", NULL), e);
+#if NETINET
+ in = macvalue(macid("{daemon_family}"), e);
if (in != NULL && strcmp(in, "inet") == 0)
{
SOCKADDR_LEN_T addrsize;
@@ -302,135 +544,148 @@ smtp(nullserver, d_flags, e)
struct sockaddr_in saddr_r;
addrsize = sizeof(struct sockaddr_in);
- if (getpeername(fileno(InChannel),
+ if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
+ NULL),
(struct sockaddr *)&saddr_r,
&addrsize) == 0)
{
sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r);
addrsize = sizeof(struct sockaddr_in);
- if (getsockname(fileno(InChannel),
+ if (getsockname(sm_io_getinfo(InChannel,
+ SM_IO_WHAT_FD,
+ NULL),
(struct sockaddr *)&saddr_l,
&addrsize) == 0)
sasl_setprop(conn, SASL_IP_LOCAL,
&saddr_l);
}
}
-# endif /* NETINET */
+#endif /* NETINET */
- authenticating = SASL_NOT_AUTH;
auth_type = NULL;
mechlist = NULL;
user = NULL;
-# if 0
- define(macid("{auth_author}", NULL), NULL, &BlankEnvelope);
-# endif /* 0 */
+# if 0
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{auth_author}"), NULL);
+# endif /* 0 */
/* set properties */
(void) memset(&ssp, '\0', sizeof ssp);
-# if SFIO
+
/* XXX should these be options settable via .cf ? */
/* ssp.min_ssf = 0; is default due to memset() */
+# if STARTTLS
+# endif /* STARTTLS */
{
- ssp.max_ssf = INT_MAX;
+ ssp.max_ssf = MaxSLBits;
ssp.maxbufsize = MAXOUTLEN;
}
-# endif /* SFIO */
-# if _FFR_SASL_OPTS
ssp.security_flags = SASLOpts & SASL_SEC_MASK;
-# endif /* _FFR_SASL_OPTS */
sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK;
if (sasl_ok)
{
/*
** external security strength factor;
- ** we have none so zero
-# if STARTTLS
- ** we may have to change this for STARTTLS
- ** (dynamically)
-# endif
+ ** currently we have none so zero
*/
+
ext_ssf.ssf = 0;
ext_ssf.auth_id = NULL;
sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
&ext_ssf) == SASL_OK;
}
if (sasl_ok)
- {
n_mechs = saslmechs(conn, &mechlist);
- sasl_ok = n_mechs > 0;
- }
}
- else
- {
- if (LogLevel > 9)
- sm_syslog(LOG_WARNING, NOQID,
- "SASL error: sasl_server_new failed=%d",
- result);
- }
-# endif /* SASL */
+#endif /* SASL */
-# if STARTTLS
-# if _FFR_TLS_O_T
- saveQuickAbort = QuickAbort;
- saveSuprErrs = SuprErrs;
- SuprErrs = TRUE;
- QuickAbort = FALSE;
- if (rscheck("offer_tls", CurSmtpClient, "", e, TRUE, FALSE, 8,
- NULL) != EX_OK || Errors > 0)
- usetls = FALSE;
- QuickAbort = saveQuickAbort;
- SuprErrs = saveSuprErrs;
-# endif /* _FFR_TLS_O_T */
-# endif /* STARTTLS */
-
-# if _FFR_MILTER
- if (milterize)
+#if MILTER
+ if (smtp.sm_milterize)
{
char state;
/* initialize mail filter connection */
- milter_init(e, &state);
+ smtp.sm_milterlist = milter_init(e, &state);
switch (state)
{
case SMFIR_REJECT:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: inititalization failed, rejecting commands");
greetcode = "554";
nullserver = "Command rejected";
- milterize = FALSE;
+ smtp.sm_milterize = false;
break;
case SMFIR_TEMPFAIL:
- tempfail = TRUE;
- milterize = FALSE;
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: inititalization failed, temp failing commands");
+ tempfail = true;
+ smtp.sm_milterize = false;
break;
}
}
- if (milterize && !bitset(EF_DISCARD, e->e_flags))
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags))
{
char state;
+ char *response;
- (void) milter_connect(peerhostname, RealHostAddr,
- e, &state);
+ response = milter_connect(peerhostname, RealHostAddr,
+ e, &state);
switch (state)
{
case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */
case SMFIR_REJECT:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: connect: host=%s, addr=%s, rejecting commands",
+ peerhostname,
+ anynet_ntoa(&RealHostAddr));
greetcode = "554";
nullserver = "Command rejected";
- milterize = FALSE;
+ smtp.sm_milterize = false;
break;
case SMFIR_TEMPFAIL:
- tempfail = TRUE;
- milterize = FALSE;
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: connect: host=%s, addr=%s, temp failing commands",
+ peerhostname,
+ anynet_ntoa(&RealHostAddr));
+ tempfail = true;
+ smtp.sm_milterize = false;
break;
}
+ if (response != NULL)
+
+ sm_free(response); /* XXX */
}
-# endif /* _FFR_MILTER */
+#endif /* MILTER */
+
+#if STARTTLS
+# if _FFR_SMTP_SSL
+ /* If this an smtps connection, start TLS now */
+ smtps = bitnset(D_SMTPS, d_flags);
+ if (smtps)
+ goto starttls;
+
+ greeting:
+
+# endif /* _FFR_SMTP_SSL */
+#endif /* STARTTLS */
/* output the first line, inserting "ESMTP" as second word */
- expand(SmtpGreeting, inp, sizeof inp, e);
+ if (*greetcode == '5')
+ (void) sm_snprintf(inp, sizeof inp, "%s not accepting messages",
+ hostname);
+ else
+ expand(SmtpGreeting, inp, sizeof inp, e);
+
p = strchr(inp, '\n');
if (p != NULL)
*p++ = '\0';
@@ -438,10 +693,10 @@ smtp(nullserver, d_flags, e)
if (id == NULL)
id = &inp[strlen(inp)];
if (p == NULL)
- snprintf(cmdbuf, sizeof cmdbuf,
+ (void) sm_snprintf(cmdbuf, sizeof cmdbuf,
"%s %%.*s ESMTP%%s", greetcode);
else
- snprintf(cmdbuf, sizeof cmdbuf,
+ (void) sm_snprintf(cmdbuf, sizeof cmdbuf,
"%s-%%.*s ESMTP%%s", greetcode);
message(cmdbuf, (int) (id - inp), inp, id);
@@ -451,70 +706,84 @@ smtp(nullserver, d_flags, e)
*p++ = '\0';
if (isascii(*id) && isspace(*id))
id++;
- (void) snprintf(cmdbuf, sizeof cmdbuf, "%s-%%s", greetcode);
+ (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, "-%s");
message(cmdbuf, id);
}
if (id != NULL)
{
if (isascii(*id) && isspace(*id))
id++;
- (void) snprintf(cmdbuf, sizeof cmdbuf, "%s %%s", greetcode);
+ (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, " %s");
message(cmdbuf, id);
}
protocol = NULL;
sendinghost = macvalue('s', e);
- gothello = FALSE;
- gotmail = FALSE;
+
+#if _FFR_QUARANTINE
+ /* If quarantining by a connect/ehlo action, save between messages */
+ if (e->e_quarmsg == NULL)
+ smtp.sm_quarmsg = NULL;
+ else
+ smtp.sm_quarmsg = newstr(e->e_quarmsg);
+#endif /* _FFR_QUARANTINE */
+
+ /* sendinghost's storage must outlive the current envelope */
+ if (sendinghost != NULL)
+ sendinghost = sm_strdup_x(sendinghost);
+#if _FFR_ADAPTIVE_EOL
+ first = true;
+#endif /* _FFR_ADAPTIVE_EOL */
+ gothello = false;
+ smtp.sm_gotmail = false;
for (;;)
{
- /* arrange for backout */
- (void) setjmp(TopFrame);
- QuickAbort = FALSE;
- HoldErrs = FALSE;
- SuprErrs = FALSE;
- LogUsrErrs = FALSE;
- OnlyOneError = TRUE;
+ SM_TRY
+ {
+ QuickAbort = false;
+ HoldErrs = false;
+ SuprErrs = false;
+ LogUsrErrs = false;
+ OnlyOneError = true;
e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
/* setup for the read */
e->e_to = NULL;
Errors = 0;
FileName = NULL;
- (void) fflush(stdout);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
/* read the input line */
SmtpPhase = "server cmd read";
- sm_setproctitle(TRUE, e, "server %s cmd read", CurSmtpClient);
-# if SASL
+ sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient);
+#if SASL
/*
- ** SMTP AUTH requires accepting any length,
- ** at least for challenge/response
- ** XXX
+ ** XXX SMTP AUTH requires accepting any length,
+ ** at least for challenge/response
*/
-# endif /* SASL */
+#endif /* SASL */
/* handle errors */
- if (ferror(OutChannel) ||
+ if (sm_io_error(OutChannel) ||
(p = sfgets(inp, sizeof inp, InChannel,
TimeOuts.to_nextcommand, SmtpPhase)) == NULL)
{
char *d;
- d = macvalue(macid("{daemon_name}", NULL), e);
+ d = macvalue(macid("{daemon_name}"), e);
if (d == NULL)
d = "stdin";
/* end of file, just die */
disconnect(1, e);
-# if _FFR_MILTER
+#if MILTER
/* close out milter filters */
milter_quit(e);
-# endif /* _FFR_MILTER */
+#endif /* MILTER */
message("421 4.4.1 %s Lost input channel from %s",
MyHostName, CurSmtpClient);
- if (LogLevel > (gotmail ? 1 : 19))
+ if (LogLevel > (smtp.sm_gotmail ? 1 : 19))
sm_syslog(LOG_NOTICE, e->e_id,
"lost input channel from %.100s to %s after %s",
CurSmtpClient, d,
@@ -529,20 +798,64 @@ smtp(nullserver, d_flags, e)
goto doquit;
}
+#if _FFR_ADAPTIVE_EOL
+ if (first)
+ {
+ char *p;
+
+ smtp.sm_crlf = true;
+ p = strchr(inp, '\n');
+ if (p == NULL || p <= inp || p[-1] != '\r')
+ {
+ smtp.sm_crlf = false;
+ if (tTd(66, 1) && LogLevel > 8)
+ {
+ /* how many bad guys are there? */
+ sm_syslog(LOG_INFO, NOQID,
+ "%.100s did not use CRLF",
+ CurSmtpClient);
+ }
+ }
+ first = false;
+ }
+#endif /* _FFR_ADAPTIVE_EOL */
+
/* clean up end of line */
- fixcrlf(inp, TRUE);
+ fixcrlf(inp, true);
-# if SASL
+#if PIPELINING
+# if _FFR_NO_PIPE
+ /*
+ ** if there is more input and pipelining is disabled:
+ ** delay ... (and maybe discard the input?)
+ ** XXX this doesn't really work, at least in tests using
+ ** telnet SM_IO_IS_READABLE only returns 1 if there were
+ ** more than 2 input lines available.
+ */
+
+ if (bitset(SRV_NO_PIPE, features) &&
+ sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL))
+ {
+ if (++np_log < 3)
+ sm_syslog(LOG_INFO, NOQID,
+ "unauthorized PIPELINING, sleeping");
+ sleep(1);
+ }
+
+# endif /* _FFR_NO_PIPE */
+#endif /* PIPELINING */
+
+#if SASL
if (authenticating == SASL_PROC_AUTH)
{
-# if 0
+# if 0
if (*inp == '\0')
{
authenticating = SASL_NOT_AUTH;
message("501 5.5.2 missing input");
continue;
}
-# endif /* 0 */
+# endif /* 0 */
if (*inp == '*' && *(inp + 1) == '\0')
{
authenticating = SASL_NOT_AUTH;
@@ -574,97 +887,95 @@ smtp(nullserver, d_flags, e)
authenticated:
message("235 2.0.0 OK Authenticated");
authenticating = SASL_IS_AUTH;
- define(macid("{auth_type}", NULL),
- newstr(auth_type), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP,
+ macid("{auth_type}"), auth_type);
result = sasl_getprop(conn, SASL_USERNAME,
(void **)&user);
if (result != SASL_OK)
{
user = "";
- define(macid("{auth_authen}", NULL),
- NULL, &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro,
+ A_PERM,
+ macid("{auth_authen}"), NULL);
}
else
{
- define(macid("{auth_authen}", NULL),
- newstr(user), &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro,
+ A_TEMP,
+ macid("{auth_authen}"), user);
}
-# if 0
+# if 0
/* get realm? */
sasl_getprop(conn, SASL_REALM, (void **) &data);
-# endif /* 0 */
-
+# endif /* 0 */
-# if SFIO
/* get security strength (features) */
result = sasl_getprop(conn, SASL_SSF,
(void **) &ssf);
if (result != SASL_OK)
{
- define(macid("{auth_ssf}", NULL),
- "0", &BlankEnvelope);
+ macdefine(&BlankEnvelope.e_macro,
+ A_PERM,
+ macid("{auth_ssf}"), "0");
ssf = NULL;
}
else
{
char pbuf[8];
- snprintf(pbuf, sizeof pbuf, "%u", *ssf);
- define(macid("{auth_ssf}", NULL),
- newstr(pbuf), &BlankEnvelope);
+ (void) sm_snprintf(pbuf, sizeof pbuf,
+ "%u", *ssf);
+ macdefine(&BlankEnvelope.e_macro,
+ A_TEMP,
+ macid("{auth_ssf}"), pbuf);
if (tTd(95, 8))
- dprintf("SASL auth_ssf: %u\n",
- *ssf);
+ sm_dprintf("AUTH auth_ssf: %u\n",
+ *ssf);
}
+
/*
- ** only switch to encrypted connection
+ ** Only switch to encrypted connection
** if a security layer has been negotiated
*/
+
if (ssf != NULL && *ssf > 0)
{
/*
- ** convert sfio stuff to use SASL
- ** check return values
- ** if the call fails,
- ** fall back to unencrypted version
- ** unless some cf option requires
- ** encryption then the connection must
- ** be aborted
+ ** Convert I/O layer to use SASL.
+ ** If the call fails, the connection
+ ** is aborted.
*/
- if (sfdcsasl(InChannel, OutChannel,
- conn) == 0)
+
+ if (sfdcsasl(&InChannel, &OutChannel,
+ conn) == 0)
{
/* restart dialogue */
- gothello = FALSE;
- OneXact = TRUE;
n_helo = 0;
+#if PIPELINING
+ (void) sm_io_autoflush(InChannel,
+ OutChannel);
+#endif /* PIPELINING */
}
else
syserr("503 5.3.3 SASL TLS failed");
- if (LogLevel > 9)
- sm_syslog(LOG_INFO,
- NOQID,
- "SASL: connection from %.64s: mech=%.16s, id=%.64s, bits=%d",
- CurSmtpClient,
- auth_type, user,
- *ssf);
}
-# else /* SFIO */
- if (LogLevel > 9)
+
+ /* NULL pointer ok since it's our function */
+ if (LogLevel > 8)
sm_syslog(LOG_INFO, NOQID,
- "SASL: connection from %.64s: mech=%.16s, id=%.64s",
- CurSmtpClient, auth_type,
- user);
-# endif /* SFIO */
+ "AUTH=server, relay=%.100s, authid=%.128s, mech=%.16s, bits=%d",
+ CurSmtpClient,
+ shortenstring(user, 128),
+ auth_type, *ssf);
}
else if (result == SASL_CONTINUE)
{
len = ENC64LEN(outlen);
out2 = xalloc(len);
result = sasl_encode64(out, outlen, out2, len,
- (u_int *)&out2len);
+ &out2len);
if (result != SASL_OK)
{
/* correct code? XXX */
@@ -672,7 +983,7 @@ smtp(nullserver, d_flags, e)
message("454 4.5.4 Internal error: unable to encode64");
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
- "SASL encode64 error [%d for \"%s\"]",
+ "AUTH encode64 error [%d for \"%s\"]",
result, out);
/* start over? */
authenticating = SASL_NOT_AUTH;
@@ -681,8 +992,8 @@ smtp(nullserver, d_flags, e)
{
message("334 %s", out2);
if (tTd(95, 2))
- dprintf("SASL continue: msg='%s' len=%d\n",
- out2, out2len);
+ sm_dprintf("AUTH continue: msg='%s' len=%u\n",
+ out2, out2len);
}
}
else
@@ -691,35 +1002,27 @@ smtp(nullserver, d_flags, e)
message("500 5.7.0 authentication failed");
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
- "AUTH failure (%s): %s (%d)",
+ "AUTH failure (%s): %s (%d) %s",
auth_type,
sasl_errstring(result, NULL,
NULL),
- result);
+ result,
+ errstr == NULL ? "" : errstr);
authenticating = SASL_NOT_AUTH;
}
}
else
{
/* don't want to do any of this if authenticating */
-# endif /* SASL */
+#endif /* SASL */
/* echo command to transcript */
if (e->e_xfp != NULL)
- fprintf(e->e_xfp, "<<< %s\n", inp);
-
- if (LogLevel >= 15)
- sm_syslog(LOG_INFO, e->e_id,
- "<-- %s",
- inp);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "<<< %s\n", inp);
- if (e->e_id == NULL)
- sm_setproctitle(TRUE, e, "%s: %.80s",
- CurSmtpClient, inp);
- else
- sm_setproctitle(TRUE, e, "%s %s: %.80s",
- qid_printname(e),
- CurSmtpClient, inp);
+ if (LogLevel > 14)
+ sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp);
/* break off command */
for (p = inp; isascii(*p) && isspace(*p); p++)
@@ -732,24 +1035,52 @@ smtp(nullserver, d_flags, e)
*cmd = '\0';
/* throw away leading whitespace */
- while (isascii(*p) && isspace(*p))
- p++;
+ SKIP_SPACE(p);
/* decode command */
for (c = CmdTab; c->cmd_name != NULL; c++)
{
- if (strcasecmp(c->cmd_name, cmdbuf) == 0)
+ if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0)
break;
}
/* reset errors */
errno = 0;
+ /* check whether a "non-null" command has been used */
+ switch (c->cmd_code)
+ {
+#if SASL
+ case CMDAUTH:
+ /* avoid information leak; take first two words? */
+ q = "AUTH";
+ break;
+#endif /* SASL */
+
+ case CMDMAIL:
+ case CMDEXPN:
+ case CMDVRFY:
+ case CMDETRN:
+ lognullconnection = false;
+ /* FALLTHROUGH */
+ default:
+ q = inp;
+ break;
+ }
+
+ if (e->e_id == NULL)
+ sm_setproctitle(true, e, "%s: %.80s",
+ CurSmtpClient, q);
+ else
+ sm_setproctitle(true, e, "%s %s: %.80s",
+ qid_printname(e),
+ CurSmtpClient, q);
+
/*
** Process command.
**
** If we are running as a null server, return 550
- ** to everything.
+ ** to almost everything.
*/
if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags))
@@ -768,22 +1099,30 @@ smtp(nullserver, d_flags, e)
if (bitnset(D_ETRNONLY, d_flags) &&
nullserver == NULL)
break;
+ DELAY_CONN("ETRN");
/* FALLTHROUGH */
default:
- if (++badcommands > MAXBADCOMMANDS)
+#if MAXBADCOMMANDS > 0
+ /* theoretically this could overflow */
+ if (nullserver != NULL &&
+ ++n_badcmds > MAXBADCOMMANDS)
{
- delay *= 2;
- if (delay >= MAXTIMEOUT)
- delay = MAXTIMEOUT;
- (void) sleep(delay);
+ message("421 4.7.0 %s Too many bad commands; closing connection",
+ MyHostName);
+
+ /* arrange to ignore send list */
+ e->e_sendqueue = NULL;
+ goto doquit;
}
+#endif /* MAXBADCOMMANDS > 0 */
if (nullserver != NULL)
{
if (ISSMTPREPLY(nullserver))
usrerr(nullserver);
else
- usrerr("550 5.0.0 %s", nullserver);
+ usrerr("550 5.0.0 %s",
+ nullserver);
}
else
usrerr("452 4.4.5 Insufficient disk space; try again later");
@@ -791,21 +1130,12 @@ smtp(nullserver, d_flags, e)
}
}
- /* non-null server */
- switch (c->cmd_code)
- {
- case CMDMAIL:
- case CMDEXPN:
- case CMDVRFY:
- case CMDETRN:
- lognullconnection = FALSE;
- }
-
switch (c->cmd_code)
{
-# if SASL
+#if SASL
case CMDAUTH: /* sasl */
- if (!sasl_ok)
+ DELAY_CONN("AUTH");
+ if (!sasl_ok || n_mechs <= 0)
{
message("503 5.3.3 AUTH not available");
break;
@@ -815,7 +1145,7 @@ smtp(nullserver, d_flags, e)
message("503 5.5.0 Already Authenticated");
break;
}
- if (gotmail)
+ if (smtp.sm_gotmail)
{
message("503 5.5.0 AUTH not permitted during a mail transaction");
break;
@@ -830,13 +1160,13 @@ smtp(nullserver, d_flags, e)
break;
}
- ismore = FALSE;
+ ismore = false;
/* crude way to avoid crack attempts */
- (void) checksmtpattack(&n_auth, n_mechs + 1, TRUE,
+ (void) checksmtpattack(&n_auth, n_mechs + 1, true,
"AUTH", e);
- /* make sure it's a valid string */
+ /* make sure mechanism (p) is a valid string */
for (q = p; *q != '\0' && isascii(*q); q++)
{
if (isspace(*q))
@@ -854,7 +1184,7 @@ smtp(nullserver, d_flags, e)
/* check whether mechanism is available */
if (iteminlist(p, mechlist, " ") == NULL)
{
- message("503 5.3.3 AUTH mechanism %s not available",
+ message("503 5.3.3 AUTH mechanism %.32s not available",
p);
break;
}
@@ -862,16 +1192,16 @@ smtp(nullserver, d_flags, e)
if (ismore)
{
/* could this be shorter? XXX */
- in = xalloc(strlen(q));
+ in = sm_rpool_malloc(e->e_rpool, strlen(q));
result = sasl_decode64(q, strlen(q), in,
- (u_int *)&inlen);
+ &inlen);
if (result != SASL_OK)
{
message("501 5.5.4 cannot BASE64 decode '%s'",
q);
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
- "SASL decode64 error [%d for \"%s\"]",
+ "AUTH decode64 error [%d for \"%s\"]",
result, q);
/* start over? */
authenticating = SASL_NOT_AUTH;
@@ -879,23 +1209,6 @@ smtp(nullserver, d_flags, e)
inlen = 0;
break;
}
-# if 0
- if (tTd(95, 99))
- {
- int i;
-
- dprintf("AUTH: more \"");
- for (i = 0; i < inlen; i++)
- {
- if (isascii(in[i]) &&
- isprint(in[i]))
- dprintf("%c", in[i]);
- else
- dprintf("_");
- }
- dprintf("\"\n");
- }
-# endif /* 0 */
}
else
{
@@ -912,11 +1225,12 @@ smtp(nullserver, d_flags, e)
message("500 5.7.0 authentication failed");
if (LogLevel > 9)
sm_syslog(LOG_ERR, e->e_id,
- "AUTH failure (%s): %s (%d)",
+ "AUTH failure (%s): %s (%d) %s",
p,
sasl_errstring(result, NULL,
NULL),
- result);
+ result,
+ errstr);
break;
}
auth_type = newstr(p);
@@ -932,14 +1246,14 @@ smtp(nullserver, d_flags, e)
len = ENC64LEN(outlen);
out2 = xalloc(len);
result = sasl_encode64(out, outlen, out2, len,
- (u_int *)&out2len);
+ &out2len);
if (result != SASL_OK)
{
message("454 4.5.4 Temporary authentication failure");
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
- "SASL encode64 error [%d for \"%s\"]",
+ "AUTH encode64 error [%d for \"%s\"]",
result, out);
/* start over? */
@@ -950,18 +1264,18 @@ smtp(nullserver, d_flags, e)
message("334 %s", out2);
authenticating = SASL_PROC_AUTH;
}
-
break;
-# endif /* SASL */
+#endif /* SASL */
-# if STARTTLS
+#if STARTTLS
case CMDSTLS: /* starttls */
+ DELAY_CONN("STARTTLS");
if (*p != '\0')
{
message("501 5.5.2 Syntax error (no parameters allowed)");
break;
}
- if (!usetls)
+ if (!bitset(SRV_OFFER_TLS, features))
{
message("503 5.5.0 TLS not available");
break;
@@ -971,7 +1285,7 @@ smtp(nullserver, d_flags, e)
message("454 4.3.3 TLS not available after start");
break;
}
- if (gotmail)
+ if (smtp.sm_gotmail)
{
message("503 5.5.0 TLS not permitted during a mail transaction");
break;
@@ -985,32 +1299,51 @@ smtp(nullserver, d_flags, e)
usrerr("454 4.7.1 Please try again later");
break;
}
+# if _FFR_SMTP_SSL
+ starttls:
+# endif /* _FFR_SMTP_SSL */
# if TLS_NO_RSA
/*
** XXX do we need a temp key ?
*/
# else /* TLS_NO_RSA */
- if (SSL_CTX_need_tmp_RSA(srv_ctx) &&
- !SSL_CTX_set_tmp_rsa(srv_ctx,
- (rsa = RSA_generate_key(RSA_KEYLENGTH, RSA_F4,
- NULL, NULL)))
- )
- {
- message("454 4.3.3 TLS not available: error generating RSA temp key");
- if (rsa != NULL)
- RSA_free(rsa);
- break;
- }
# endif /* TLS_NO_RSA */
+
+# if TLS_VRFY_PER_CTX
+ /*
+ ** Note: this sets the verification globally
+ ** (per SSL_CTX)
+ ** it's ok since it applies only to one transaction
+ */
+
+ TLS_VERIFY_CLIENT();
+# endif /* TLS_VRFY_PER_CTX */
+
if (srv_ssl != NULL)
SSL_clear(srv_ssl);
else if ((srv_ssl = SSL_new(srv_ctx)) == NULL)
{
message("454 4.3.3 TLS not available: error generating SSL handle");
+# if _FFR_SMTP_SSL
+ goto tls_done;
+# else /* _FFR_SMTP_SSL */
break;
+# endif /* _FFR_SMTP_SSL */
}
- rfd = fileno(InChannel);
- wfd = fileno(OutChannel);
+
+# if !TLS_VRFY_PER_CTX
+ /*
+ ** this could be used if it were possible to set
+ ** verification per SSL (connection)
+ ** not just per SSL_CTX (global)
+ */
+
+ TLS_VERIFY_CLIENT();
+# endif /* !TLS_VRFY_PER_CTX */
+
+ rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
+ wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
+
if (rfd < 0 || wfd < 0 ||
SSL_set_rfd(srv_ssl, rfd) <= 0 ||
SSL_set_wfd(srv_ssl, wfd) <= 0)
@@ -1018,27 +1351,97 @@ smtp(nullserver, d_flags, e)
message("454 4.3.3 TLS not available: error set fd");
SSL_free(srv_ssl);
srv_ssl = NULL;
+# if _FFR_SMTP_SSL
+ goto tls_done;
+# else /* _FFR_SMTP_SSL */
break;
+# endif /* _FFR_SMTP_SSL */
}
- message("220 2.0.0 Ready to start TLS");
+# if _FFR_SMTP_SSL
+ if (!smtps)
+# endif /* _FFR_SMTP_SSL */
+ message("220 2.0.0 Ready to start TLS");
+# if PIPELINING
+ (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
+# endif /* PIPELINING */
+
SSL_set_accept_state(srv_ssl);
# define SSL_ACC(s) SSL_accept(s)
+
+ tlsstart = curtime();
+ ssl_retry:
if ((r = SSL_ACC(srv_ssl)) <= 0)
{
int i;
+ bool timedout;
+ time_t left;
+ time_t now = curtime();
+ struct timeval tv;
/* what to do in this case? */
i = SSL_get_error(srv_ssl, r);
+
+ /*
+ ** For SSL_ERROR_WANT_{READ,WRITE}:
+ ** There is no SSL record available yet
+ ** or there is only a partial SSL record
+ ** removed from the network (socket) buffer
+ ** into the SSL buffer. The SSL_accept will
+ ** only succeed when a full SSL record is
+ ** available (assuming a "real" error
+ ** doesn't happen). To handle when a "real"
+ ** error does happen the select is set for
+ ** exceptions too.
+ ** The connection may be re-negotiated
+ ** during this time so both read and write
+ ** "want errors" need to be handled.
+ ** A select() exception loops back so that
+ ** a proper SSL error message can be gotten.
+ */
+
+ left = TimeOuts.to_starttls - (now - tlsstart);
+ timedout = left <= 0;
+ if (!timedout)
+ {
+ tv.tv_sec = left;
+ tv.tv_usec = 0;
+ }
+
+ /* XXX what about SSL_pending() ? */
+ if (!timedout && i == SSL_ERROR_WANT_READ)
+ {
+ fd_set ssl_maskr, ssl_maskx;
+
+ FD_ZERO(&ssl_maskr);
+ FD_SET(rfd, &ssl_maskr);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(rfd + 1, &ssl_maskr, NULL,
+ &ssl_maskx, &tv) > 0)
+ goto ssl_retry;
+ }
+ if (!timedout && i == SSL_ERROR_WANT_WRITE)
+ {
+ fd_set ssl_maskw, ssl_maskx;
+
+ FD_ZERO(&ssl_maskw);
+ FD_SET(wfd, &ssl_maskw);
+ FD_ZERO(&ssl_maskx);
+ FD_SET(rfd, &ssl_maskx);
+ if (select(wfd + 1, NULL, &ssl_maskw,
+ &ssl_maskx, &tv) > 0)
+ goto ssl_retry;
+ }
if (LogLevel > 5)
{
- sm_syslog(LOG_WARNING, e->e_id,
- "TLS: error: accept failed=%d (%d)",
- r, i);
- if (LogLevel > 9)
- tlslogerr();
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=server, error: accept failed=%d, SSL_error=%d, timedout=%d",
+ r, i, (int) timedout);
+ if (LogLevel > 8)
+ tlslogerr("server");
}
- tls_ok_srv = FALSE;
+ tls_ok_srv = false;
SSL_free(srv_ssl);
srv_ssl = NULL;
@@ -1053,8 +1456,10 @@ smtp(nullserver, d_flags, e)
}
/* ignore return code for now, it's in {verify} */
- (void) tls_get_info(srv_ssl, &BlankEnvelope, TRUE,
- CurSmtpClient, TRUE);
+ (void) tls_get_info(srv_ssl, true,
+ CurSmtpClient,
+ &BlankEnvelope.e_macro,
+ bitset(SRV_VRFY_CLT, features));
/*
** call Stls_client to find out whether
@@ -1063,12 +1468,13 @@ smtp(nullserver, d_flags, e)
saveQuickAbort = QuickAbort;
saveSuprErrs = SuprErrs;
- SuprErrs = TRUE;
- QuickAbort = FALSE;
+ SuprErrs = true;
+ QuickAbort = false;
if (rscheck("tls_client",
- macvalue(macid("{verify}", NULL), e),
- "STARTTLS", e, TRUE, TRUE, 6, NULL) !=
- EX_OK || Errors > 0)
+ macvalue(macid("{verify}"), e),
+ "STARTTLS", e, true, true, 5,
+ NULL, NOQID) != EX_OK ||
+ Errors > 0)
{
extern char MsgBuf[];
@@ -1080,48 +1486,36 @@ smtp(nullserver, d_flags, e)
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
- tls_ok_srv = FALSE; /* don't offer STARTTLS again */
- gothello = FALSE; /* discard info */
+ tls_ok_srv = false; /* don't offer STARTTLS again */
n_helo = 0;
- OneXact = TRUE; /* only one xaction this run */
-# if SASL
+# if SASL
if (sasl_ok)
{
char *s;
- if ((s = macvalue(macid("{cipher_bits}", NULL), e)) != NULL &&
- (ext_ssf.ssf = atoi(s)) > 0)
+ s = macvalue(macid("{cipher_bits}"), e);
+ if (s != NULL && (ext_ssf.ssf = atoi(s)) > 0)
{
-# if _FFR_EXT_MECH
- ext_ssf.auth_id = macvalue(macid("{cert_subject}",
- NULL),
+ ext_ssf.auth_id = macvalue(macid("{cert_subject}"),
e);
-# endif /* _FFR_EXT_MECH */
sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
&ext_ssf) == SASL_OK;
- if (mechlist != NULL)
- sm_free(mechlist);
mechlist = NULL;
if (sasl_ok)
- {
n_mechs = saslmechs(conn,
&mechlist);
- sasl_ok = n_mechs > 0;
- }
}
}
-# endif /* SASL */
+# endif /* SASL */
/* switch to secure connection */
-#if SFIO
- r = sfdctls(InChannel, OutChannel, srv_ssl);
-#else /* SFIO */
-# if _FFR_TLS_TOREK
- r = sfdctls(&InChannel, &OutChannel, srv_ssl);
-# endif /* _FFR_TLS_TOREK */
-#endif /* SFIO */
- if (r == 0)
- tls_active = TRUE;
+ if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0)
+ {
+ tls_active = true;
+# if PIPELINING
+ (void) sm_io_autoflush(InChannel, OutChannel);
+# endif /* PIPELINING */
+ }
else
{
/*
@@ -1132,14 +1526,26 @@ smtp(nullserver, d_flags, e)
** encrypted layer, but we could not...
** just "hang up"?
*/
+
nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer";
- syserr("TLS: can't switch to encrypted layer");
+ syserr("STARTTLS: can't switch to encrypted layer");
}
+# if _FFR_SMTP_SSL
+ tls_done:
+ if (smtps)
+ {
+ if (tls_active)
+ goto greeting;
+ else
+ goto doquit;
+ }
+# endif /* _FFR_SMTP_SSL */
break;
-# endif /* STARTTLS */
+#endif /* STARTTLS */
case CMDHELO: /* hello -- introduce yourself */
case CMDEHLO: /* extended hello */
+ DELAY_CONN("EHLO");
if (c->cmd_code == CMDEHLO)
{
protocol = "ESMTP";
@@ -1152,9 +1558,11 @@ smtp(nullserver, d_flags, e)
}
/* avoid denial-of-service */
- (void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, TRUE,
+ (void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, true,
"HELO/EHLO", e);
+#if 0
+ /* RFC2821 4.1.4 allows duplicate HELO/EHLO */
/* check for duplicate HELO/EHLO per RFC 1651 4.2 */
if (gothello)
{
@@ -1162,6 +1570,7 @@ smtp(nullserver, d_flags, e)
MyHostName);
break;
}
+#endif /* 0 */
/* check for valid domain name (re 1123 5.2.5) */
if (*p == '\0' && !AllowBogusHELO)
@@ -1200,7 +1609,7 @@ smtp(nullserver, d_flags, e)
if (*q == '\0')
{
q = "pleased to meet you";
- sendinghost = newstr(p);
+ sendinghost = sm_strdup_x(p);
}
else if (!AllowBogusHELO)
{
@@ -1216,10 +1625,32 @@ smtp(nullserver, d_flags, e)
q = "accepting invalid domain name";
}
- gothello = TRUE;
+ if (gothello)
+ {
+ CLEAR_STATE(cmdbuf);
-# if _FFR_MILTER
- if (milterize && !bitset(EF_DISCARD, e->e_flags))
+#if _FFR_QUARANTINE
+ /* restore connection quarantining */
+ if (smtp.sm_quarmsg == NULL)
+ {
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), "");
+ }
+ else
+ {
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
+ smtp.sm_quarmsg);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"),
+ e->e_quarmsg);
+ }
+#endif /* _FFR_QUARANTINE */
+ }
+
+#if MILTER
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
@@ -1228,22 +1659,48 @@ smtp(nullserver, d_flags, e)
switch (state)
{
case SMFIR_REPLYCODE:
- nullserver = response;
- milterize = FALSE;
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: helo=%s, reject=%s",
+ p, response);
+ nullserver = newstr(response);
+ smtp.sm_milterize = false;
break;
case SMFIR_REJECT:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: helo=%s, reject=Command rejected",
+ p);
nullserver = "Command rejected";
- milterize = FALSE;
+ smtp.sm_milterize = false;
break;
case SMFIR_TEMPFAIL:
- tempfail = TRUE;
- milterize = FALSE;
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: helo=%s, reject=%s",
+ p, MSG_TEMPFAIL);
+ tempfail = true;
+ smtp.sm_milterize = false;
break;
}
+ if (response != NULL)
+ sm_free(response);
+
+#if _FFR_QUARANTINE
+ /*
+ ** If quarantining by a connect/ehlo action,
+ ** save between messages
+ */
+
+ if (smtp.sm_quarmsg == NULL &&
+ e->e_quarmsg != NULL)
+ smtp.sm_quarmsg = newstr(e->e_quarmsg);
+#endif /* _FFR_QUARANTINE */
}
-# endif /* _FFR_MILTER */
+#endif /* MILTER */
+ gothello = true;
/* print HELO response message */
if (c->cmd_code != CMDEHLO)
@@ -1267,48 +1724,56 @@ smtp(nullserver, d_flags, e)
** print EHLO features list
**
** Note: If you change this list,
- ** remember to update 'helpfile'
+ ** remember to update 'helpfile'
*/
message("250-ENHANCEDSTATUSCODES");
- if (!bitset(PRIV_NOEXPN, PrivacyFlags))
+#if PIPELINING
+ if (bitset(SRV_OFFER_PIPE, features))
+ message("250-PIPELINING");
+#endif /* PIPELINING */
+ if (bitset(SRV_OFFER_EXPN, features))
{
message("250-EXPN");
- if (!bitset(PRIV_NOVERB, PrivacyFlags))
+ if (bitset(SRV_OFFER_VERB, features))
message("250-VERB");
}
-# if MIME8TO7
+#if MIME8TO7
message("250-8BITMIME");
-# endif /* MIME8TO7 */
+#endif /* MIME8TO7 */
if (MaxMessageSize > 0)
message("250-SIZE %ld", MaxMessageSize);
else
message("250-SIZE");
-# if DSN
- if (SendMIMEErrors &&
- !bitset(PRIV_NORECEIPTS, PrivacyFlags))
+#if DSN
+ if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features))
message("250-DSN");
-# endif /* DSN */
- message("250-ONEX");
- if (!bitset(PRIV_NOETRN, PrivacyFlags) &&
- !bitnset(D_NOETRN, d_flags))
+#endif /* DSN */
+ if (bitset(SRV_OFFER_ETRN, features))
message("250-ETRN");
- message("250-XUSR");
-
-# if SASL
+#if SASL
if (sasl_ok && mechlist != NULL && *mechlist != '\0')
message("250-AUTH %s", mechlist);
-# endif /* SASL */
-# if STARTTLS
- if (tls_ok_srv && usetls)
+#endif /* SASL */
+#if STARTTLS
+ if (tls_ok_srv && bitset(SRV_OFFER_TLS, features))
message("250-STARTTLS");
-# endif /* STARTTLS */
+#endif /* STARTTLS */
+ if (DeliverByMin > 0)
+ message("250-DELIVERBY %ld",
+ (long) DeliverByMin);
+ else if (DeliverByMin == 0)
+ message("250-DELIVERBY");
+
+ /* < 0: no deliver-by */
+
message("250 HELP");
break;
case CMDMAIL: /* mail -- designate sender */
SmtpPhase = "server MAIL";
+ DELAY_CONN("MAIL");
/* check for validity of this command */
if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
@@ -1316,25 +1781,19 @@ smtp(nullserver, d_flags, e)
usrerr("503 5.0.0 Polite people say HELO first");
break;
}
- if (gotmail)
+ if (smtp.sm_gotmail)
{
usrerr("503 5.5.0 Sender already specified");
break;
}
- if (InChild)
- {
- errno = 0;
- syserr("503 5.5.0 Nested MAIL command: MAIL %s", p);
- finis(TRUE, ExitStat);
- }
-# if SASL
- if (bitnset(D_AUTHREQ, d_flags) &&
+#if SASL
+ if (bitset(SRV_REQ_AUTH, features) &&
authenticating != SASL_IS_AUTH)
{
usrerr("530 5.7.0 Authentication required");
break;
}
-# endif /* SASL */
+#endif /* SASL */
p = skipword(p, "from");
if (p == NULL)
@@ -1345,7 +1804,7 @@ smtp(nullserver, d_flags, e)
sm_syslog(LOG_INFO, e->e_id,
"SMTP MAIL command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
- usrerr("451 4.7.1 Please try again later");
+ usrerr(MSG_TEMPFAIL);
break;
}
@@ -1354,103 +1813,88 @@ smtp(nullserver, d_flags, e)
sendinghost = peerhostname;
- /* fork a subprocess to process this command */
- ric = runinchild("SMTP-MAIL", e);
-
- /* Catch a problem and stop processing */
- if (ric == RIC_TEMPFAIL && nullserver == NULL)
- nullserver = "452 4.3.0 Internal software error";
- if (ric != RIC_INCHILD)
- break;
+#if SM_HEAP_CHECK
+ if (sm_debug_active(&DebugLeakSmtp, 1))
+ {
+ sm_heap_newgroup();
+ sm_dprintf("smtp() heap group #%d\n",
+ sm_heap_group());
+ }
+#endif /* SM_HEAP_CHECK */
if (Errors > 0)
- goto undo_subproc_no_pm;
+ goto undo_no_pm;
if (!gothello)
{
- auth_warning(e,
- "%s didn't use HELO protocol",
- CurSmtpClient);
+ auth_warning(e, "%s didn't use HELO protocol",
+ CurSmtpClient);
}
-# ifdef PICKY_HELO_CHECK
- if (strcasecmp(sendinghost, peerhostname) != 0 &&
- (strcasecmp(peerhostname, "localhost") != 0 ||
- strcasecmp(sendinghost, MyHostName) != 0))
+#ifdef PICKY_HELO_CHECK
+ if (sm_strcasecmp(sendinghost, peerhostname) != 0 &&
+ (sm_strcasecmp(peerhostname, "localhost") != 0 ||
+ sm_strcasecmp(sendinghost, MyHostName) != 0))
{
auth_warning(e, "Host %s claimed to be %s",
- CurSmtpClient, sendinghost);
+ CurSmtpClient, sendinghost);
}
-# endif /* PICKY_HELO_CHECK */
+#endif /* PICKY_HELO_CHECK */
if (protocol == NULL)
protocol = "SMTP";
- define('r', protocol, e);
- define('s', sendinghost, e);
+ macdefine(&e->e_macro, A_PERM, 'r', protocol);
+ macdefine(&e->e_macro, A_PERM, 's', sendinghost);
if (Errors > 0)
- goto undo_subproc_no_pm;
- nrcpts = 0;
- define(macid("{ntries}", NULL), "0", e);
+ goto undo_no_pm;
+ smtp.sm_nrcpts = 0;
+ n_badrcpts = 0;
+ macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0");
+ macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0");
e->e_flags |= EF_CLRQUEUE;
- sm_setproctitle(TRUE, e, "%s %s: %.80s",
+ sm_setproctitle(true, e, "%s %s: %.80s",
qid_printname(e),
CurSmtpClient, inp);
- /* child -- go do the processing */
- if (setjmp(TopFrame) > 0)
- {
- /* this failed -- undo work */
- undo_subproc_no_pm:
- e->e_flags &= ~EF_PM_NOTIFY;
- undo_subproc:
- if (InChild)
- {
- QuickAbort = FALSE;
- SuprErrs = TRUE;
- e->e_flags &= ~EF_FATALERRS;
-
- if (LogLevel > 4 &&
- bitset(EF_LOGSENDER, e->e_flags))
- logsender(e, NULL);
- e->e_flags &= ~EF_LOGSENDER;
-
- finis(TRUE, ExitStat);
- }
- break;
- }
- QuickAbort = TRUE;
+ /* do the processing */
+ SM_TRY
+ {
+ QuickAbort = true;
/* must parse sender first */
delimptr = NULL;
- setsender(p, e, &delimptr, ' ', FALSE);
+ setsender(p, e, &delimptr, ' ', false);
if (delimptr != NULL && *delimptr != '\0')
*delimptr++ = '\0';
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
/* Successfully set e_from, allow logging */
e->e_flags |= EF_LOGSENDER;
/* put resulting triple from parseaddr() into macros */
if (e->e_from.q_mailer != NULL)
- define(macid("{mail_mailer}", NULL),
- e->e_from.q_mailer->m_name, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_mailer}"),
+ e->e_from.q_mailer->m_name);
else
- define(macid("{mail_mailer}", NULL),
- NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_mailer}"), NULL);
if (e->e_from.q_host != NULL)
- define(macid("{mail_host}", NULL),
- e->e_from.q_host, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_host}"),
+ e->e_from.q_host);
else
- define(macid("{mail_host}", NULL),
- "localhost", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_host}"), "localhost");
if (e->e_from.q_user != NULL)
- define(macid("{mail_addr}", NULL),
- e->e_from.q_user, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_addr}"),
+ e->e_from.q_user);
else
- define(macid("{mail_addr}", NULL),
- NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{mail_addr}"), NULL);
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
/* check for possible spoofing */
if (RealUid != 0 && OpMode == MD_SMTP &&
@@ -1476,8 +1920,7 @@ smtp(nullserver, d_flags, e)
char *equal = NULL;
/* locate the beginning of the keyword */
- while (isascii(*p) && isspace(*p))
- p++;
+ SKIP_SPACE(p);
if (*p == '\0')
break;
kp = p;
@@ -1502,7 +1945,7 @@ smtp(nullserver, d_flags, e)
*p++ = '\0';
if (tTd(19, 1))
- dprintf("MAIL: got arg %s=\"%s\"\n", kp,
+ sm_dprintf("MAIL: got arg %s=\"%s\"\n", kp,
vp == NULL ? "<null>" : vp);
mail_esmtp_args(kp, vp, e);
@@ -1512,17 +1955,47 @@ smtp(nullserver, d_flags, e)
if (argno >= MAXSMTPARGS - 1)
usrerr("501 5.5.4 Too many parameters");
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
args[argno] = NULL;
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
+
+#if SASL
+# if _FFR_AUTH_PASSING
+ /* set the default AUTH= if the sender didn't */
+ if (e->e_auth_param == NULL)
+ {
+ /* XXX only do this for an MSA? */
+ e->e_auth_param = macvalue(macid("{auth_authen}"),
+ e);
+ if (e->e_auth_param == NULL)
+ e->e_auth_param = "<>";
+
+ /*
+ ** XXX should we invoke Strust_auth now?
+ ** authorizing as the client that just
+ ** authenticated, so we'll trust implicitly
+ */
+ }
+# endif /* _FFR_AUTH_PASSING */
+#endif /* SASL */
/* do config file checking of the sender */
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "e s");
+#if _FFR_MAIL_MACRO
+ /* make the "real" sender address available */
+ macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"),
+ e->e_from.q_paddr);
+#endif /* _FFR_MAIL_MACRO */
if (rscheck("check_mail", addr,
- NULL, e, TRUE, TRUE, 4, NULL) != EX_OK ||
+ NULL, e, true, true, 3, NULL,
+ e->e_id) != EX_OK ||
Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), NULL);
if (MaxMessageSize > 0 &&
(e->e_msgsize > MaxMessageSize ||
@@ -1530,80 +2003,97 @@ smtp(nullserver, d_flags, e)
{
usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)",
MaxMessageSize);
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
- if (!enoughdiskspace(e->e_msgsize, TRUE))
+ /*
+ ** XXX always check whether there is at least one fs
+ ** with enough space?
+ ** However, this may not help much: the queue group
+ ** selection may later on select a FS that hasn't
+ ** enough space.
+ */
+
+ if ((NumFileSys == 1 || NumQueue == 1) &&
+ !enoughdiskspace(e->e_msgsize, e)
+#if _FFR_ANY_FREE_FS
+ && !filesys_free(e->e_msgsize)
+#endif /* _FFR_ANY_FREE_FS */
+ )
{
+ /*
+ ** We perform this test again when the
+ ** queue directory is selected, in collect.
+ */
+
usrerr("452 4.4.5 Insufficient disk space; try again later");
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
}
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
-# if _FFR_MILTER
- LogUsrErrs = TRUE;
- if (milterize && !bitset(EF_DISCARD, e->e_flags))
+ LogUsrErrs = true;
+#if MILTER
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_envfrom(args, e, &state);
- switch (state)
- {
- case SMFIR_REPLYCODE:
- usrerr(response);
- break;
-
- case SMFIR_REJECT:
- usrerr("550 5.7.1 Command rejected");
- break;
-
- case SMFIR_DISCARD:
- e->e_flags |= EF_DISCARD;
- break;
-
- case SMFIR_TEMPFAIL:
- usrerr("451 4.7.1 Please try again later");
- break;
- }
- if (response != NULL)
- sm_free(response);
+ MILTER_REPLY("from");
}
-# endif /* _FFR_MILTER */
+#endif /* MILTER */
if (Errors > 0)
- goto undo_subproc_no_pm;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
message("250 2.1.0 Sender ok");
- gotmail = TRUE;
+ smtp.sm_gotmail = true;
+ }
+ SM_EXCEPT(exc, "[!F]*")
+ {
+ /*
+ ** An error occurred while processing a MAIL command.
+ ** Jump to the common error handling code.
+ */
+
+ sm_exc_free(exc);
+ goto undo_no_pm;
+ }
+ SM_END_TRY
+ break;
+
+ undo_no_pm:
+ e->e_flags &= ~EF_PM_NOTIFY;
+ undo:
break;
case CMDRCPT: /* rcpt -- designate recipient */
- if (!gotmail)
+ DELAY_CONN("RCPT");
+ if (!smtp.sm_gotmail)
{
usrerr("503 5.0.0 Need MAIL before RCPT");
break;
}
SmtpPhase = "server RCPT";
- if (setjmp(TopFrame) > 0)
- {
- e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
- break;
- }
- QuickAbort = TRUE;
- LogUsrErrs = TRUE;
+ SM_TRY
+ {
+ QuickAbort = true;
+ LogUsrErrs = true;
/* limit flooding of our machine */
- if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg)
+ if (MaxRcptPerMsg > 0 &&
+ smtp.sm_nrcpts >= MaxRcptPerMsg)
{
+ /* sleep(1); / * slow down? */
usrerr("452 4.5.3 Too many recipients");
- break;
+ goto rcpt_done;
}
if (e->e_sendmode != SM_DELIVER)
e->e_flags |= EF_VRFYONLY;
-# if _FFR_MILTER
+#if MILTER
/*
** If the filter will be deleting recipients,
** don't expand them at RCPT time (in the call
@@ -1615,24 +2105,46 @@ smtp(nullserver, d_flags, e)
if (milter_can_delrcpts())
e->e_flags |= EF_VRFYONLY;
-# endif /* _FFR_MILTER */
+#endif /* MILTER */
p = skipword(p, "to");
if (p == NULL)
- break;
-# if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), "e r", e);
-# endif /* _FFR_ADDR_TYPE */
- a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
-#if _FFR_ADDR_TYPE
- define(macid("{addr_type}", NULL), NULL, e);
-#endif /* _FFR_ADDR_TYPE */
+ goto rcpt_done;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "e r");
+ a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr,
+ e, true);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), NULL);
+ if (BadRcptThrottle > 0 &&
+ n_badrcpts >= BadRcptThrottle)
+ {
+ if (LogLevel > 5 &&
+ n_badrcpts == BadRcptThrottle)
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "%.100s: Possible SMTP RCPT flood, throttling.",
+ CurSmtpClient);
+
+ /* To avoid duplicated message */
+ n_badrcpts++;
+ }
+
+ /*
+ ** Don't use exponential backoff for now.
+ ** Some servers will open more connections
+ ** and actually overload the receiver even
+ ** more.
+ */
+
+ (void) sleep(1);
+ }
if (Errors > 0)
- break;
+ goto rcpt_done;
if (a == NULL)
{
usrerr("501 5.0.0 Missing recipient");
- break;
+ goto rcpt_done;
}
if (delimptr != NULL && *delimptr != '\0')
@@ -1640,25 +2152,26 @@ smtp(nullserver, d_flags, e)
/* put resulting triple from parseaddr() into macros */
if (a->q_mailer != NULL)
- define(macid("{rcpt_mailer}", NULL),
- a->q_mailer->m_name, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"),
+ a->q_mailer->m_name);
else
- define(macid("{rcpt_mailer}", NULL),
- NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), NULL);
if (a->q_host != NULL)
- define(macid("{rcpt_host}", NULL),
- a->q_host, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"), a->q_host);
else
- define(macid("{rcpt_host}", NULL),
- "localhost", e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"), "localhost");
if (a->q_user != NULL)
- define(macid("{rcpt_addr}", NULL),
- a->q_user, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), a->q_user);
else
- define(macid("{rcpt_addr}", NULL),
- NULL, e);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), NULL);
if (Errors > 0)
- break;
+ goto rcpt_done;
/* now parse ESMTP arguments */
addr = p;
@@ -1672,8 +2185,7 @@ smtp(nullserver, d_flags, e)
char *equal = NULL;
/* locate the beginning of the keyword */
- while (isascii(*p) && isspace(*p))
- p++;
+ SKIP_SPACE(p);
if (*p == '\0')
break;
kp = p;
@@ -1698,7 +2210,7 @@ smtp(nullserver, d_flags, e)
*p++ = '\0';
if (tTd(19, 1))
- dprintf("RCPT: got arg %s=\"%s\"\n", kp,
+ sm_dprintf("RCPT: got arg %s=\"%s\"\n", kp,
vp == NULL ? "<null>" : vp);
rcpt_esmtp_args(a, kp, vp, e);
@@ -1712,325 +2224,126 @@ smtp(nullserver, d_flags, e)
}
args[argno] = NULL;
if (Errors > 0)
- break;
+ goto rcpt_done;
/* do config file checking of the recipient */
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), "e r");
if (rscheck("check_rcpt", addr,
- NULL, e, TRUE, TRUE, 4, NULL) != EX_OK ||
+ NULL, e, true, true, 3, NULL,
+ e->e_id) != EX_OK ||
Errors > 0)
- break;
+ goto rcpt_done;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{addr_type}"), NULL);
-# if _FFR_MILTER
- if (milterize && !bitset(EF_DISCARD, e->e_flags))
+#if MILTER
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_envrcpt(args, e, &state);
- switch (state)
- {
- case SMFIR_REPLYCODE:
- usrerr(response);
- break;
-
- case SMFIR_REJECT:
- usrerr("550 5.7.1 Command rejected");
- break;
-
- case SMFIR_DISCARD:
- e->e_flags |= EF_DISCARD;
- break;
-
- case SMFIR_TEMPFAIL:
- usrerr("451 4.7.1 Please try again later");
- break;
- }
- if (response != NULL)
- sm_free(response);
- }
-# endif /* _FFR_MILTER */
-
- define(macid("{rcpt_mailer}", NULL), NULL, e);
- define(macid("{rcpt_relay}", NULL), NULL, e);
- define(macid("{rcpt_addr}", NULL), NULL, e);
- define(macid("{dsn_notify}", NULL), NULL, e);
+ MILTER_REPLY("to");
+ }
+#endif /* MILTER */
+
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_relay}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_notify}"), NULL);
if (Errors > 0)
- break;
+ goto rcpt_done;
/* save in recipient list after ESMTP mods */
a = recipient(a, &e->e_sendqueue, 0, e);
if (Errors > 0)
- break;
+ goto rcpt_done;
/* no errors during parsing, but might be a duplicate */
e->e_to = a->q_paddr;
if (!QS_IS_BADADDR(a->q_state))
{
- if (e->e_queuedir == NOQDIR)
+ if (smtp.sm_nrcpts == 0)
initsys(e);
message("250 2.1.5 Recipient ok%s",
QS_IS_QUEUEUP(a->q_state) ?
" (will queue)" : "");
- nrcpts++;
+ smtp.sm_nrcpts++;
}
else
{
/* punt -- should keep message in ADDRESS.... */
usrerr("550 5.1.1 Addressee unknown");
}
+ rcpt_done:
+ if (Errors > 0)
+ ++n_badrcpts;
+ }
+ SM_EXCEPT(exc, "[!F]*")
+ {
+ /* An exception occurred while processing RCPT */
+ e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
+ ++n_badrcpts;
+ }
+ SM_END_TRY
break;
case CMDDATA: /* data -- text of mail */
- SmtpPhase = "server DATA";
- if (!gotmail)
- {
- usrerr("503 5.0.0 Need MAIL command");
- break;
- }
- else if (nrcpts <= 0)
- {
- usrerr("503 5.0.0 Need RCPT (recipient)");
- break;
- }
-
- /* put back discard bit */
- if (discard)
- e->e_flags |= EF_DISCARD;
-
- /* check to see if we need to re-expand aliases */
- /* also reset QS_BADADDR on already-diagnosted addrs */
- doublequeue = FALSE;
- for (a = e->e_sendqueue; a != NULL; a = a->q_next)
- {
- if (QS_IS_VERIFIED(a->q_state) &&
- !bitset(EF_DISCARD, e->e_flags))
- {
- /* need to re-expand aliases */
- doublequeue = TRUE;
- }
- if (QS_IS_BADADDR(a->q_state))
- {
- /* make this "go away" */
- a->q_state = QS_DONTSEND;
- }
- }
-
- /* collect the text of the message */
- SmtpPhase = "collect";
- buffer_errors();
- collect(InChannel, TRUE, NULL, e);
-
-# if _FFR_MILTER
- if (milterize &&
- Errors <= 0 &&
- !bitset(EF_DISCARD, e->e_flags))
- {
- char state;
- char *response;
-
- response = milter_data(e, &state);
- switch (state)
- {
- case SMFIR_REPLYCODE:
- usrerr(response);
- break;
-
- case SMFIR_REJECT:
- usrerr("554 5.7.1 Command rejected");
- break;
-
- case SMFIR_DISCARD:
- e->e_flags |= EF_DISCARD;
- break;
-
- case SMFIR_TEMPFAIL:
- usrerr("451 4.7.1 Please try again later");
- break;
- }
- if (response != NULL)
- sm_free(response);
- }
-
- /* abort message filters that didn't get the body */
- if (milterize)
- milter_abort(e);
-# endif /* _FFR_MILTER */
-
- /* redefine message size */
- if ((q = macvalue(macid("{msg_size}", NULL), e))
- != NULL)
- sm_free(q);
- snprintf(inp, sizeof inp, "%ld", e->e_msgsize);
- define(macid("{msg_size}", NULL), newstr(inp), e);
- if (Errors > 0)
- {
- /* Log who the mail would have gone to */
- if (LogLevel > 8 &&
- e->e_message != NULL)
- {
- for (a = e->e_sendqueue;
- a != NULL;
- a = a->q_next)
- {
- if (!QS_IS_UNDELIVERED(a->q_state))
- continue;
-
- e->e_to = a->q_paddr;
- logdelivery(NULL, NULL,
- a->q_status,
- e->e_message,
- NULL,
- (time_t) 0, e);
- }
- e->e_to = NULL;
- }
- flush_errors(TRUE);
- buffer_errors();
- goto abortmessage;
- }
-
- /* make sure we actually do delivery */
- e->e_flags &= ~EF_CLRQUEUE;
-
- /* from now on, we have to operate silently */
- buffer_errors();
- e->e_errormode = EM_MAIL;
-
- /*
- ** Arrange to send to everyone.
- ** If sending to multiple people, mail back
- ** errors rather than reporting directly.
- ** In any case, don't mail back errors for
- ** anything that has happened up to
- ** now (the other end will do this).
- ** Truncate our transcript -- the mail has gotten
- ** to us successfully, and if we have
- ** to mail this back, it will be easier
- ** on the reader.
- ** Then send to everyone.
- ** Finally give a reply code. If an error has
- ** already been given, don't mail a
- ** message back.
- ** We goose error returns by clearing error bit.
- */
-
- SmtpPhase = "delivery";
- (void) bftruncate(e->e_xfp);
- id = e->e_id;
-
- /*
- ** If a header/body check (header checks or milter)
- ** set EF_DISCARD, don't queueup the message --
- ** that would lose the EF_DISCARD bit and deliver
- ** the message.
- */
-
- if (bitset(EF_DISCARD, e->e_flags))
- doublequeue = FALSE;
-
- if (doublequeue)
- {
- /* make sure it is in the queue */
- queueup(e, FALSE);
- }
- else
- {
- /* send to all recipients */
-# if NAMED_BIND
- _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
- _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
-# endif /* NAMED_BIND */
- sendall(e, SM_DEFAULT);
- }
- e->e_to = NULL;
-
- /* issue success message */
- message("250 2.0.0 %s Message accepted for delivery", id);
-
- /* if we just queued, poke it */
- if (doublequeue &&
- e->e_sendmode != SM_QUEUE &&
- e->e_sendmode != SM_DEFER)
- {
- CurrentLA = sm_getla(e);
-
- if (!shouldqueue(e->e_msgpriority, e->e_ctime))
- {
- /* close all the queue files */
- closexscript(e);
- if (e->e_dfp != NULL)
- (void) bfclose(e->e_dfp);
- e->e_dfp = NULL;
- unlockqueue(e);
-
- (void) dowork(e->e_queuedir, id,
- TRUE, TRUE, e);
- }
- }
-
- abortmessage:
- if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
- logsender(e, NULL);
- e->e_flags &= ~EF_LOGSENDER;
-
- /* if in a child, pop back to our parent */
- if (InChild)
- finis(TRUE, ExitStat);
-
- /* clean up a bit */
- gotmail = FALSE;
- dropenvelope(e, TRUE);
- CurEnv = e = newenvelope(e, CurEnv);
- e->e_flags = BlankEnvelope.e_flags;
+ DELAY_CONN("DATA");
+ smtp_data(&smtp, e);
break;
case CMDRSET: /* rset -- reset state */
-# if _FFR_MILTER
- /* abort milter filters */
- milter_abort(e);
-# endif /* _FFR_MILTER */
-
if (tTd(94, 100))
message("451 4.0.0 Test failure");
else
message("250 2.0.0 Reset state");
-
- /* arrange to ignore any current send list */
- e->e_sendqueue = NULL;
- e->e_flags |= EF_CLRQUEUE;
-
- if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
- logsender(e, NULL);
- e->e_flags &= ~EF_LOGSENDER;
-
- if (InChild)
- finis(TRUE, ExitStat);
-
- /* clean up a bit */
- gotmail = FALSE;
- SuprErrs = TRUE;
- dropenvelope(e, TRUE);
- CurEnv = e = newenvelope(e, CurEnv);
+ CLEAR_STATE(cmdbuf);
+#if _FFR_QUARANTINE
+ /* restore connection quarantining */
+ if (smtp.sm_quarmsg == NULL)
+ {
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), "");
+ }
+ else
+ {
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
+ smtp.sm_quarmsg);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
+ }
+#endif /* _FFR_QUARANTINE */
break;
case CMDVRFY: /* vrfy -- verify address */
case CMDEXPN: /* expn -- expand address */
+ vrfy = c->cmd_code == CMDVRFY;
+ DELAY_CONN(vrfy ? "VRFY" : "EXPN");
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP %s command (%.100s) from %.100s tempfailed (due to previous checks)",
- c->cmd_code == CMDVRFY ? "VRFY" : "EXPN",
+ vrfy ? "VRFY" : "EXPN",
p, CurSmtpClient);
+
+ /* RFC 821 doesn't allow 4xy reply code */
usrerr("550 5.7.1 Please try again later");
break;
}
- wt = checksmtpattack(&nverifies, MAXVRFYCOMMANDS, FALSE,
- c->cmd_code == CMDVRFY ? "VRFY" : "EXPN", e);
+ wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS,
+ false, vrfy ? "VRFY" : "EXPN", e);
previous = curtime();
- vrfy = c->cmd_code == CMDVRFY;
if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
- PrivacyFlags))
+ PrivacyFlags))
{
if (vrfy)
message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
@@ -2050,18 +2363,15 @@ smtp(nullserver, d_flags, e)
usrerr("503 5.0.0 I demand that you introduce yourself first");
break;
}
- if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
- break;
if (Errors > 0)
- goto undo_subproc;
+ break;
if (LogLevel > 5)
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: %s",
+ sm_syslog(LOG_INFO, e->e_id, "%.100s: %s",
CurSmtpClient,
shortenstring(inp, MAXSHORTSTR));
- if (setjmp(TopFrame) > 0)
- goto undo_subproc;
- QuickAbort = TRUE;
+ SM_TRY
+ {
+ QuickAbort = true;
vrfyqueue = NULL;
if (vrfy)
e->e_flags |= EF_VRFYONLY;
@@ -2075,9 +2385,10 @@ smtp(nullserver, d_flags, e)
{
/* do config file checking of the address */
if (rscheck(vrfy ? "check_vrfy" : "check_expn",
- p, NULL, e, TRUE, FALSE, 4, NULL)
- != EX_OK || Errors > 0)
- goto undo_subproc;
+ p, NULL, e, true, false, 3, NULL,
+ NOQID) != EX_OK ||
+ Errors > 0)
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
}
if (wt > 0)
@@ -2089,7 +2400,7 @@ smtp(nullserver, d_flags, e)
(void) sleep(t);
}
if (Errors > 0)
- goto undo_subproc;
+ sm_exc_raisenew_x(&EtypeQuickAbort, 1);
if (vrfyqueue == NULL)
{
usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN");
@@ -2110,13 +2421,26 @@ smtp(nullserver, d_flags, e)
printvrfyaddr(vrfyqueue, a == NULL, vrfy);
vrfyqueue = a;
}
- if (InChild)
- finis(TRUE, ExitStat);
+ }
+ SM_EXCEPT(exc, "[!F]*")
+ {
+ /*
+ ** An exception occurred while processing VRFY/EXPN
+ */
+
+ sm_exc_free(exc);
+ goto undo;
+ }
+ SM_END_TRY
break;
case CMDETRN: /* etrn -- force queue flush */
- if (bitset(PRIV_NOETRN, PrivacyFlags) ||
- bitnset(D_NOETRN, d_flags))
+ DELAY_CONN("ETRN");
+
+ /* Don't leak queue information via debug flags */
+ if (!bitset(SRV_OFFER_ETRN, features) || UseMSP ||
+ (RealUid != 0 && RealUid != TrustedUid &&
+ OpMode == MD_SMTP))
{
/* different message for MSA ? */
message("502 5.7.0 Sorry, we do not allow this operation");
@@ -2133,7 +2457,7 @@ smtp(nullserver, d_flags, e)
sm_syslog(LOG_INFO, e->e_id,
"SMTP ETRN command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
- usrerr("451 4.7.1 Please try again later");
+ usrerr(MSG_TEMPFAIL);
break;
}
@@ -2144,80 +2468,119 @@ smtp(nullserver, d_flags, e)
}
/* crude way to avoid denial-of-service attacks */
- (void) checksmtpattack(&n_etrn, MAXETRNCOMMANDS, TRUE,
+ (void) checksmtpattack(&n_etrn, MAXETRNCOMMANDS, true,
"ETRN", e);
- /* do config file checking of the parameter */
- if (rscheck("check_etrn", p, NULL, e, TRUE, FALSE, 4,
- NULL) != EX_OK || Errors > 0)
+ /*
+ ** Do config file checking of the parameter.
+ ** Even though we have srv_features now, we still
+ ** need this ruleset because the former is called
+ ** when the connection has been established, while
+ ** this ruleset is called when the command is
+ ** actually issued and therefore has all information
+ ** available to make a decision.
+ */
+
+ if (rscheck("check_etrn", p, NULL, e, true, false, 3,
+ NULL, NOQID) != EX_OK || Errors > 0)
break;
if (LogLevel > 5)
sm_syslog(LOG_INFO, e->e_id,
- "%.100s: ETRN %s",
- CurSmtpClient,
+ "%.100s: ETRN %s", CurSmtpClient,
shortenstring(p, MAXSHORTSTR));
id = p;
+ if (*id == '#')
+ {
+ int wgrp;
+
+ id++;
+ wgrp = name2qid(id);
+ if (!ISVALIDQGRP(wgrp))
+ {
+ usrerr("459 4.5.4 Queue %s unknown",
+ id);
+ break;
+ }
+ ok = run_work_group(wgrp, true, false,
+ false, true);
+ if (ok && Errors == 0)
+ message("250 2.0.0 Queuing for queue group %s started", id);
+ break;
+ }
+
if (*id == '@')
id++;
else
*--id = '@';
- new = (QUEUE_CHAR *)xalloc(sizeof(QUEUE_CHAR));
+ new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR));
+ if (new == NULL)
+ {
+ syserr("500 5.5.0 ETRN out of memory");
+ break;
+ }
new->queue_match = id;
+ new->queue_negate = false;
new->queue_next = NULL;
QueueLimitRecipient = new;
- ok = runqueue(TRUE, FALSE);
- sm_free(QueueLimitRecipient);
+ ok = runqueue(true, false, false, true);
+ sm_free(QueueLimitRecipient); /* XXX */
QueueLimitRecipient = NULL;
if (ok && Errors == 0)
message("250 2.0.0 Queuing for node %s started", p);
break;
case CMDHELP: /* help -- give user info */
+ DELAY_CONN("HELP");
help(p, e);
break;
case CMDNOOP: /* noop -- do nothing */
- (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
+ DELAY_CONN("NOOP");
+ (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true,
"NOOP", e);
message("250 2.0.0 OK");
break;
case CMDQUIT: /* quit -- leave mail */
message("221 2.0.0 %s closing connection", MyHostName);
+#if PIPELINING
+ (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
+#endif /* PIPELINING */
+
+ if (smtp.sm_nrcpts > 0)
+ logundelrcpts(e, "aborted by sender", 9, false);
/* arrange to ignore any current send list */
e->e_sendqueue = NULL;
-# if STARTTLS
+#if STARTTLS
/* shutdown TLS connection */
if (tls_active)
{
(void) endtls(srv_ssl, "server");
- tls_active = FALSE;
+ tls_active = false;
}
-# endif /* STARTTLS */
-# if SASL
+#endif /* STARTTLS */
+#if SASL
if (authenticating == SASL_IS_AUTH)
{
sasl_dispose(&conn);
authenticating = SASL_NOT_AUTH;
+ /* XXX sasl_done(); this is a child */
}
-# endif /* SASL */
+#endif /* SASL */
doquit:
/* avoid future 050 messages */
disconnect(1, e);
-# if _FFR_MILTER
+#if MILTER
/* close out milter filters */
milter_quit(e);
-# endif /* _FFR_MILTER */
-
- if (InChild)
- ExitStat = EX_QUIT;
+#endif /* MILTER */
if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
logsender(e, NULL);
@@ -2227,49 +2590,48 @@ doquit:
{
char *d;
- d = macvalue(macid("{daemon_name}", NULL), e);
+ d = macvalue(macid("{daemon_name}"), e);
if (d == NULL)
d = "stdin";
- sm_syslog(LOG_INFO, NULL,
- "%.100s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s",
+
+ /*
+ ** even though this id is "bogus", it makes
+ ** it simpler to "grep" related events, e.g.,
+ ** timeouts for the same connection.
+ */
+
+ sm_syslog(LOG_INFO, e->e_id,
+ "%.100s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s",
CurSmtpClient, d);
}
- finis(TRUE, ExitStat);
+#if PROFILING
+ return;
+#endif /* PROFILING */
+ finis(true, true, ExitStat);
/* NOTREACHED */
case CMDVERB: /* set verbose mode */
+ DELAY_CONN("VERB");
if (bitset(PRIV_NOEXPN, PrivacyFlags) ||
+ !bitset(SRV_OFFER_VERB, features) ||
bitset(PRIV_NOVERB, PrivacyFlags))
{
/* this would give out the same info */
message("502 5.7.0 Verbose unavailable");
break;
}
- (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
+ (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true,
"VERB", e);
Verbose = 1;
set_delivery_mode(SM_DELIVER, e);
message("250 2.0.0 Verbose mode");
break;
- case CMDONEX: /* doing one transaction only */
- (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
- "ONEX", e);
- OneXact = TRUE;
- message("250 2.0.0 Only one transaction");
- break;
-
- case CMDXUSR: /* initial (user) submission */
- (void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
- "XUSR", e);
- define(macid("{daemon_flags}", NULL), "c u", CurEnv);
- message("250 2.0.0 Initial submission");
- break;
-
-# if SMTPDEBUG
+#if SMTPDEBUG
case CMDDBGQSHOW: /* show queues */
- printf("Send Queue=");
- printaddr(e->e_sendqueue, TRUE);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Send Queue=");
+ printaddr(e->e_sendqueue, true);
break;
case CMDDBGDEBUG: /* set debug mode */
@@ -2278,11 +2640,12 @@ doquit:
message("200 2.0.0 Debug set");
break;
-# else /* SMTPDEBUG */
+#else /* SMTPDEBUG */
case CMDDBGQSHOW: /* show queues */
case CMDDBGDEBUG: /* set debug mode */
-# endif /* SMTPDEBUG */
+#endif /* SMTPDEBUG */
case CMDLOGBOGUS: /* bogus command */
+ DELAY_CONN("Bogus");
if (LogLevel > 0)
sm_syslog(LOG_CRIT, e->e_id,
"\"%s\" command from %.100s (%.100s)",
@@ -2291,7 +2654,8 @@ doquit:
/* FALLTHROUGH */
case CMDERROR: /* unknown command */
- if (++badcommands > MAXBADCOMMANDS)
+#if MAXBADCOMMANDS > 0
+ if (++n_badcmds > MAXBADCOMMANDS)
{
message("421 4.7.0 %s Too many bad commands; closing connection",
MyHostName);
@@ -2300,28 +2664,439 @@ doquit:
e->e_sendqueue = NULL;
goto doquit;
}
+#endif /* MAXBADCOMMANDS > 0 */
usrerr("500 5.5.1 Command unrecognized: \"%s\"",
shortenstring(inp, MAXSHORTSTR));
break;
case CMDUNIMPL:
+ DELAY_CONN("Unimpl");
usrerr("502 5.5.1 Command not implemented: \"%s\"",
shortenstring(inp, MAXSHORTSTR));
break;
default:
+ DELAY_CONN("default");
errno = 0;
syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code);
break;
}
-# if SASL
+#if SASL
}
-# endif /* SASL */
+#endif /* SASL */
+ }
+ SM_EXCEPT(exc, "[!F]*")
+ {
+ /*
+ ** The only possible exception is "E:mta.quickabort".
+ ** There is nothing to do except fall through and loop.
+ */
+ }
+ SM_END_TRY
}
+}
+/*
+** SMTP_DATA -- implement the SMTP DATA command.
+**
+** Parameters:
+** smtp -- status of SMTP connection.
+** e -- envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** possibly sends message.
+*/
+
+static void
+smtp_data(smtp, e)
+ SMTP_T *smtp;
+ ENVELOPE *e;
+{
+#if MILTER
+ bool milteraccept;
+#endif /* MILTER */
+ bool aborting;
+ bool doublequeue;
+ ADDRESS *a;
+ ENVELOPE *ee;
+ char *id;
+ char buf[32];
+
+ SmtpPhase = "server DATA";
+ if (!smtp->sm_gotmail)
+ {
+ usrerr("503 5.0.0 Need MAIL command");
+ return;
+ }
+ else if (smtp->sm_nrcpts <= 0)
+ {
+ usrerr("503 5.0.0 Need RCPT (recipient)");
+ return;
+ }
+ (void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts);
+ if (rscheck("check_data", buf, NULL, e,
+ true, false, 3, NULL, e->e_id) != EX_OK)
+ return;
+
+ /* put back discard bit */
+ if (smtp->sm_discard)
+ e->e_flags |= EF_DISCARD;
+
+ /* check to see if we need to re-expand aliases */
+ /* also reset QS_BADADDR on already-diagnosted addrs */
+ doublequeue = false;
+ for (a = e->e_sendqueue; a != NULL; a = a->q_next)
+ {
+ if (QS_IS_VERIFIED(a->q_state) &&
+ !bitset(EF_DISCARD, e->e_flags))
+ {
+ /* need to re-expand aliases */
+ doublequeue = true;
+ }
+ if (QS_IS_BADADDR(a->q_state))
+ {
+ /* make this "go away" */
+ a->q_state = QS_DONTSEND;
+ }
+ }
+
+ /* collect the text of the message */
+ SmtpPhase = "collect";
+ buffer_errors();
+
+#if _FFR_ADAPTIVE_EOL
+ /* triggers error in collect, disabled for now */
+ if (smtp->sm_crlf)
+ e->e_flags |= EF_NL_NOT_EOL;
+#endif /* _FFR_ADAPTIVE_EOL */
+
+ collect(InChannel, true, NULL, e);
+
+ /* redefine message size */
+ (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
+ macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
+
+#if _FFR_CHECK_EOM
+ /* rscheck() will set Errors or EF_DISCARD if it trips */
+ (void) rscheck("check_eom", buf, NULL, e, false,
+ true, 3, NULL, e->e_id);
+#endif /* _FFR_CHECK_EOM */
+
+#if MILTER
+ milteraccept = true;
+ if (smtp->sm_milterlist && smtp->sm_milterize &&
+ Errors <= 0 &&
+ !bitset(EF_DISCARD, e->e_flags))
+ {
+ char state;
+ char *response;
+
+ response = milter_data(e, &state);
+ switch (state)
+ {
+ case SMFIR_REPLYCODE:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: data, reject=%s",
+ response);
+ milteraccept = false;
+ usrerr(response);
+ break;
+
+ case SMFIR_REJECT:
+ milteraccept = false;
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: data, reject=554 5.7.1 Command rejected");
+ usrerr("554 5.7.1 Command rejected");
+ break;
+
+ case SMFIR_DISCARD:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: data, discard");
+ milteraccept = false;
+ e->e_flags |= EF_DISCARD;
+ break;
+
+ case SMFIR_TEMPFAIL:
+ if (MilterLogLevel > 3)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Milter: data, reject=%s",
+ MSG_TEMPFAIL);
+ milteraccept = false;
+ usrerr(MSG_TEMPFAIL);
+ break;
+ }
+ if (response != NULL)
+ sm_free(response);
+ }
+
+ /* Milter may have changed message size */
+ (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
+ macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
+
+ /* abort message filters that didn't get the body & log msg is OK */
+ if (smtp->sm_milterlist && smtp->sm_milterize)
+ {
+ milter_abort(e);
+ if (milteraccept && MilterLogLevel > 9)
+ sm_syslog(LOG_INFO, e->e_id, "Milter accept: message");
+ }
+#endif /* MILTER */
+
+#if _FFR_QUARANTINE
+ /* Check if quarantining stats should be updated */
+ if (e->e_quarmsg != NULL)
+ markstats(e, NULL, STATS_QUARANTINE);
+#endif /* _FFR_QUARANTINE */
+
+ /*
+ ** If a header/body check (header checks or milter)
+ ** set EF_DISCARD, don't queueup the message --
+ ** that would lose the EF_DISCARD bit and deliver
+ ** the message.
+ */
+
+ if (bitset(EF_DISCARD, e->e_flags))
+ doublequeue = false;
+
+ aborting = Errors > 0;
+ if (!aborting &&
+#if _FFR_QUARANTINE
+ (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) &&
+#endif /* _FFR_QUARANTINE */
+ !split_by_recipient(e))
+ aborting = bitset(EF_FATALERRS, e->e_flags);
+
+ if (aborting)
+ {
+ /* Log who the mail would have gone to */
+ logundelrcpts(e, e->e_message, 8, false);
+ flush_errors(true);
+ buffer_errors();
+ goto abortmessage;
+ }
+
+ /* from now on, we have to operate silently */
+ buffer_errors();
+
+#if 0
+ /*
+ ** Clear message, it may contain an error from the SMTP dialogue.
+ ** This error must not show up in the queue.
+ ** Some error message should show up, e.g., alias database
+ ** not available, but others shouldn't, e.g., from check_rcpt.
+ */
+
+ e->e_message = NULL;
+#endif /* 0 */
+
+ /*
+ ** Arrange to send to everyone.
+ ** If sending to multiple people, mail back
+ ** errors rather than reporting directly.
+ ** In any case, don't mail back errors for
+ ** anything that has happened up to
+ ** now (the other end will do this).
+ ** Truncate our transcript -- the mail has gotten
+ ** to us successfully, and if we have
+ ** to mail this back, it will be easier
+ ** on the reader.
+ ** Then send to everyone.
+ ** Finally give a reply code. If an error has
+ ** already been given, don't mail a
+ ** message back.
+ ** We goose error returns by clearing error bit.
+ */
+
+ SmtpPhase = "delivery";
+ (void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL);
+ id = e->e_id;
+
+#if NAMED_BIND
+ _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
+ _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
+#endif /* NAMED_BIND */
+
+ for (ee = e; ee != NULL; ee = ee->e_sibling)
+ {
+ /* make sure we actually do delivery */
+ ee->e_flags &= ~EF_CLRQUEUE;
+
+ /* from now on, operate silently */
+ ee->e_errormode = EM_MAIL;
+
+ if (doublequeue)
+ {
+ /* make sure it is in the queue */
+ queueup(ee, false, true);
+ }
+ else
+ {
+ /* send to all recipients */
+ sendall(ee, SM_DEFAULT);
+ }
+ ee->e_to = NULL;
+ }
+
+ /* issue success message */
+ message("250 2.0.0 %s Message accepted for delivery", id);
+
+ /* if we just queued, poke it */
+ if (doublequeue)
+ {
+ bool anything_to_send = false;
+
+ sm_getla();
+ for (ee = e; ee != NULL; ee = ee->e_sibling)
+ {
+ if (WILL_BE_QUEUED(ee->e_sendmode))
+ continue;
+ if (shouldqueue(ee->e_msgpriority, ee->e_ctime))
+ {
+ ee->e_sendmode = SM_QUEUE;
+ continue;
+ }
+#if _FFR_QUARANTINE
+ else if (QueueMode != QM_QUARANTINE &&
+ ee->e_quarmsg != NULL)
+ {
+ ee->e_sendmode = SM_QUEUE;
+ continue;
+ }
+#endif /* _FFR_QUARANTINE */
+ anything_to_send = true;
+
+ /* close all the queue files */
+ closexscript(ee);
+ if (ee->e_dfp != NULL)
+ {
+ (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT);
+ ee->e_dfp = NULL;
+ }
+ unlockqueue(ee);
+ }
+ if (anything_to_send)
+ {
+#if PIPELINING
+ /*
+ ** XXX if we don't do this, we get 250 twice
+ ** because it is also flushed in the child.
+ */
+
+ (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
+#endif /* PIPELINING */
+ (void) doworklist(e, true, true);
+ }
+ }
+
+ abortmessage:
+ if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
+ logsender(e, NULL);
+ e->e_flags &= ~EF_LOGSENDER;
+
+ /* clean up a bit */
+ smtp->sm_gotmail = false;
+
+ /*
+ ** Call dropenvelope if and only if the envelope is *not*
+ ** being processed by the child process forked by doworklist().
+ */
+
+ if (aborting || bitset(EF_DISCARD, e->e_flags))
+ dropenvelope(e, true, false);
+ else
+ {
+ for (ee = e; ee != NULL; ee = ee->e_sibling)
+ {
+#if _FFR_QUARANTINE
+ if (!doublequeue &&
+ QueueMode != QM_QUARANTINE &&
+ ee->e_quarmsg != NULL)
+ {
+ dropenvelope(ee, true, false);
+ continue;
+ }
+#endif /* _FFR_QUARANTINE */
+ if (WILL_BE_QUEUED(ee->e_sendmode))
+ dropenvelope(ee, true, false);
+ }
+ }
+ sm_rpool_free(e->e_rpool);
+
+ /*
+ ** At this point, e == &MainEnvelope, but if we did splitting,
+ ** then CurEnv may point to an envelope structure that was just
+ ** freed with the rpool. So reset CurEnv *before* calling
+ ** newenvelope.
+ */
+
+ CurEnv = e;
+ newenvelope(e, e, sm_rpool_new_x(NULL));
+ e->e_flags = BlankEnvelope.e_flags;
+
+#if _FFR_QUARANTINE
+ /* restore connection quarantining */
+ if (smtp->sm_quarmsg == NULL)
+ {
+ e->e_quarmsg = NULL;
+ macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
+ }
+ else
+ {
+ e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{quarantine}"), e->e_quarmsg);
+ }
+#endif /* _FFR_QUARANTINE */
+}
+/*
+** LOGUNDELRCPTS -- log undelivered (or all) recipients.
+**
+** Parameters:
+** e -- envelope.
+** msg -- message for Stat=
+** level -- log level.
+** all -- log all recipients.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** logs undelivered (or all) recipients
+*/
+
+void
+logundelrcpts(e, msg, level, all)
+ ENVELOPE *e;
+ char *msg;
+ int level;
+ bool all;
+{
+ ADDRESS *a;
+
+ if (LogLevel <= level || msg == NULL || *msg == '\0')
+ return;
+
+ /* Clear $h so relay= doesn't get mislogged by logdelivery() */
+ macdefine(&e->e_macro, A_PERM, 'h', NULL);
+ /* Log who the mail would have gone to */
+ for (a = e->e_sendqueue; a != NULL; a = a->q_next)
+ {
+ if (!QS_IS_UNDELIVERED(a->q_state) && !all)
+ continue;
+ e->e_to = a->q_paddr;
+ logdelivery(NULL, NULL, a->q_status, msg, NULL,
+ (time_t) 0, e);
+ }
+ e->e_to = NULL;
}
- /*
+/*
** CHECKSMTPATTACK -- check for denial-of-service attack by repetition
**
** Parameters:
@@ -2341,12 +3116,15 @@ doquit:
static time_t
checksmtpattack(pcounter, maxcount, waitnow, cname, e)
- volatile int *pcounter;
+ volatile unsigned int *pcounter;
int maxcount;
bool waitnow;
char *cname;
ENVELOPE *e;
{
+ if (maxcount <= 0) /* no limit */
+ return (time_t) 0;
+
if (++(*pcounter) >= maxcount)
{
time_t s;
@@ -2354,25 +3132,102 @@ checksmtpattack(pcounter, maxcount, waitnow, cname, e)
if (*pcounter == maxcount && LogLevel > 5)
{
sm_syslog(LOG_INFO, e->e_id,
- "%.100s: possible SMTP attack: command=%.40s, count=%d",
+ "%.100s: possible SMTP attack: command=%.40s, count=%u",
CurSmtpClient, cname, *pcounter);
}
s = 1 << (*pcounter - maxcount);
- if (s >= MAXTIMEOUT)
+ if (s >= MAXTIMEOUT || s <= 0)
s = MAXTIMEOUT;
+
/* sleep at least 1 second before returning */
(void) sleep(*pcounter / maxcount);
s -= *pcounter / maxcount;
if (waitnow)
{
(void) sleep(s);
- return(0);
+ return 0;
}
- return(s);
+ return s;
}
- return((time_t) 0);
+ return (time_t) 0;
}
- /*
+/*
+** SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server
+**
+** Parameters:
+** none.
+**
+** Returns:
+** nothing.
+**
+** Side Effects:
+** may change I/O fd.
+*/
+
+static void
+setup_smtpd_io()
+{
+ int inchfd, outchfd, outfd;
+
+ inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
+ outchfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
+ outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL);
+ if (outchfd != outfd)
+ {
+ /* arrange for debugging output to go to remote host */
+ (void) dup2(outchfd, outfd);
+ }
+
+ /*
+ ** if InChannel and OutChannel are stdin/stdout
+ ** and connected to ttys
+ ** and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT,
+ ** then "chain" them together.
+ */
+
+ if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO &&
+ isatty(inchfd) && isatty(outchfd))
+ {
+ int inmode, outmode;
+
+ inmode = fcntl(inchfd, F_GETFL, 0);
+ if (inmode == -1)
+ {
+ if (LogLevel > 11)
+ sm_syslog(LOG_INFO, NOQID,
+ "fcntl(inchfd, F_GETFL) failed: %s",
+ sm_errstring(errno));
+ return;
+ }
+ outmode = fcntl(outchfd, F_GETFL, 0);
+ if (outmode == -1)
+ {
+ if (LogLevel > 11)
+ sm_syslog(LOG_INFO, NOQID,
+ "fcntl(outchfd, F_GETFL) failed: %s",
+ sm_errstring(errno));
+ return;
+ }
+ if (bitset(O_NONBLOCK, inmode) ||
+ bitset(O_NONBLOCK, outmode) ||
+ fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1)
+ return;
+ outmode = fcntl(outchfd, F_GETFL, 0);
+ if (outmode != -1 && bitset(O_NONBLOCK, outmode))
+ {
+ /* changing InChannel also changes OutChannel */
+ sm_io_automode(OutChannel, InChannel);
+ if (tTd(97, 4) && LogLevel > 9)
+ sm_syslog(LOG_INFO, NOQID,
+ "set automode for I (%d)/O (%d) in SMTP server",
+ inchfd, outchfd);
+ }
+
+ /* undo change of inchfd */
+ (void) fcntl(inchfd, F_SETFL, inmode);
+ }
+}
+/*
** SKIPWORD -- skip a fixed word.
**
** Parameters:
@@ -2396,8 +3251,7 @@ skipword(p, w)
char *firstp = p;
/* find beginning of word */
- while (isascii(*p) && isspace(*p))
- p++;
+ SKIP_SPACE(p);
q = p;
/* find end of word */
@@ -2413,19 +3267,18 @@ skipword(p, w)
return NULL;
}
*p++ = '\0';
- while (isascii(*p) && isspace(*p))
- p++;
+ SKIP_SPACE(p);
if (*p == '\0')
goto syntax;
/* see if the input word matches desired word */
- if (strcasecmp(q, w))
+ if (sm_strcasecmp(q, w))
goto syntax;
return p;
}
- /*
+/*
** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
**
** Parameters:
@@ -2443,45 +3296,50 @@ mail_esmtp_args(kp, vp, e)
char *vp;
ENVELOPE *e;
{
- if (strcasecmp(kp, "size") == 0)
+ if (sm_strcasecmp(kp, "size") == 0)
{
if (vp == NULL)
{
usrerr("501 5.5.2 SIZE requires a value");
/* NOTREACHED */
}
- define(macid("{msg_size}", NULL), newstr(vp), e);
+ macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp);
+ errno = 0;
e->e_msgsize = strtol(vp, (char **) NULL, 10);
if (e->e_msgsize == LONG_MAX && errno == ERANGE)
{
usrerr("552 5.2.3 Message size exceeds maximum value");
/* NOTREACHED */
}
+ if (e->e_msgsize < 0)
+ {
+ usrerr("552 5.2.3 Message size invalid");
+ /* NOTREACHED */
+ }
}
- else if (strcasecmp(kp, "body") == 0)
+ else if (sm_strcasecmp(kp, "body") == 0)
{
if (vp == NULL)
{
usrerr("501 5.5.2 BODY requires a value");
/* NOTREACHED */
}
- else if (strcasecmp(vp, "8bitmime") == 0)
+ else if (sm_strcasecmp(vp, "8bitmime") == 0)
{
- SevenBitInput = FALSE;
+ SevenBitInput = false;
}
- else if (strcasecmp(vp, "7bit") == 0)
+ else if (sm_strcasecmp(vp, "7bit") == 0)
{
- SevenBitInput = TRUE;
+ SevenBitInput = true;
}
else
{
- usrerr("501 5.5.4 Unknown BODY type %s",
- vp);
+ usrerr("501 5.5.4 Unknown BODY type %s", vp);
/* NOTREACHED */
}
- e->e_bodytype = newstr(vp);
+ e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp);
}
- else if (strcasecmp(kp, "envid") == 0)
+ else if (sm_strcasecmp(kp, "envid") == 0)
{
if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
{
@@ -2503,10 +3361,11 @@ mail_esmtp_args(kp, vp, e)
usrerr("501 5.5.0 Duplicate ENVID parameter");
/* NOTREACHED */
}
- e->e_envid = newstr(vp);
- define(macid("{dsn_envid}", NULL), newstr(vp), e);
+ e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_envid}"), e->e_envid);
}
- else if (strcasecmp(kp, "ret") == 0)
+ else if (sm_strcasecmp(kp, "ret") == 0)
{
if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
{
@@ -2524,23 +3383,24 @@ mail_esmtp_args(kp, vp, e)
/* NOTREACHED */
}
e->e_flags |= EF_RET_PARAM;
- if (strcasecmp(vp, "hdrs") == 0)
+ if (sm_strcasecmp(vp, "hdrs") == 0)
e->e_flags |= EF_NO_BODY_RETN;
- else if (strcasecmp(vp, "full") != 0)
+ else if (sm_strcasecmp(vp, "full") != 0)
{
usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp);
/* NOTREACHED */
}
- define(macid("{dsn_ret}", NULL), newstr(vp), e);
+ macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp);
}
-# if SASL
- else if (strcasecmp(kp, "auth") == 0)
+#if SASL
+ else if (sm_strcasecmp(kp, "auth") == 0)
{
int len;
char *q;
char *auth_param; /* the value of the AUTH=x */
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
+ bool saveExitStat = ExitStat;
char pbuf[256];
if (vp == NULL)
@@ -2558,7 +3418,7 @@ mail_esmtp_args(kp, vp, e)
else
len = strlen(vp) + 1;
auth_param = xalloc(len);
- (void) strlcpy(auth_param, vp, len);
+ (void) sm_strlcpy(auth_param, vp, len);
if (!xtextok(auth_param))
{
usrerr("501 5.5.4 Syntax error in AUTH parameter value");
@@ -2567,11 +3427,11 @@ mail_esmtp_args(kp, vp, e)
}
/* XXX this might be cut off */
- snprintf(pbuf, sizeof pbuf, "%s", xuntextify(auth_param));
+ (void) sm_strlcpy(pbuf, xuntextify(auth_param), sizeof pbuf);
/* xalloc() the buffer instead? */
/* XXX define this always or only if trusted? */
- define(macid("{auth_author}", NULL), newstr(pbuf), e);
+ macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), pbuf);
/*
** call Strust_auth to find out whether
@@ -2580,42 +3440,123 @@ mail_esmtp_args(kp, vp, e)
** (required by RFC, leave it to ruleset?)
*/
- SuprErrs = TRUE;
- QuickAbort = FALSE;
+ SuprErrs = true;
+ QuickAbort = false;
if (strcmp(auth_param, "<>") != 0 &&
- (rscheck("trust_auth", pbuf, NULL, e, TRUE, FALSE, 10,
- NULL) != EX_OK || Errors > 0))
+ (rscheck("trust_auth", pbuf, NULL, e, true, false, 9,
+ NULL, NOQID) != EX_OK || Errors > 0))
{
if (tTd(95, 8))
{
q = e->e_auth_param;
- dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n",
+ sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n",
pbuf, (q == NULL) ? "" : q);
}
+
/* not trusted */
- e->e_auth_param = newstr("<>");
+ e->e_auth_param = "<>";
+# if _FFR_AUTH_PASSING
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{auth_author}"), NULL);
+# endif /* _FFR_AUTH_PASSING */
}
else
{
if (tTd(95, 8))
- dprintf("auth=\"%.100s\" trusted\n", pbuf);
- e->e_auth_param = newstr(auth_param);
+ sm_dprintf("auth=\"%.100s\" trusted\n", pbuf);
+ e->e_auth_param = sm_rpool_strdup_x(e->e_rpool,
+ auth_param);
}
- sm_free(auth_param);
+ sm_free(auth_param); /* XXX */
/* reset values */
Errors = 0;
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
+ ExitStat = saveExitStat;
+ }
+#endif /* SASL */
+#define PRTCHAR(c) ((isascii(c) && isprint(c)) ? (c) : '?')
+
+ /*
+ ** "by" is only accepted if DeliverByMin >= 0.
+ ** We maybe could add this to the list of server_features.
+ */
+
+ else if (sm_strcasecmp(kp, "by") == 0 && DeliverByMin >= 0)
+ {
+ char *s;
+
+ if (vp == NULL)
+ {
+ usrerr("501 5.5.2 BY= requires a value");
+ /* NOTREACHED */
+ }
+ errno = 0;
+ e->e_deliver_by = strtol(vp, &s, 10);
+ if (e->e_deliver_by == LONG_MIN ||
+ e->e_deliver_by == LONG_MAX ||
+ e->e_deliver_by > 999999999l ||
+ e->e_deliver_by < -999999999l)
+ {
+ usrerr("501 5.5.2 BY=%s out of range", vp);
+ /* NOTREACHED */
+ }
+ if (s == NULL || *s != ';')
+ {
+ usrerr("501 5.5.2 BY= missing ';'");
+ /* NOTREACHED */
+ }
+ e->e_dlvr_flag = 0;
+ ++s; /* XXX: spaces allowed? */
+ SKIP_SPACE(s);
+ switch (tolower(*s))
+ {
+ case 'n':
+ e->e_dlvr_flag = DLVR_NOTIFY;
+ break;
+ case 'r':
+ e->e_dlvr_flag = DLVR_RETURN;
+ if (e->e_deliver_by <= 0)
+ {
+ usrerr("501 5.5.4 mode R requires BY time > 0");
+ /* NOTREACHED */
+ }
+ if (DeliverByMin > 0 && e->e_deliver_by > 0 &&
+ e->e_deliver_by < DeliverByMin)
+ {
+ usrerr("555 5.5.2 time %ld less than %ld",
+ e->e_deliver_by, (long) DeliverByMin);
+ /* NOTREACHED */
+ }
+ break;
+ default:
+ usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s));
+ /* NOTREACHED */
+ }
+ ++s; /* XXX: spaces allowed? */
+ SKIP_SPACE(s);
+ switch (tolower(*s))
+ {
+ case 't':
+ e->e_dlvr_flag |= DLVR_TRACE;
+ break;
+ case '\0':
+ break;
+ default:
+ usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s));
+ /* NOTREACHED */
+ }
+
+ /* XXX: check whether more characters follow? */
}
-# endif /* SASL */
else
{
usrerr("555 5.5.4 %s parameter unrecognized", kp);
/* NOTREACHED */
}
}
- /*
+/*
** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
**
** Parameters:
@@ -2635,7 +3576,7 @@ rcpt_esmtp_args(a, kp, vp, e)
char *vp;
ENVELOPE *e;
{
- if (strcasecmp(kp, "notify") == 0)
+ if (sm_strcasecmp(kp, "notify") == 0)
{
char *p;
@@ -2651,20 +3592,20 @@ rcpt_esmtp_args(a, kp, vp, e)
}
a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
a->q_flags |= QHASNOTIFY;
- define(macid("{dsn_notify}", NULL), newstr(vp), e);
+ macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp);
- if (strcasecmp(vp, "never") == 0)
+ if (sm_strcasecmp(vp, "never") == 0)
return;
for (p = vp; p != NULL; vp = p)
{
p = strchr(p, ',');
if (p != NULL)
*p++ = '\0';
- if (strcasecmp(vp, "success") == 0)
+ if (sm_strcasecmp(vp, "success") == 0)
a->q_flags |= QPINGONSUCCESS;
- else if (strcasecmp(vp, "failure") == 0)
+ else if (sm_strcasecmp(vp, "failure") == 0)
a->q_flags |= QPINGONFAILURE;
- else if (strcasecmp(vp, "delay") == 0)
+ else if (sm_strcasecmp(vp, "delay") == 0)
a->q_flags |= QPINGONDELAY;
else
{
@@ -2674,7 +3615,7 @@ rcpt_esmtp_args(a, kp, vp, e)
}
}
}
- else if (strcasecmp(kp, "orcpt") == 0)
+ else if (sm_strcasecmp(kp, "orcpt") == 0)
{
if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
{
@@ -2696,7 +3637,7 @@ rcpt_esmtp_args(a, kp, vp, e)
usrerr("501 5.5.0 Duplicate ORCPT parameter");
/* NOTREACHED */
}
- a->q_orcpt = newstr(vp);
+ a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp);
}
else
{
@@ -2704,11 +3645,11 @@ rcpt_esmtp_args(a, kp, vp, e)
/* NOTREACHED */
}
}
- /*
+/*
** PRINTVRFYADDR -- print an entry in the verify queue
**
** Parameters:
-** a -- the address to print
+** a -- the address to print.
** last -- set if this is the last one.
** vrfy -- set if this is a VRFY command.
**
@@ -2730,21 +3671,21 @@ printvrfyaddr(a, last, vrfy)
if (vrfy && a->q_mailer != NULL &&
!bitnset(M_VRFY250, a->q_mailer->m_flags))
- (void) strlcpy(fmtbuf, "252", sizeof fmtbuf);
+ (void) sm_strlcpy(fmtbuf, "252", sizeof fmtbuf);
else
- (void) strlcpy(fmtbuf, "250", sizeof fmtbuf);
+ (void) sm_strlcpy(fmtbuf, "250", sizeof fmtbuf);
fmtbuf[3] = last ? ' ' : '-';
- (void) strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4);
+ (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4);
if (a->q_fullname == NULL)
{
if ((a->q_mailer == NULL ||
a->q_mailer->m_addrtype == NULL ||
- strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
+ sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
strchr(a->q_user, '@') == NULL)
- (void) strlcpy(&fmtbuf[OFFF], "<%s@%s>",
+ (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>",
sizeof fmtbuf - OFFF);
else
- (void) strlcpy(&fmtbuf[OFFF], "<%s>",
+ (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>",
sizeof fmtbuf - OFFF);
message(fmtbuf, a->q_user, MyHostName);
}
@@ -2752,127 +3693,27 @@ printvrfyaddr(a, last, vrfy)
{
if ((a->q_mailer == NULL ||
a->q_mailer->m_addrtype == NULL ||
- strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
+ sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
strchr(a->q_user, '@') == NULL)
- (void) strlcpy(&fmtbuf[OFFF], "%s <%s@%s>",
+ (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>",
sizeof fmtbuf - OFFF);
else
- (void) strlcpy(&fmtbuf[OFFF], "%s <%s>",
+ (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>",
sizeof fmtbuf - OFFF);
message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
}
}
- /*
-** RUNINCHILD -- return twice -- once in the child, then in the parent again
-**
-** Parameters:
-** label -- a string used in error messages
-**
-** Returns:
-** RIC_INCHILD in the child
-** RIC_INPARENT in the parent
-** RIC_TEMPFAIL tempfail condition
-**
-** Side Effects:
-** none.
-*/
-
-static int
-runinchild(label, e)
- char *label;
- register ENVELOPE *e;
-{
- pid_t childpid;
-
- if (!OneXact)
- {
- extern int NumQueues;
- /*
- ** advance state of PRNG
- ** this is necessary because otherwise all child processes
- ** will produce the same PRN sequence and hence the selection
- ** of a queue directory is not "really" random.
- */
- if (NumQueues > 1)
- (void) get_random();
-
- /*
- ** Disable child process reaping, in case ETRN has preceded
- ** MAIL command, and then fork.
- */
-
- (void) blocksignal(SIGCHLD);
-
-
- childpid = dofork();
- if (childpid < 0)
- {
- syserr("451 4.3.0 %s: cannot fork", label);
- (void) releasesignal(SIGCHLD);
- return RIC_INPARENT;
- }
- if (childpid > 0)
- {
- auto int st;
-
- /* parent -- wait for child to complete */
- sm_setproctitle(TRUE, e, "server %s child wait",
- CurSmtpClient);
- st = waitfor(childpid);
- if (st == -1)
- syserr("451 4.3.0 %s: lost child", label);
- else if (!WIFEXITED(st))
- {
- syserr("451 4.3.0 %s: died on signal %d",
- label, st & 0177);
- return RIC_TEMPFAIL;
- }
-
- /* if exited on a QUIT command, complete the process */
- if (WEXITSTATUS(st) == EX_QUIT)
- {
- disconnect(1, e);
- finis(TRUE, ExitStat);
- }
-
- /* restore the child signal */
- (void) releasesignal(SIGCHLD);
-
- return RIC_INPARENT;
- }
- else
- {
- /* child */
- InChild = TRUE;
- QuickAbort = FALSE;
-
- /* Reset global flags */
- RestartRequest = NULL;
- ShutdownRequest = NULL;
- PendingSignal = 0;
-
- clearstats();
- clearenvelope(e, FALSE);
- assign_queueid(e);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) releasesignal(SIGCHLD);
- }
- }
- return RIC_INCHILD;
-}
-
-# if SASL
-
- /*
+#if SASL
+/*
** SASLMECHS -- get list of possible AUTH mechanisms
**
** Parameters:
-** conn -- SASL connection info
-** mechlist -- output parameter for list of mechanisms
+** conn -- SASL connection info.
+** mechlist -- output parameter for list of mechanisms.
**
** Returns:
-** number of mechs
+** number of mechs.
*/
static int
@@ -2885,35 +3726,41 @@ saslmechs(conn, mechlist)
/* "user" is currently unused */
result = sasl_listmech(conn, "user", /* XXX */
"", " ", "", mechlist,
- (u_int *)&len, (u_int *)&num);
- if (result == SASL_OK && num > 0)
+ (unsigned int *)&len, (unsigned int *)&num);
+ if (result != SASL_OK)
+ {
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, NOQID,
+ "AUTH error: listmech=%d, num=%d",
+ result, num);
+ num = 0;
+ }
+ if (num > 0)
{
if (LogLevel > 11)
sm_syslog(LOG_INFO, NOQID,
- "SASL: available mech=%s, allowed mech=%s",
+ "AUTH: available mech=%s, allowed mech=%s",
*mechlist, AuthMechanisms);
- *mechlist = intersect(AuthMechanisms, *mechlist);
+ *mechlist = intersect(AuthMechanisms, *mechlist, NULL);
}
else
{
- if (LogLevel > 9)
+ *mechlist = NULL; /* be paranoid... */
+ if (result == SASL_OK && LogLevel > 9)
sm_syslog(LOG_WARNING, NOQID,
- "SASL error: listmech=%d, num=%d",
- result, num);
- num = 0;
+ "AUTH warning: no mechanisms");
}
return num;
}
-
- /*
+/*
** PROXY_POLICY -- define proxy policy for AUTH
**
** Parameters:
-** conntext -- unused
-** auth_identity -- authentication identity
-** requested_user -- authorization identity
-** user -- allowed user (output)
-** errstr -- possible error string (output)
+** context -- unused.
+** auth_identity -- authentication identity.
+** requested_user -- authorization identity.
+** user -- allowed user (output).
+** errstr -- possible error string (output).
**
** Returns:
** ok?
@@ -2932,1275 +3779,139 @@ proxy_policy(context, auth_identity, requested_user, user, errstr)
*user = newstr(auth_identity);
return SASL_OK;
}
+#endif /* SASL */
-# endif /* SASL */
-
-# if STARTTLS
-# if !TLS_NO_RSA
-RSA *rsa_tmp; /* temporary RSA key */
-static RSA * tmp_rsa_key __P((SSL *, int, int));
-# endif /* !TLS_NO_RSA */
-
-# if !NO_DH
-static DH *get_dh512 __P((void));
-
-static unsigned char dh512_p[] =
-{
- 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
- 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
- 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
- 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
- 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
- 0x47,0x74,0xE8,0x33
-};
-static unsigned char dh512_g[] =
-{
- 0x02
-};
-
-static DH *
-get_dh512()
-{
- DH *dh = NULL;
-
- if ((dh = DH_new()) == NULL)
- return(NULL);
- dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
- dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
- if ((dh->p == NULL) || (dh->g == NULL))
- return(NULL);
- return(dh);
-}
-# endif /* !NO_DH */
-
- /*
-** TLS_RAND_INIT -- initialize STARTTLS random generator
-**
-** Parameters:
-** randfile -- name of file with random data
-** logl -- loglevel
-**
-** Returns:
-** success/failure
-**
-** Side Effects:
-** initializes PRNG for tls library.
-*/
-
-#define MIN_RAND_BYTES 16 /* 128 bits */
-
-bool
-tls_rand_init(randfile, logl)
- char *randfile;
- int logl;
-{
-# ifndef HASURANDOMDEV
- /* not required if /dev/urandom exists, OpenSSL does it internally */
-#define RF_OK 0 /* randfile OK */
-#define RF_MISS 1 /* randfile == NULL || *randfile == '\0' */
-#define RF_UNKNOWN 2 /* unknown prefix for randfile */
-
-#define RI_NONE 0 /* no init yet */
-#define RI_SUCCESS 1 /* init was successful */
-#define RI_FAIL 2 /* init failed */
-
- bool ok;
- int randdef;
- static int done = RI_NONE;
-
- /*
- ** initialize PRNG
- */
-
- /* did we try this before? if yes: return old value */
- if (done != RI_NONE)
- return done == RI_SUCCESS;
-
- /* set default values */
- ok = FALSE;
- done = RI_FAIL;
- randdef = (randfile == NULL || *randfile == '\0') ? RF_MISS : RF_OK;
-# if EGD
- if (randdef == RF_OK && strncasecmp(randfile, "egd:", 4) == 0)
- {
- randfile += 4;
- if (RAND_egd(randfile) < 0)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: RAND_egd(%s) failed: random number generator not seeded",
- randfile);
- }
- else
- ok = TRUE;
- }
- else
-# endif /* EGD */
- if (randdef == RF_OK && strncasecmp(randfile, "file:", 5) == 0)
- {
- int fd;
- long sff;
- struct stat st;
-
- randfile += 5;
- sff = SFF_SAFEDIRPATH | SFF_NOWLINK
- | SFF_NOGWFILES | SFF_NOWWFILES
- | SFF_NOGRFILES | SFF_NOWRFILES
- | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
- if ((fd = safeopen(randfile, O_RDONLY, 0, sff)) >= 0)
- {
- if (fstat(fd, &st) < 0)
- {
- if (LogLevel > logl)
- sm_syslog(LOG_ERR, NOQID,
- "TLS: can't fstat(%s)",
- randfile);
- }
- else
- {
- bool use, problem;
-
- use = TRUE;
- problem = FALSE;
- if (st.st_mtime + 600 < curtime())
- {
- use = bitnset(DBS_INSUFFICIENTENTROPY,
- DontBlameSendmail);
- problem = TRUE;
- if (LogLevel > logl)
- sm_syslog(LOG_ERR, NOQID,
- "TLS: RandFile %s too old: %s",
- randfile,
- use ? "unsafe" :
- "unusable");
- }
- if (use && st.st_size < MIN_RAND_BYTES)
- {
- use = bitnset(DBS_INSUFFICIENTENTROPY,
- DontBlameSendmail);
- problem = TRUE;
- if (LogLevel > logl)
- sm_syslog(LOG_ERR, NOQID,
- "TLS: size(%s) < %d: %s",
- randfile,
- MIN_RAND_BYTES,
- use ? "unsafe" :
- "unusable");
- }
- if (use)
- ok = RAND_load_file(randfile, -1) >=
- MIN_RAND_BYTES;
- if (use && !ok)
- {
- if (LogLevel > logl)
- sm_syslog(LOG_WARNING,
- NOQID,
- "TLS: RAND_load_file(%s) failed: random number generator not seeded",
- randfile);
- }
- if (problem)
- ok = FALSE;
- }
- if (ok || bitnset(DBS_INSUFFICIENTENTROPY,
- DontBlameSendmail))
- {
- /* add this even if fstat() failed */
- RAND_seed((void *) &st, sizeof st);
- }
- (void) close(fd);
- }
- else
- {
- if (LogLevel > logl)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: Warning: safeopen(%s) failed",
- randfile);
- }
- }
- else if (randdef == RF_OK)
- {
- if (LogLevel > logl)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: Error: no proper random file definition %s",
- randfile);
- randdef = RF_UNKNOWN;
- }
- if (randdef == RF_MISS)
- {
- if (LogLevel > logl)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: Error: missing random file definition");
- }
- if (!ok && bitnset(DBS_INSUFFICIENTENTROPY, DontBlameSendmail))
- {
- int i;
- long r;
- unsigned char buf[MIN_RAND_BYTES];
-
- /* assert((MIN_RAND_BYTES % sizeof(long)) == 0); */
- for (i = 0; i <= sizeof(buf) - sizeof(long); i += sizeof(long))
- {
- r = get_random();
- (void) memcpy(buf + i, (void *) &r, sizeof(long));
- }
- RAND_seed(buf, sizeof buf);
- if (LogLevel > logl)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: Warning: random number generator not properly seeded");
- ok = TRUE;
- }
- done = ok ? RI_SUCCESS : RI_FAIL;
- return ok;
-# else /* !HASURANDOMDEV */
- return TRUE;
-# endif /* !HASURANDOMDEV */
-}
-
+#if STARTTLS
/*
-** status in initialization
-** these flags keep track of the status of the initialization
-** i.e., whether a file exists (_EX) and whether it can be used (_OK)
-** [due to permissions]
-*/
-#define TLS_S_NONE 0x00000000 /* none yet */
-#define TLS_S_CERT_EX 0x00000001 /* CERT file exists */
-#define TLS_S_CERT_OK 0x00000002 /* CERT file is ok */
-#define TLS_S_KEY_EX 0x00000004 /* KEY file exists */
-#define TLS_S_KEY_OK 0x00000008 /* KEY file is ok */
-#define TLS_S_CERTP_EX 0x00000010 /* CA CERT PATH exists */
-#define TLS_S_CERTP_OK 0x00000020 /* CA CERT PATH is ok */
-#define TLS_S_CERTF_EX 0x00000040 /* CA CERT FILE exists */
-#define TLS_S_CERTF_OK 0x00000080 /* CA CERT FILE is ok */
-
-# if _FFR_TLS_1
-#define TLS_S_CERT2_EX 0x00001000 /* 2nd CERT file exists */
-#define TLS_S_CERT2_OK 0x00002000 /* 2nd CERT file is ok */
-#define TLS_S_KEY2_EX 0x00004000 /* 2nd KEY file exists */
-#define TLS_S_KEY2_OK 0x00008000 /* 2nd KEY file is ok */
-# endif /* _FFR_TLS_1 */
-
-#define TLS_S_DH_OK 0x00200000 /* DH cert is ok */
-#define TLS_S_DHPAR_EX 0x00400000 /* DH param file exists */
-#define TLS_S_DHPAR_OK 0x00800000 /* DH param file is ok to use */
-
- /*
-** TLS_OK_F -- can var be an absolute filename?
-**
-** Parameters:
-** var -- filename
-** fn -- what is the filename used for?
-**
-** Returns:
-** ok?
-*/
-
-static bool
-tls_ok_f(var, fn)
- char *var;
- char *fn;
-{
- /* must be absolute pathname */
- if (var != NULL && *var == '/')
- return TRUE;
- if (LogLevel > 12)
- sm_syslog(LOG_WARNING, NOQID, "TLS: file %s missing", fn);
- return FALSE;
-}
-
- /*
-** TLS_SAFE_F -- is a file safe to use?
-**
-** Parameters:
-** var -- filename
-** sff -- flags for safefile()
-**
-** Returns:
-** ok?
-*/
-
-static bool
-tls_safe_f(var, sff)
- char *var;
- long sff;
-{
- int ret;
-
- if ((ret = safefile(var, RunAsUid, RunAsGid, RunAsUserName, sff,
- S_IRUSR, NULL)) == 0)
- return TRUE;
- if (LogLevel > 7)
- sm_syslog(LOG_WARNING, NOQID, "TLS: file %s unsafe: %s",
- var, errstring(ret));
- return FALSE;
-}
-
-/*
-** TLS_OK_F -- macro to simplify calls to tls_ok_f
-**
-** Parameters:
-** var -- filename
-** fn -- what is the filename used for?
-** req -- is the file required?
-** st -- status bit to set if ok
-**
-** Side Effects:
-** uses r, ok; may change ok and status.
-**
-*/
-
-#define TLS_OK_F(var, fn, req, st) if (ok) \
- { \
- r = tls_ok_f(var, fn); \
- if (r) \
- status |= st; \
- else if (req) \
- ok = FALSE; \
- }
-
-/*
-** TLS_UNR -- macro to return whether a file should be unreadable
-**
-** Parameters:
-** bit -- flag to test
-** req -- flags
-**
-** Returns:
-** 0/SFF_NORFILES
-*/
-#define TLS_UNR(bit, req) (bitset(bit, req) ? SFF_NORFILES : 0)
-
-/*
-** TLS_SAFE_F -- macro to simplify calls to tls_safe_f
-**
-** Parameters:
-** var -- filename
-** sff -- flags for safefile()
-** req -- is the file required?
-** ex -- does the file exist?
-** st -- status bit to set if ok
-**
-** Side Effects:
-** uses r, ok, ex; may change ok and status.
-**
-*/
-
-#define TLS_SAFE_F(var, sff, req, ex, st) if (ex && ok) \
- { \
- r = tls_safe_f(var, sff); \
- if (r) \
- status |= st; \
- else if (req) \
- ok = FALSE; \
- }
- /*
-** INIT_TLS_LIBRARY -- calls functions which setup TLS library for global use
+** INITSRVTLS -- initialize server side TLS
**
** Parameters:
-** none.
+** tls_ok -- should tls initialization be done?
**
** Returns:
** succeeded?
**
** Side Effects:
-** Sets tls_ok_srv static, even when called from main()
+** sets tls_ok_srv which is a static variable in this module.
+** Do NOT remove assignments to it!
*/
bool
-init_tls_library()
+initsrvtls(tls_ok)
+ bool tls_ok;
{
- /*
- ** basic TLS initialization
- ** ignore result for now
- */
-
- SSL_library_init();
- SSL_load_error_strings();
-# if 0
- /* this is currently a macro for SSL_library_init */
- SSLeay_add_ssl_algorithms();
-# endif /* 0 */
-
- /* initialize PRNG */
- tls_ok_srv = tls_rand_init(RandFile, 7);
+ if (!tls_ok)
+ return false;
+ /* do NOT remove assignment */
+ tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, true, SrvCERTfile,
+ Srvkeyfile, CACERTpath, CACERTfile, DHParams);
return tls_ok_srv;
}
- /*
-** INITTLS -- initialize TLS
+#endif /* STARTTLS */
+/*
+** SRVFEATURES -- get features for SMTP server
**
** Parameters:
-** ctx -- pointer to context
-** req -- requirements for initialization (see sendmail.h)
-** srv -- server side?
-** certfile -- filename of certificate
-** keyfile -- filename of private key
-** cacertpath -- path to CAs
-** cacertfile -- file with CA
-** dhparam -- parameters for DH
+** e -- envelope (should be session context).
+** clientname -- name of client.
+** features -- default features for this invocation.
**
** Returns:
-** succeeded?
+** server features.
*/
-bool
-inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam)
- SSL_CTX **ctx;
- u_long req;
- bool srv;
- char *certfile, *keyfile, *cacertpath, *cacertfile, *dhparam;
+/* table with options: it uses just one character, how about strings? */
+static struct
{
-# if !NO_DH
- static DH *dh = NULL;
-# endif /* !NO_DH */
- int r;
- bool ok;
- long sff, status;
- char *who;
-# if _FFR_TLS_1
- char *cf2, *kf2;
-# endif /* _FFR_TLS_1 */
-
- status = TLS_S_NONE;
- who = srv ? "srv" : "clt";
- if (ctx == NULL)
- syserr("TLS: %s:inittls: ctx == NULL", who);
-
- /* already initialized? (we could re-init...) */
- if (*ctx != NULL)
- return TRUE;
-
- /* PRNG seeded? */
- if (!tls_rand_init(RandFile, 10))
- return FALSE;
-
- /* let's start with the assumption it will work */
- ok = TRUE;
-
-# if _FFR_TLS_1
- /*
- ** look for a second filename: it must be separated by a ','
- ** no blanks allowed (they won't be skipped).
- ** we change a global variable here! this change will be undone
- ** before return from the function but only if it returns TRUE.
- ** this isn't a problem since in a failure case this function
- ** won't be called again with the same (overwritten) values.
- ** otherwise each return must be replaced with a goto endinittls.
- */
- cf2 = NULL;
- kf2 = NULL;
- if (certfile != NULL && (cf2 = strchr(certfile, ',')) != NULL)
- {
- *cf2++ = '\0';
- if (keyfile != NULL && (kf2 = strchr(keyfile, ',')) != NULL)
- *kf2++ = '\0';
- }
-# endif /* _FFR_TLS_1 */
-
- /*
- ** what do we require from the client?
- ** must it have CERTs?
- ** introduce an option and decide based on that
- */
-
- TLS_OK_F(certfile, "CertFile", bitset(TLS_I_CERT_EX, req),
- TLS_S_CERT_EX);
- TLS_OK_F(keyfile, "KeyFile", bitset(TLS_I_KEY_EX, req),
- TLS_S_KEY_EX);
- TLS_OK_F(cacertpath, "CACERTPath", bitset(TLS_I_CERTP_EX, req),
- TLS_S_CERTP_EX);
- TLS_OK_F(cacertfile, "CACERTFile", bitset(TLS_I_CERTF_EX, req),
- TLS_S_CERTF_EX);
-
-# if _FFR_TLS_1
- if (cf2 != NULL)
- {
- TLS_OK_F(cf2, "CertFile", bitset(TLS_I_CERT_EX, req),
- TLS_S_CERT2_EX);
- }
- if (kf2 != NULL)
- {
- TLS_OK_F(kf2, "KeyFile", bitset(TLS_I_KEY_EX, req),
- TLS_S_KEY2_EX);
- }
-# endif /* _FFR_TLS_1 */
-
- /*
- ** valid values for dhparam are (only the first char is checked)
- ** none no parameters: don't use DH
- ** 512 generate 512 bit parameters (fixed)
- ** 1024 generate 1024 bit parameters
- ** /file/name read parameters from /file/name
- ** default is: 1024 for server, 512 for client (OK? XXX)
- */
- if (bitset(TLS_I_TRY_DH, req))
- {
- if (dhparam != NULL)
- {
- char c = *dhparam;
-
- if (c == '1')
- req |= TLS_I_DH1024;
- else if (c == '5')
- req |= TLS_I_DH512;
- else if (c != 'n' && c != 'N' && c != '/')
- {
- if (LogLevel > 12)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: illegal value '%s' for DHParam",
- dhparam);
- dhparam = NULL;
- }
- }
- if (dhparam == NULL)
- dhparam = srv ? "1" : "5";
- else if (*dhparam == '/')
- {
- TLS_OK_F(dhparam, "DHParameters",
- bitset(TLS_I_DHPAR_EX, req),
- TLS_S_DHPAR_EX);
- }
- }
- if (!ok)
- return ok;
-
- /* certfile etc. must be "safe". */
- sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
- | SFF_NOGWFILES | SFF_NOWWFILES
- | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
-
- TLS_SAFE_F(certfile, sff | TLS_UNR(TLS_I_CERT_UNR, req),
- bitset(TLS_I_CERT_EX, req),
- bitset(TLS_S_CERT_EX, status), TLS_S_CERT_OK);
- TLS_SAFE_F(keyfile, sff | TLS_UNR(TLS_I_KEY_UNR, req),
- bitset(TLS_I_KEY_EX, req),
- bitset(TLS_S_KEY_EX, status), TLS_S_KEY_OK);
- TLS_SAFE_F(cacertfile, sff | TLS_UNR(TLS_I_CERTF_UNR, req),
- bitset(TLS_I_CERTF_EX, req),
- bitset(TLS_S_CERTF_EX, status), TLS_S_CERTF_OK);
- TLS_SAFE_F(dhparam, sff | TLS_UNR(TLS_I_DHPAR_UNR, req),
- bitset(TLS_I_DHPAR_EX, req),
- bitset(TLS_S_DHPAR_EX, status), TLS_S_DHPAR_OK);
- if (!ok)
- return ok;
-# if _FFR_TLS_1
- if (cf2 != NULL)
- {
- TLS_SAFE_F(cf2, sff | TLS_UNR(TLS_I_CERT_UNR, req),
- bitset(TLS_I_CERT_EX, req),
- bitset(TLS_S_CERT2_EX, status), TLS_S_CERT2_OK);
- }
- if (kf2 != NULL)
- {
- TLS_SAFE_F(kf2, sff | TLS_UNR(TLS_I_KEY_UNR, req),
- bitset(TLS_I_KEY_EX, req),
- bitset(TLS_S_KEY2_EX, status), TLS_S_KEY2_OK);
- }
-# endif /* _FFR_TLS_1 */
-
- /* create a method and a new context */
- if (srv)
- {
- if ((*ctx = SSL_CTX_new(SSLv23_server_method())) == NULL)
- {
- if (LogLevel > 7)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: SSL_CTX_new(SSLv23_server_method()) failed");
- if (LogLevel > 9)
- tlslogerr();
- return FALSE;
- }
- }
- else
- {
- if ((*ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
- {
- if (LogLevel > 7)
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: SSL_CTX_new(SSLv23_client_method()) failed");
- if (LogLevel > 9)
- tlslogerr();
- return FALSE;
- }
- }
-
-# if TLS_NO_RSA
- /* turn off backward compatibility, required for no-rsa */
- SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2);
-# endif /* TLS_NO_RSA */
-
+ char srvf_opt;
+ unsigned int srvf_flag;
+} srv_feat_table[] =
+{
+ { 'A', SRV_OFFER_AUTH },
+ { 'B', SRV_OFFER_VERB },
+ { 'D', SRV_OFFER_DSN },
+ { 'E', SRV_OFFER_ETRN },
+ { 'L', SRV_REQ_AUTH }, /* not documented in 8.12 */
+#if PIPELINING
+# if _FFR_NO_PIPE
+ { 'N', SRV_NO_PIPE },
+# endif /* _FFR_NO_PIPE */
+ { 'P', SRV_OFFER_PIPE },
+#endif /* PIPELINING */
+ { 'R', SRV_VRFY_CLT },
+ { 'S', SRV_OFFER_TLS },
+/* { 'T', SRV_TMP_FAIL }, */
+ { 'V', SRV_VRFY_CLT },
+ { 'X', SRV_OFFER_EXPN },
+/* { 'Y', SRV_OFFER_VRFY }, */
+ { '\0', SRV_NONE }
+};
-# if !TLS_NO_RSA
- /*
- ** Create a temporary RSA key
- ** XXX Maybe we shouldn't create this always (even though it
- ** is only at startup).
- ** It is a time-consuming operation and it is not always necessary.
- ** maybe we should do it only on demand...
- */
- if (bitset(TLS_I_RSA_TMP, req) &&
- (rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL,
- NULL)) == NULL
- )
- {
- if (LogLevel > 7)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: RSA_generate_key failed",
- who);
- if (LogLevel > 9)
- tlslogerr();
- }
- return FALSE;
- }
-# endif /* !TLS_NO_RSA */
+static unsigned int
+srvfeatures(e, clientname, features)
+ ENVELOPE *e;
+ char *clientname;
+ unsigned int features;
+{
+ int r, i, j;
+ char **pvp, c, opt;
+ char pvpbuf[PSBUFSIZE];
+
+ pvp = NULL;
+ r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf,
+ sizeof(pvpbuf));
+ if (r != EX_OK)
+ return features;
+ if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
+ return features;
+ if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
+ return SRV_TMP_FAIL;
/*
- ** load private key
- ** XXX change this for DSA-only version
+ ** General rule (see sendmail.h, d_flags):
+ ** lower case: required/offered, upper case: Not required/available
+ **
+ ** Since we can change some features per daemon, we have both
+ ** cases here: turn on/off a feature.
*/
- if (bitset(TLS_S_KEY_OK, status) &&
- SSL_CTX_use_PrivateKey_file(*ctx, keyfile,
- SSL_FILETYPE_PEM) <= 0)
- {
- if (LogLevel > 7)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_use_PrivateKey_file(%s) failed",
- who, keyfile);
- if (LogLevel > 9)
- tlslogerr();
- }
- if (bitset(TLS_I_USE_KEY, req))
- return FALSE;
- }
-
- /* get the certificate file */
- if (bitset(TLS_S_CERT_OK, status) &&
- SSL_CTX_use_certificate_file(*ctx, certfile,
- SSL_FILETYPE_PEM) <= 0)
- {
- if (LogLevel > 7)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_use_certificate_file(%s) failed",
- who, certfile);
- if (LogLevel > 9)
- tlslogerr();
- }
- if (bitset(TLS_I_USE_CERT, req))
- return FALSE;
- }
-
- /* check the private key */
- if (bitset(TLS_S_KEY_OK, status) &&
- (r = SSL_CTX_check_private_key(*ctx)) <= 0)
- {
- /* Private key does not match the certificate public key */
- if (LogLevel > 5)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_check_private_key failed(%s): %d",
- who, keyfile, r);
- if (LogLevel > 9)
- tlslogerr();
- }
- if (bitset(TLS_I_USE_KEY, req))
- return FALSE;
- }
-# if _FFR_TLS_1
- /* XXX this code is pretty much duplicated from above! */
-
- /* load private key */
- if (bitset(TLS_S_KEY2_OK, status) &&
- SSL_CTX_use_PrivateKey_file(*ctx, kf2, SSL_FILETYPE_PEM) <= 0)
+ for (i = 1; pvp[i] != NULL; i++)
{
- if (LogLevel > 7)
+ c = pvp[i][0];
+ j = 0;
+ for (;;)
{
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_use_PrivateKey_file(%s) failed",
- who, kf2);
- if (LogLevel > 9)
- tlslogerr();
- }
- }
-
- /* get the certificate file */
- if (bitset(TLS_S_CERT2_OK, status) &&
- SSL_CTX_use_certificate_file(*ctx, cf2, SSL_FILETYPE_PEM) <= 0)
- {
- if (LogLevel > 7)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_use_certificate_file(%s) failed",
- who, cf2);
- if (LogLevel > 9)
- tlslogerr();
- }
- }
-
- /* we should also check the private key: */
- if (bitset(TLS_S_KEY2_OK, status) &&
- (r = SSL_CTX_check_private_key(*ctx)) <= 0)
- {
- /* Private key does not match the certificate public key */
- if (LogLevel > 5)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_check_private_key 2 failed: %d",
- who, r);
- if (LogLevel > 9)
- tlslogerr();
- }
- }
-# endif /* _FFR_TLS_1 */
-
- /* SSL_CTX_set_quiet_shutdown(*ctx, 1); violation of standard? */
- SSL_CTX_set_options(*ctx, SSL_OP_ALL); /* XXX bug compatibility? */
-
-# if !NO_DH
- /* Diffie-Hellman initialization */
- if (bitset(TLS_I_TRY_DH, req))
- {
- if (bitset(TLS_S_DHPAR_OK, status))
- {
- BIO *bio;
-
- if ((bio = BIO_new_file(dhparam, "r")) != NULL)
+ if ((opt = srv_feat_table[j].srvf_opt) == '\0')
{
- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
- BIO_free(bio);
- if (dh == NULL && LogLevel > 7)
- {
- u_long err;
-
- err = ERR_get_error();
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: cannot read DH parameters(%s): %s",
- who, dhparam,
- ERR_error_string(err, NULL));
- if (LogLevel > 9)
- tlslogerr();
- }
- }
- else
- {
- if (LogLevel > 5)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: BIO_new_file(%s) failed",
- who, dhparam);
- if (LogLevel > 9)
- tlslogerr();
- }
- }
- }
- if (dh == NULL && bitset(TLS_I_DH1024, req))
- {
- DSA *dsa;
-
- /* this takes a while! (7-130s on a 450MHz AMD K6-2) */
- dsa = DSA_generate_parameters(1024, NULL, 0, NULL,
- NULL, 0, NULL);
- dh = DSA_dup_DH(dsa);
- DSA_free(dsa);
- }
- else
- if (dh == NULL && bitset(TLS_I_DH512, req))
- dh = get_dh512();
-
- if (dh == NULL)
- {
- if (LogLevel > 9)
- {
- u_long err;
-
- err = ERR_get_error();
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: cannot read or set DH parameters(%s): %s",
- who, dhparam,
- ERR_error_string(err, NULL));
+ if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, e->e_id,
+ "srvfeatures: unknown feature %s",
+ pvp[i]);
+ break;
}
- if (bitset(TLS_I_REQ_DH, req))
- return FALSE;
- }
- else
- {
- SSL_CTX_set_tmp_dh(*ctx, dh);
-
- /* important to avoid small subgroup attacks */
- SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_DH_USE);
- if (LogLevel > 12)
- sm_syslog(LOG_INFO, NOQID,
- "TLS: %s: Diffie-Hellman init, key=%d bit (%c)",
- who, 8 * DH_size(dh), *dhparam);
- DH_free(dh);
- }
- }
-# endif /* !NO_DH */
-
-
- /* XXX do we need this cache here? */
- if (bitset(TLS_I_CACHE, req))
- SSL_CTX_sess_set_cache_size(*ctx, 128);
- /* timeout? SSL_CTX_set_timeout(*ctx, TimeOut...); */
-
- /* load certificate locations and default CA paths */
- if (bitset(TLS_S_CERTP_EX, status) && bitset(TLS_S_CERTF_EX, status))
- {
- if ((r = SSL_CTX_load_verify_locations(*ctx, cacertfile,
- cacertpath)) == 1)
- {
-# if !TLS_NO_RSA
- if (bitset(TLS_I_RSA_TMP, req))
- SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key);
-# endif /* !TLS_NO_RSA */
-
- /* ask to verify the peer */
- SSL_CTX_set_verify(*ctx, SSL_VERIFY_PEER, NULL);
-
- /* install verify callback */
- SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb,
- NULL);
- SSL_CTX_set_client_CA_list(*ctx,
- SSL_load_client_CA_file(cacertfile));
- }
- else
- {
- /*
- ** can't load CA data; do we care?
- ** the data is necessary to authenticate the client,
- ** which in turn would be necessary
- ** if we want to allow relaying based on it.
- */
- if (LogLevel > 5)
+ if (c == opt)
{
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: %d load verify locs %s, %s",
- who, r, cacertpath, cacertfile);
- if (LogLevel > 9)
- tlslogerr();
+ features &= ~(srv_feat_table[j].srvf_flag);
+ break;
}
- if (bitset(TLS_I_VRFY_LOC, req))
- return FALSE;
- }
- }
-
- /* XXX: make this dependent on an option? */
- if (tTd(96, 9))
- SSL_CTX_set_info_callback(*ctx, apps_ssl_info_cb);
-
-# if _FFR_TLS_1
- /*
- ** XXX install our own cipher list: option?
- */
- if (CipherList != NULL && *CipherList != '\0')
- {
- if (SSL_CTX_set_cipher_list(*ctx, CipherList) <= 0)
- {
- if (LogLevel > 7)
+ if (c == tolower(opt))
{
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: error: %s: SSL_CTX_set_cipher_list(%s) failed, list ignored",
- who, CipherList);
-
- if (LogLevel > 9)
- tlslogerr();
+ features |= srv_feat_table[j].srvf_flag;
+ break;
}
- /* failure if setting to this list is required? */
+ ++j;
}
}
-# endif /* _FFR_TLS_1 */
- if (LogLevel > 12)
- sm_syslog(LOG_INFO, NOQID, "TLS: init(%s)=%d", who, ok);
-
-# if _FFR_TLS_1
-# if 0
- /*
- ** this label is required if we want to have a "clean" exit
- ** see the comments above at the initialization of cf2
- */
- endinittls:
-# endif /* 0 */
-
- /* undo damage to global variables */
- if (cf2 != NULL)
- *--cf2 = ',';
- if (kf2 != NULL)
- *--kf2 = ',';
-# endif /* _FFR_TLS_1 */
-
- return ok;
+ return features;
}
- /*
-** INITSRVTLS -- initialize server side TLS
-**
-** Parameters:
-** none.
-**
-** Returns:
-** succeeded?
-**
-** Side Effects:
-** sets tls_ok_srv static, even when called from main()
-*/
-
-bool
-initsrvtls()
-{
- tls_ok_srv = inittls(&srv_ctx, TLS_I_SRV, TRUE, SrvCERTfile,
- Srvkeyfile, CACERTpath, CACERTfile, DHParams);
- return tls_ok_srv;
-}
- /*
-** TLS_GET_INFO -- get information about TLS connection
-**
-** Parameters:
-** ssl -- SSL connection structure
-** e -- current envelope
-** srv -- server or client
-** host -- hostname of other side
-** log -- log connection information?
-**
-** Returns:
-** result of authentication.
-**
-** Side Effects:
-** sets ${cipher}, ${tls_version}, ${verify}, ${cipher_bits},
-** ${cert}
-*/
-
-int
-tls_get_info(ssl, e, srv, host, log)
- SSL *ssl;
- ENVELOPE *e;
- bool srv;
- char *host;
- bool log;
-{
- SSL_CIPHER *c;
- int b, r;
- char *s;
- char bitstr[16];
- X509 *cert;
-
- c = SSL_get_current_cipher(ssl);
- define(macid("{cipher}", NULL), newstr(SSL_CIPHER_get_name(c)), e);
- b = SSL_CIPHER_get_bits(c, &r);
- (void) snprintf(bitstr, sizeof bitstr, "%d", b);
- define(macid("{cipher_bits}", NULL), newstr(bitstr), e);
-# if _FFR_TLS_1
- (void) snprintf(bitstr, sizeof bitstr, "%d", r);
- define(macid("{alg_bits}", NULL), newstr(bitstr), e);
-# endif /* _FFR_TLS_1 */
- s = SSL_CIPHER_get_version(c);
- if (s == NULL)
- s = "UNKNOWN";
- define(macid("{tls_version}", NULL), newstr(s), e);
-
- cert = SSL_get_peer_certificate(ssl);
- if (log && LogLevel >= 14)
- sm_syslog(LOG_INFO, e->e_id,
- "TLS: get_verify in %s: %ld get_peer: 0x%lx",
- srv ? "srv" : "clt",
- SSL_get_verify_result(ssl), (u_long) cert);
- if (cert != NULL)
- {
- char buf[MAXNAME];
-
- X509_NAME_oneline(X509_get_subject_name(cert),
- buf, sizeof buf);
- define(macid("{cert_subject}", NULL),
- newstr(xtextify(buf, "<>\")")), e);
- X509_NAME_oneline(X509_get_issuer_name(cert),
- buf, sizeof buf);
- define(macid("{cert_issuer}", NULL),
- newstr(xtextify(buf, "<>\")")), e);
-# if _FFR_TLS_1
- X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
- NID_commonName, buf, sizeof buf);
- define(macid("{cn_subject}", NULL),
- newstr(xtextify(buf, "<>\")")), e);
- X509_NAME_get_text_by_NID(X509_get_issuer_name(cert),
- NID_commonName, buf, sizeof buf);
- define(macid("{cn_issuer}", NULL),
- newstr(xtextify(buf, "<>\")")), e);
-# endif /* _FFR_TLS_1 */
- }
- else
- {
- define(macid("{cert_subject}", NULL), "", e);
- define(macid("{cert_issuer}", NULL), "", e);
-# if _FFR_TLS_1
- define(macid("{cn_subject}", NULL), "", e);
- define(macid("{cn_issuer}", NULL), "", e);
-# endif /* _FFR_TLS_1 */
- }
- switch(SSL_get_verify_result(ssl))
- {
- case X509_V_OK:
- if (cert != NULL)
- {
- s = "OK";
- r = TLS_AUTH_OK;
- }
- else
- {
- s = "NO";
- r = TLS_AUTH_NO;
- }
- break;
- default:
- s = "FAIL";
- r = TLS_AUTH_FAIL;
- break;
- }
- define(macid("{verify}", NULL), newstr(s), e);
- if (cert != NULL)
- X509_free(cert);
-
- /* do some logging */
- if (log && LogLevel > 9)
- {
- char *vers, *s1, *s2, *bits;
-
- vers = macvalue(macid("{tls_version}", NULL), e);
- bits = macvalue(macid("{cipher_bits}", NULL), e);
- s1 = macvalue(macid("{verify}", NULL), e);
- s2 = macvalue(macid("{cipher}", NULL), e);
- sm_syslog(LOG_INFO, NOQID,
- "TLS: connection %s %.64s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s",
- srv ? "from" : "to",
- host == NULL ? "none" : host,
- vers == NULL ? "none" : vers,
- s1 == NULL ? "none" : s1,
- s2 == NULL ? "none" : s2,
- bits == NULL ? "0" : bits);
- if (LogLevel > 11)
- {
- /*
- ** maybe run xuntextify on the strings?
- ** that is easier to read but makes it maybe a bit
- ** more complicated to figure out the right values
- ** for the access map...
- */
- s1 = macvalue(macid("{cert_subject}", NULL), e);
- s2 = macvalue(macid("{cert_issuer}", NULL), e);
- sm_syslog(LOG_INFO, NOQID,
- "TLS: %s cert subject:%.128s, cert issuer=%.128s",
- srv ? "client" : "server",
- s1 == NULL ? "none" : s1,
- s2 == NULL ? "none" : s2);
- }
- }
-
- return r;
-}
-
-# if !TLS_NO_RSA
- /*
-** TMP_RSA_KEY -- return temporary RSA key
-**
-** Parameters:
-** s -- SSL connection structure
-** export --
-** keylength --
-**
-** Returns:
-** temporary RSA key.
-*/
-
-/* ARGUSED0 */
-static RSA *
-tmp_rsa_key(s, export, keylength)
- SSL *s;
- int export;
- int keylength;
-{
- return rsa_tmp;
-}
-# endif /* !TLS_NO_RSA */
- /*
-** APPS_SSL_INFO_CB -- info callback for TLS connections
-**
-** Parameters:
-** s -- SSL connection structure
-** where --
-** ret --
-**
-** Returns:
-** none.
-*/
-
-void
-apps_ssl_info_cb(s, where, ret)
- SSL *s;
- int where;
- int ret;
-{
- char *str;
- int w;
- BIO *bio_err = NULL;
-
- if (LogLevel > 14)
- sm_syslog(LOG_INFO, NOQID,
- "info_callback where 0x%x ret %d", where, ret);
-
- w = where & ~SSL_ST_MASK;
- if (bio_err == NULL)
- bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
-
- if (w & SSL_ST_CONNECT)
- str = "SSL_connect";
- else if (w & SSL_ST_ACCEPT)
- str = "SSL_accept";
- else
- str = "undefined";
-
- if (where & SSL_CB_LOOP)
- {
- if (LogLevel > 12)
- sm_syslog(LOG_NOTICE, NOQID,
- "%s:%s\n", str, SSL_state_string_long(s));
- }
- else if (where & SSL_CB_ALERT)
- {
- str = (where & SSL_CB_READ) ? "read" : "write";
- if (LogLevel > 12)
- sm_syslog(LOG_NOTICE, NOQID,
- "SSL3 alert %s:%s:%s\n",
- str, SSL_alert_type_string_long(ret),
- SSL_alert_desc_string_long(ret));
- }
- else if (where & SSL_CB_EXIT)
- {
- if (ret == 0)
- {
- if (LogLevel > 7)
- sm_syslog(LOG_WARNING, NOQID,
- "%s:failed in %s\n",
- str, SSL_state_string_long(s));
- }
- else if (ret < 0)
- {
- if (LogLevel > 7)
- sm_syslog(LOG_WARNING, NOQID,
- "%s:error in %s\n",
- str, SSL_state_string_long(s));
- }
- }
-}
- /*
-** TLS_VERIFY_LOG -- log verify error for TLS certificates
-**
-** Parameters:
-** ok -- verify ok?
-** ctx -- x509 context
-**
-** Returns:
-** 0 -- fatal error
-** 1 -- ok
-*/
-
-static int
-tls_verify_log(ok, ctx)
- int ok;
- X509_STORE_CTX *ctx;
-{
- SSL *ssl;
- X509 *cert;
- int reason, depth;
- char buf[512];
-
- cert = X509_STORE_CTX_get_current_cert(ctx);
- reason = X509_STORE_CTX_get_error(ctx);
- depth = X509_STORE_CTX_get_error_depth(ctx);
- ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx,
- SSL_get_ex_data_X509_STORE_CTX_idx());
-
- if (ssl == NULL)
- {
- /* internal error */
- sm_syslog(LOG_ERR, NOQID,
- "TLS: internal error: tls_verify_cb: ssl == NULL");
- return 0;
- }
-
- X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof buf);
- sm_syslog(LOG_INFO, NOQID,
- "TLS cert verify: depth=%d %s, state=%d, reason=%s\n",
- depth, buf, ok, X509_verify_cert_error_string(reason));
- return 1;
-}
-
- /*
-** TLS_VERIFY_CB -- verify callback for TLS certificates
-**
-** Parameters:
-** ctx -- x509 context
-**
-** Returns:
-** accept connection?
-** currently: always yes.
-*/
-
-static int
-tls_verify_cb(ctx)
- X509_STORE_CTX *ctx;
-{
- int ok;
-
- ok = X509_verify_cert(ctx);
- if (ok == 0)
- {
- if (LogLevel > 13)
- return tls_verify_log(ok, ctx);
- return 1; /* override it */
- }
- return ok;
-}
-
-
- /*
-** TLSLOGERR -- log the errors from the TLS error stack
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-*/
-
-void
-tlslogerr()
-{
- unsigned long l;
- int line, flags;
- unsigned long es;
- char *file, *data;
- char buf[256];
-#define CP (const char **)
-
- es = CRYPTO_thread_id();
- while ((l = ERR_get_error_line_data(CP &file, &line, CP &data, &flags))
- != 0)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "TLS: %lu:%s:%s:%d:%s\n", es, ERR_error_string(l, buf),
- file, line, (flags & ERR_TXT_STRING) ? data : "");
- }
-}
-
-# endif /* STARTTLS */
-#endif /* SMTP */
- /*
+/*
** HELP -- implement the HELP command.
**
** Parameters:
** topic -- the topic we want help for.
-** e -- envelope
+** e -- envelope.
**
** Returns:
** none.
@@ -4216,11 +3927,11 @@ help(topic, e)
char *topic;
ENVELOPE *e;
{
- register FILE *hf;
+ register SM_FILE_T *hf;
register char *p;
int len;
bool noinfo;
- bool first = TRUE;
+ bool first = true;
long sff = SFF_OPENASROOT|SFF_REGONLY;
char buf[MAXLINE];
char inp[MAXLINE];
@@ -4245,17 +3956,17 @@ help(topic, e)
if (topic == NULL || *topic == '\0')
{
topic = "smtp";
- noinfo = FALSE;
+ noinfo = false;
}
else
{
makelower(topic);
- noinfo = TRUE;
+ noinfo = true;
}
len = strlen(topic);
- while (fgets(buf, sizeof buf, hf) != NULL)
+ while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
if (buf[0] == '#')
{
@@ -4264,8 +3975,8 @@ help(topic, e)
{
int h;
- if (sscanf(buf + strlen(HELPVSTR), "%d",
- &h) == 1)
+ if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d",
+ &h) == 1)
foundvers = h;
}
continue;
@@ -4274,7 +3985,7 @@ help(topic, e)
{
if (first)
{
- first = FALSE;
+ first = false;
/* print version if no/old vers# in file */
if (foundvers < 2 && !noinfo)
@@ -4285,7 +3996,7 @@ help(topic, e)
p = buf + strlen(buf) - 1;
else
p++;
- fixcrlf(p, TRUE);
+ fixcrlf(p, true);
if (foundvers >= 2)
{
translate_dollars(p);
@@ -4293,7 +4004,7 @@ help(topic, e)
p = inp;
}
message("214-2.0.0 %s", p);
- noinfo = FALSE;
+ noinfo = false;
}
}
@@ -4313,5 +4024,5 @@ help(topic, e)
foundvers = 0;
}
- (void) fclose(hf);
+ (void) sm_io_close(hf, SM_TIME_DEFAULT);
}
diff --git a/contrib/sendmail/src/stab.c b/contrib/sendmail/src/stab.c
index 82775bc..b2ad12d 100644
--- a/contrib/sendmail/src/stab.c
+++ b/contrib/sendmail/src/stab.c
@@ -11,12 +11,10 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: stab.c,v 8.40.16.7 2001/05/07 22:06:41 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+SM_RCSID("@(#)$Id: stab.c,v 8.86 2001/12/29 04:27:56 ca Exp $")
+
/*
** STAB -- manage the symbol table
**
@@ -24,8 +22,7 @@ static char id[] = "@(#)$Id: stab.c,v 8.40.16.7 2001/05/07 22:06:41 gshapiro Exp
** name -- the name to be looked up or inserted.
** type -- the type of symbol.
** op -- what to do:
-** ST_ENTER -- enter the name if not
-** already present.
+** ST_ENTER -- enter the name if not already present.
** ST_FIND -- find it only.
**
** Returns:
@@ -37,6 +34,7 @@ static char id[] = "@(#)$Id: stab.c,v 8.40.16.7 2001/05/07 22:06:41 gshapiro Exp
*/
#define STABSIZE 2003
+#define SM_LOWER(c) ((isascii(c) && isupper(c)) ? tolower(c) : (c))
static STAB *SymTab[STABSIZE];
@@ -53,7 +51,7 @@ stab(name, type, op)
int len;
if (tTd(36, 5))
- dprintf("STAB: %s %d ", name, type);
+ sm_dprintf("STAB: %s %d ", name, type);
/*
** Compute the hashing function
@@ -61,22 +59,22 @@ stab(name, type, op)
hfunc = type;
for (p = name; *p != '\0'; p++)
- hfunc = ((hfunc << 1) ^ (lower(*p) & 0377)) % STABSIZE;
+ hfunc = ((hfunc << 1) ^ (SM_LOWER(*p) & 0377)) % STABSIZE;
if (tTd(36, 9))
- dprintf("(hfunc=%d) ", hfunc);
+ sm_dprintf("(hfunc=%d) ", hfunc);
ps = &SymTab[hfunc];
if (type == ST_MACRO || type == ST_RULESET)
{
while ((s = *ps) != NULL &&
- (s->s_type != type || strcmp(name, s->s_name)))
+ (s->s_symtype != type || strcmp(name, s->s_name)))
ps = &s->s_next;
}
else
{
while ((s = *ps) != NULL &&
- (s->s_type != type || strcasecmp(name, s->s_name)))
+ (s->s_symtype != type || sm_strcasecmp(name, s->s_name)))
ps = &s->s_next;
}
@@ -89,13 +87,13 @@ stab(name, type, op)
if (tTd(36, 5))
{
if (s == NULL)
- dprintf("not found\n");
+ sm_dprintf("not found\n");
else
{
long *lp = (long *) s->s_class;
- dprintf("type %d val %lx %lx %lx %lx\n",
- s->s_type, lp[0], lp[1], lp[2], lp[3]);
+ sm_dprintf("type %d val %lx %lx %lx %lx\n",
+ s->s_symtype, lp[0], lp[1], lp[2], lp[3]);
}
}
return s;
@@ -106,7 +104,7 @@ stab(name, type, op)
*/
if (tTd(36, 5))
- dprintf("entered\n");
+ sm_dprintf("entered\n");
/* determine size of new entry */
switch (type)
@@ -159,21 +157,25 @@ stab(name, type, op)
len = sizeof s->s_service;
break;
-#ifdef LDAPMAP
+#if LDAPMAP
case ST_LMAP:
len = sizeof s->s_lmap;
break;
#endif /* LDAPMAP */
-#if _FFR_MILTER
+#if MILTER
case ST_MILTER:
len = sizeof s->s_milter;
break;
-#endif /* _FFR_MILTER */
+#endif /* MILTER */
+
+ case ST_QUEUE:
+ len = sizeof s->s_quegrp;
+ break;
default:
/*
- ** Each mailer has it's own MCI stab entry:
+ ** Each mailer has its own MCI stab entry:
**
** s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
**
@@ -192,14 +194,13 @@ stab(name, type, op)
len += sizeof *s - sizeof s->s_value;
if (tTd(36, 15))
- dprintf("size of stab entry: %d\n", len);
+ sm_dprintf("size of stab entry: %d\n", len);
/* make new entry */
- s = (STAB *) xalloc(len);
+ s = (STAB *) sm_pmalloc_x(len);
memset((char *) s, '\0', len);
- s->s_name = newstr(name);
- s->s_type = type;
- s->s_len = len;
+ s->s_name = sm_pstrdup_x(name);
+ s->s_symtype = type;
/* link it in */
*ps = s;
@@ -210,12 +211,12 @@ stab(name, type, op)
return s;
}
- /*
+/*
** STABAPPLY -- apply function to all stab entries
**
** Parameters:
-** func -- the function to apply. It will be given one
-** parameter (the stab entry).
+** func -- the function to apply. It will be given two
+** parameters (the stab entry and the arg).
** arg -- an arbitrary argument, passed to func.
**
** Returns:
@@ -235,13 +236,13 @@ stabapply(func, arg)
for (s = *shead; s != NULL; s = s->s_next)
{
if (tTd(36, 90))
- dprintf("stabapply: trying %d/%s\n",
- s->s_type, s->s_name);
+ sm_dprintf("stabapply: trying %d/%s\n",
+ s->s_symtype, s->s_name);
func(s, arg);
}
}
}
- /*
+/*
** QUEUEUP_MACROS -- queueup the macros in a class
**
** Write the macros listed in the specified class into the
@@ -249,7 +250,7 @@ stabapply(func, arg)
**
** Parameters:
** class -- class ID.
-** qfp -- file pointer to the qf file.
+** qfp -- file pointer to the queue file.
** e -- the envelope.
**
** Returns:
@@ -259,7 +260,7 @@ stabapply(func, arg)
void
queueup_macros(class, qfp, e)
int class;
- FILE *qfp;
+ SM_FILE_T *qfp;
ENVELOPE *e;
{
register STAB **shead;
@@ -276,39 +277,21 @@ queueup_macros(class, qfp, e)
int m;
char *p;
- if (s->s_type == ST_CLASS &&
- bitnset(class, s->s_class) &&
- (m = macid(s->s_name, NULL)) != '\0' &&
+ if (s->s_symtype == ST_CLASS &&
+ bitnset(bitidx(class), s->s_class) &&
+ (m = macid(s->s_name)) != '\0' &&
(p = macvalue(m, e)) != NULL)
{
- /*
- ** HACK ALERT: Unfortunately, 8.10 and
- ** 8.11 reused the ${if_addr} and
- ** ${if_family} macros for both the incoming
- ** interface address/family (getrequests())
- ** and the outgoing interface address/family
- ** (makeconnection()). In order for D_BINDIF
- ** to work properly, have to preserve the
- ** incoming information in the queue file for
- ** later delivery attempts. The original
- ** information is stored in the envelope
- ** in readqf() so it can be stored in
- ** queueup_macros(). This should be fixed
- ** in 8.12.
- */
-
- if (e->e_if_macros[EIF_ADDR] != NULL &&
- strcmp(s->s_name, "{if_addr}") == 0)
- p = e->e_if_macros[EIF_ADDR];
-
- fprintf(qfp, "$%s%s\n",
- s->s_name,
- denlstring(p, TRUE, FALSE));
+ (void) sm_io_fprintf(qfp, SM_TIME_DEFAULT,
+ "$%s%s\n",
+ s->s_name,
+ denlstring(p, true,
+ false));
}
}
}
}
- /*
+/*
** COPY_CLASS -- copy class members from one class to another
**
** Parameters:
@@ -333,9 +316,154 @@ copy_class(src, dst)
{
for (s = *shead; s != NULL; s = s->s_next)
{
- if (s->s_type == ST_CLASS &&
+ if (s->s_symtype == ST_CLASS &&
bitnset(src, s->s_class))
setbitn(dst, s->s_class);
}
}
}
+
+/*
+** RMEXPSTAB -- remove expired entries from SymTab.
+**
+** These entries need to be removed in long-running processes,
+** e.g., persistent queue runners, to avoid consuming memory.
+**
+** XXX It might be useful to restrict the maximum TTL to avoid
+** caching data very long.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** can remove entries from the symbol table.
+*/
+
+#define SM_STAB_FREE(x) \
+ do \
+ { \
+ char *o = (x); \
+ (x) = NULL; \
+ if (o != NULL) \
+ sm_free(o); \
+ } while (0)
+
+void
+rmexpstab()
+{
+ int i;
+ STAB *s, *p, *f;
+ time_t now;
+
+ now = curtime();
+ for (i = 0; i < STABSIZE; i++)
+ {
+ p = NULL;
+ s = SymTab[i];
+ while (s != NULL)
+ {
+ switch (s->s_symtype)
+ {
+ case ST_HOSTSIG:
+ if (s->s_hostsig.hs_exp >= now)
+ goto next; /* not expired */
+ SM_STAB_FREE(s->s_hostsig.hs_sig); /* XXX */
+ break;
+
+ case ST_NAMECANON:
+ if (s->s_namecanon.nc_exp >= now)
+ goto next; /* not expired */
+ SM_STAB_FREE(s->s_namecanon.nc_cname); /* XXX */
+ break;
+
+ default:
+ if (s->s_symtype >= ST_MCI)
+ {
+ /* call mci_uncache? */
+ SM_STAB_FREE(s->s_mci.mci_status);
+ SM_STAB_FREE(s->s_mci.mci_rstatus);
+ SM_STAB_FREE(s->s_mci.mci_heloname);
+#if 0
+ /* not dynamically allocated */
+ SM_STAB_FREE(s->s_mci.mci_host);
+ SM_STAB_FREE(s->s_mci.mci_tolist);
+#endif /* 0 */
+#if SASL
+ /* should always by NULL */
+ SM_STAB_FREE(s->s_mci.mci_sasl_string);
+#endif /* SASL */
+ if (s->s_mci.mci_rpool != NULL)
+ {
+ sm_rpool_free(s->s_mci.mci_rpool);
+ s->s_mci.mci_macro.mac_rpool = NULL;
+ s->s_mci.mci_rpool = NULL;
+ }
+ break;
+ }
+ next:
+ p = s;
+ s = s->s_next;
+ continue;
+ }
+
+ /* remove entry */
+ SM_STAB_FREE(s->s_name); /* XXX */
+ f = s;
+ s = s->s_next;
+ sm_free(f); /* XXX */
+ if (p == NULL)
+ SymTab[i] = s;
+ else
+ p->s_next = s;
+ }
+ }
+}
+
+#if SM_HEAP_CHECK
+/*
+** DUMPSTAB -- dump symbol table.
+**
+** For debugging.
+*/
+
+#define MAXSTTYPES (ST_MCI + 1)
+
+void
+dumpstab()
+{
+ int i, t, total, types[MAXSTTYPES];
+ STAB *s;
+ static int prevt[MAXSTTYPES], prev = 0;
+
+ total = 0;
+ for (i = 0; i < MAXSTTYPES; i++)
+ types[i] = 0;
+ for (i = 0; i < STABSIZE; i++)
+ {
+ s = SymTab[i];
+ while (s != NULL)
+ {
+ ++total;
+ t = s->s_symtype;
+ if (t > MAXSTTYPES - 1)
+ t = MAXSTTYPES - 1;
+ types[t]++;
+ s = s->s_next;
+ }
+ }
+ sm_syslog(LOG_INFO, NOQID, "stab: total=%d (%d)", total, total - prev);
+ prev = total;
+ for (i = 0; i < MAXSTTYPES; i++)
+ {
+ if (types[i] != 0)
+ {
+ sm_syslog(LOG_INFO, NOQID, "stab: type[%2d]=%2d (%d)",
+ i, types[i], types[i] - prevt[i]);
+ }
+ prevt[i] = types[i];
+ }
+}
+#endif /* SM_HEAP_CHECK */
diff --git a/contrib/sendmail/src/stats.c b/contrib/sendmail/src/stats.c
index e03de5f..0ae8ff4 100644
--- a/contrib/sendmail/src/stats.c
+++ b/contrib/sendmail/src/stats.c
@@ -11,28 +11,26 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: stats.c,v 8.36.14.5 2001/02/14 04:07:30 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-#include <sendmail/mailstats.h>
+SM_RCSID("@(#)$Id: stats.c,v 8.52 2001/11/21 13:39:14 gshapiro Exp $")
+
+#include <sendmail/mailstats.h>
static struct statistics Stat;
-static bool GotStats = FALSE; /* set when we have stats to merge */
+static bool GotStats = false; /* set when we have stats to merge */
/* See http://physics.nist.gov/cuu/Units/binary.html */
#define ONE_K 1000 /* one thousand (twenty-four?) */
#define KBYTES(x) (((x) + (ONE_K - 1)) / ONE_K)
- /*
+/*
** MARKSTATS -- mark statistics
**
** Parameters:
** e -- the envelope.
** to -- to address.
-** reject -- whether this is a rejection.
+** type -- type of stats this represents.
**
** Returns:
** none.
@@ -42,13 +40,21 @@ static bool GotStats = FALSE; /* set when we have stats to merge */
*/
void
-markstats(e, to, reject)
+markstats(e, to, type)
register ENVELOPE *e;
register ADDRESS *to;
- bool reject;
+ int type;
{
- if (reject)
+ switch (type)
{
+#if _FFR_QUARANTINE
+ case STATS_QUARANTINE:
+ if (e->e_from.q_mailer != NULL)
+ Stat.stat_nq[e->e_from.q_mailer->m_mno]++;
+ break;
+#endif /* _FFR_QUARANTINE */
+
+ case STATS_REJECT:
if (e->e_from.q_mailer != NULL)
{
if (bitset(EF_DISCARD, e->e_flags))
@@ -57,28 +63,36 @@ markstats(e, to, reject)
Stat.stat_nr[e->e_from.q_mailer->m_mno]++;
}
Stat.stat_cr++;
- }
- else if (to == NULL)
- {
- Stat.stat_cf++;
- if (e->e_from.q_mailer != NULL)
+ break;
+
+ case STATS_NORMAL:
+ if (to == NULL)
{
- Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
- Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
- KBYTES(e->e_msgsize);
+ Stat.stat_cf++;
+ if (e->e_from.q_mailer != NULL)
+ {
+ Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
+ Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
+ KBYTES(e->e_msgsize);
+ }
}
- }
- else
- {
- Stat.stat_ct++;
- Stat.stat_nt[to->q_mailer->m_mno]++;
- Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
+ else
+ {
+ Stat.stat_ct++;
+ Stat.stat_nt[to->q_mailer->m_mno]++;
+ Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
+ }
+ break;
+
+ default:
+ /* Silently ignore bogus call */
+ return;
}
- GotStats = TRUE;
+ GotStats = true;
}
- /*
+/*
** CLEARSTATS -- clear statistics structure
**
** Parameters:
@@ -96,9 +110,9 @@ clearstats()
{
/* clear the structure to avoid future disappointment */
memset(&Stat, '\0', sizeof Stat);
- GotStats = FALSE;
+ GotStats = false;
}
- /*
+/*
** POSTSTATS -- post statistics in the statistics file
**
** Parameters:
@@ -115,13 +129,15 @@ void
poststats(sfile)
char *sfile;
{
- register int fd;
+ int fd;
+ static bool entered = false;
long sff = SFF_REGONLY|SFF_OPENASROOT;
struct statistics stats;
extern off_t lseek();
- if (sfile == NULL || !GotStats)
+ if (sfile == NULL || *sfile == '\0' || !GotStats || entered)
return;
+ entered = true;
(void) time(&Stat.stat_itime);
Stat.stat_size = sizeof Stat;
@@ -138,8 +154,9 @@ poststats(sfile)
{
if (LogLevel > 12)
sm_syslog(LOG_INFO, NOQID, "poststats: %s: %s",
- sfile, errstring(errno));
+ sfile, sm_errstring(errno));
errno = 0;
+ entered = false;
return;
}
if (read(fd, (char *) &stats, sizeof stats) == sizeof stats &&
@@ -158,6 +175,9 @@ poststats(sfile)
stats.stat_bt[i] += Stat.stat_bt[i];
stats.stat_nr[i] += Stat.stat_nr[i];
stats.stat_nd[i] += Stat.stat_nd[i];
+#if _FFR_QUARANTINE
+ stats.stat_nq[i] += Stat.stat_nq[i];
+#endif /* _FFR_QUARANTINE */
}
stats.stat_cr += Stat.stat_cr;
stats.stat_ct += Stat.stat_ct;
@@ -173,4 +193,5 @@ poststats(sfile)
/* clear the structure to avoid future disappointment */
clearstats();
+ entered = false;
}
diff --git a/contrib/sendmail/src/statusd_shm.h b/contrib/sendmail/src/statusd_shm.h
index c48b2fd..7d88964 100644
--- a/contrib/sendmail/src/statusd_shm.h
+++ b/contrib/sendmail/src/statusd_shm.h
@@ -1,22 +1,22 @@
/*
- * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
- * $Id: statusd_shm.h,v 8.4 1999/05/18 08:00:04 gshapiro Exp $
+ * $Id: statusd_shm.h,v 8.7 2000/09/17 17:30:06 gshapiro Exp $
*
* Contributed by Exactis.com, Inc.
*
*/
/*
-** The shared memory part of statusd.
+** The shared memory part of statusd.
**
-** Attach to STATUSD_SHM_KEY and update the counter appropriate
-** for your type of service.
+** Attach to STATUSD_SHM_KEY and update the counter appropriate
+** for your type of service.
**
*/
@@ -24,7 +24,8 @@
#define STATUSD_SHM_KEY (key_t)(13)
#define STATUSD_LONGS (2)
-typedef struct {
+typedef struct
+{
unsigned long magic;
unsigned long ul[STATUSD_LONGS];
} STATUSD_SHM;
diff --git a/contrib/sendmail/src/sysexits.c b/contrib/sendmail/src/sysexits.c
index 6cce614..5cce2b7 100644
--- a/contrib/sendmail/src/sysexits.c
+++ b/contrib/sendmail/src/sysexits.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,60 +11,11 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: sysexits.c,v 8.25 1999/09/23 19:59:24 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-/*
-** SYSEXITS.C -- error messages corresponding to sysexits.h
-**
-** If the first character of the string is a colon, interpolate
-** the current errno after the rest of the string.
-*/
+SM_RCSID("@(#)$Id: sysexits.c,v 8.33 2001/09/11 04:05:17 gshapiro Exp $")
-char *SysExMsg[] =
-{
- /* 64 USAGE */ " 500 5.0.0 Bad usage",
- /* 65 DATAERR */ " 501 5.6.0 Data format error",
- /* 66 NOINPUT */ ":550 5.3.0 Cannot open input",
- /* 67 NOUSER */ " 550 5.1.1 User unknown",
- /* 68 NOHOST */ " 550 5.1.2 Host unknown",
- /* 69 UNAVAILABLE */ " 554 5.0.0 Service unavailable",
- /* 70 SOFTWARE */ ":554 5.3.0 Internal error",
- /* 71 OSERR */ ":451 4.0.0 Operating system error",
- /* 72 OSFILE */ ":554 5.3.5 System file missing",
- /* 73 CANTCREAT */ ":550 5.0.0 Can't create output",
- /* 74 IOERR */ ":451 4.0.0 I/O error",
- /* 75 TEMPFAIL */ " 450 4.0.0 Deferred",
- /* 76 PROTOCOL */ " 554 5.5.0 Remote protocol error",
- /* 77 NOPERM */ ":550 5.0.0 Insufficient permission",
- /* 78 CONFIG */ " 554 5.3.5 Local configuration error",
-};
-
-int N_SysEx = sizeof(SysExMsg) / sizeof(SysExMsg[0]);
-
-static char *SysExitMsg[] =
-{
- "command line usage error",
- "data format error",
- "cannot open input",
- "addressee unknown",
- "host name unknown",
- "service unavailable",
- "internal software error",
- "system error (e.g., can't fork)",
- "critical OS file missing",
- "can't create (user) output file",
- "input/output error",
- "temp failure; user is invited to retry",
- "remote error in protocol",
- "permission denied",
- "configuration error"
-};
-
- /*
+/*
** DSNTOEXITSTAT -- convert DSN-style error code to EX_ style.
**
** Parameters:
@@ -181,8 +132,7 @@ dsntoexitstat(dsncode)
}
return EX_CONFIG;
}
-
- /*
+/*
** EXITSTAT -- convert EX_ value to error text.
**
** Parameters:
@@ -198,19 +148,15 @@ exitstat(excode)
{
char *c;
int i;
+ char *exitmsg;
if (excode == NULL || *excode == '\0')
return excode;
- i = 0;
- for (c = excode; *c != '\0'; c++)
- {
- if (isascii(*c) && isdigit(*c))
- i = i * 10 + (*c - '0');
- else
- return excode;
- }
- i -= EX__BASE;
- if (i >= 0 && i <= N_SysEx)
- return SysExitMsg[i];
+ i = (int) strtol(excode, &c, 10);
+ if (*c != '\0')
+ return excode;
+ exitmsg = sm_sysexitmsg(i);
+ if (exitmsg != NULL)
+ return exitmsg;
return excode;
}
diff --git a/contrib/sendmail/src/timers.c b/contrib/sendmail/src/timers.c
index acd774c..43dd73a 100644
--- a/contrib/sendmail/src/timers.c
+++ b/contrib/sendmail/src/timers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -10,9 +10,8 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: timers.c,v 8.13.16.1 2000/10/09 01:06:45 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
+SM_RCSID("@(#)$Id: timers.c,v 8.24 2001/09/11 04:05:17 gshapiro Exp $")
#if _FFR_TIMERS
# include <sys/types.h>
@@ -34,17 +33,17 @@ warntimer(msg, va_alist)
# endif /* __STDC__ */
{
char buf[MAXLINE];
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
# if 0
if (!tTd(98, 30))
return;
# endif /* 0 */
- VA_START(msg);
- vsnprintf(buf, sizeof buf, msg, ap);
- VA_END;
+ SM_VA_START(ap, msg);
+ (void) sm_vsnprintf(buf, sizeof buf, msg, ap);
+ SM_VA_END(ap);
sm_syslog(LOG_NOTICE, CurEnv->e_id, "%s; e_timers=0x%lx",
- buf, (u_long) &CurEnv->e_timers);
+ buf, (unsigned long) &CurEnv->e_timers);
}
static void
@@ -169,7 +168,7 @@ pushtimer(ptimer)
if (TimerStack[i] == ptimer)
{
warntimer("Timer@0x%lx already on stack, index=%d, NTimers=%d",
- (u_long) ptimer, i, NTimers);
+ (unsigned long) ptimer, i, NTimers);
errno = save_errno;
return;
}
@@ -211,7 +210,7 @@ poptimer(ptimer)
if (i != NTimers - 1)
warntimer("poptimer: odd pop (timer=0x%lx, index=%d, NTimers=%d)",
- (u_long) ptimer, i, NTimers);
+ (unsigned long) ptimer, i, NTimers);
NTimers = i;
/* clean up and return */
@@ -224,7 +223,7 @@ strtimer(ptimer)
{
static char buf[40];
- snprintf(buf, sizeof buf, "%ld.%06ldr/%ld.%06ldc",
+ (void) sm_snprintf(buf, sizeof buf, "%ld.%06ldr/%ld.%06ldc",
ptimer->ti_wall_sec, ptimer->ti_wall_usec,
ptimer->ti_cpu_sec, ptimer->ti_cpu_usec);
return buf;
diff --git a/contrib/sendmail/src/timers.h b/contrib/sendmail/src/timers.h
index e86b6ec..d7faee1 100644
--- a/contrib/sendmail/src/timers.h
+++ b/contrib/sendmail/src/timers.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
- * $Id: timers.h,v 8.4 1999/11/04 19:31:26 ca Exp $
+ * $Id: timers.h,v 8.6 2001/04/03 01:53:18 gshapiro Exp $
*
* Contributed by Exactis.com, Inc.
*
@@ -30,4 +30,4 @@ TIMER
extern void pushtimer __P((TIMER *));
extern void poptimer __P((TIMER *));
extern char *strtimer __P((TIMER *));
-#endif /* TIMERS_H */
+#endif /* ! TIMERS_H */
diff --git a/contrib/sendmail/src/tls.c b/contrib/sendmail/src/tls.c
new file mode 100644
index 0000000..2eb0047
--- /dev/null
+++ b/contrib/sendmail/src/tls.c
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sendmail.h>
+
+SM_RCSID("@(#)$Id: tls.c,v 8.75 2001/09/11 04:05:17 gshapiro Exp $")
+
+#if STARTTLS
+# include <openssl/err.h>
+# include <openssl/bio.h>
+# include <openssl/pem.h>
+# ifndef HASURANDOMDEV
+# include <openssl/rand.h>
+# endif /* ! HASURANDOMDEV */
+# if SM_CONF_SHM
+# include <sm/shm.h>
+# endif /* SM_CONF_SHM */
+# if !TLS_NO_RSA
+static RSA *rsa_tmp = NULL; /* temporary RSA key */
+static RSA *tmp_rsa_key __P((SSL *, int, int));
+# endif /* !TLS_NO_RSA */
+static int tls_verify_cb __P((X509_STORE_CTX *));
+
+static void apps_ssl_info_cb __P((SSL *, int , int));
+
+# if !NO_DH
+static DH *get_dh512 __P((void));
+
+static unsigned char dh512_p[] =
+{
+ 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
+ 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
+ 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
+ 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
+ 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
+ 0x47,0x74,0xE8,0x33
+};
+static unsigned char dh512_g[] =
+{
+ 0x02
+};
+
+static DH *
+get_dh512()
+{
+ DH *dh = NULL;
+
+ if ((dh = DH_new()) == NULL)
+ return NULL;
+ dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
+ dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return NULL;
+ return dh;
+}
+# endif /* !NO_DH */
+
+
+/*
+** TLS_RAND_INIT -- initialize STARTTLS random generator
+**
+** Parameters:
+** randfile -- name of file with random data
+** logl -- loglevel
+**
+** Returns:
+** success/failure
+**
+** Side Effects:
+** initializes PRNG for tls library.
+*/
+
+# define MIN_RAND_BYTES 128 /* 1024 bits */
+
+# define RF_OK 0 /* randfile OK */
+# define RF_MISS 1 /* randfile == NULL || *randfile == '\0' */
+# define RF_UNKNOWN 2 /* unknown prefix for randfile */
+
+# define RI_NONE 0 /* no init yet */
+# define RI_SUCCESS 1 /* init was successful */
+# define RI_FAIL 2 /* init failed */
+
+static bool tls_rand_init __P((char *, int));
+
+static bool
+tls_rand_init(randfile, logl)
+ char *randfile;
+ int logl;
+{
+# ifndef HASURANDOMDEV
+ /* not required if /dev/urandom exists, OpenSSL does it internally */
+
+ bool ok;
+ int randdef;
+ static int done = RI_NONE;
+
+ /*
+ ** initialize PRNG
+ */
+
+ /* did we try this before? if yes: return old value */
+ if (done != RI_NONE)
+ return done == RI_SUCCESS;
+
+ /* set default values */
+ ok = false;
+ done = RI_FAIL;
+ randdef = (randfile == NULL || *randfile == '\0') ? RF_MISS : RF_OK;
+# if EGD
+ if (randdef == RF_OK && sm_strncasecmp(randfile, "egd:", 4) == 0)
+ {
+ randfile += 4;
+ if (RAND_egd(randfile) < 0)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: RAND_egd(%s) failed: random number generator not seeded",
+ randfile);
+ }
+ else
+ ok = true;
+ }
+ else
+# endif /* EGD */
+ if (randdef == RF_OK && sm_strncasecmp(randfile, "file:", 5) == 0)
+ {
+ int fd;
+ long sff;
+ struct stat st;
+
+ randfile += 5;
+ sff = SFF_SAFEDIRPATH | SFF_NOWLINK
+ | SFF_NOGWFILES | SFF_NOWWFILES
+ | SFF_NOGRFILES | SFF_NOWRFILES
+ | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
+ if ((fd = safeopen(randfile, O_RDONLY, 0, sff)) >= 0)
+ {
+ if (fstat(fd, &st) < 0)
+ {
+ if (LogLevel > logl)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS: can't fstat(%s)",
+ randfile);
+ }
+ else
+ {
+ bool use, problem;
+
+ use = true;
+ problem = false;
+
+ /* max. age of file: 10 minutes */
+ if (st.st_mtime + 600 < curtime())
+ {
+ use = bitnset(DBS_INSUFFICIENTENTROPY,
+ DontBlameSendmail);
+ problem = true;
+ if (LogLevel > logl)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS: RandFile %s too old: %s",
+ randfile,
+ use ? "unsafe" :
+ "unusable");
+ }
+ if (use && st.st_size < MIN_RAND_BYTES)
+ {
+ use = bitnset(DBS_INSUFFICIENTENTROPY,
+ DontBlameSendmail);
+ problem = true;
+ if (LogLevel > logl)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS: size(%s) < %d: %s",
+ randfile,
+ MIN_RAND_BYTES,
+ use ? "unsafe" :
+ "unusable");
+ }
+ if (use)
+ ok = RAND_load_file(randfile, -1) >=
+ MIN_RAND_BYTES;
+ if (use && !ok)
+ {
+ if (LogLevel > logl)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: RAND_load_file(%s) failed: random number generator not seeded",
+ randfile);
+ }
+ if (problem)
+ ok = false;
+ }
+ if (ok || bitnset(DBS_INSUFFICIENTENTROPY,
+ DontBlameSendmail))
+ {
+ /* add this even if fstat() failed */
+ RAND_seed((void *) &st, sizeof st);
+ }
+ (void) close(fd);
+ }
+ else
+ {
+ if (LogLevel > logl)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: Warning: safeopen(%s) failed",
+ randfile);
+ }
+ }
+ else if (randdef == RF_OK)
+ {
+ if (LogLevel > logl)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: Error: no proper random file definition %s",
+ randfile);
+ randdef = RF_UNKNOWN;
+ }
+ if (randdef == RF_MISS)
+ {
+ if (LogLevel > logl)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: Error: missing random file definition");
+ }
+ if (!ok && bitnset(DBS_INSUFFICIENTENTROPY, DontBlameSendmail))
+ {
+ int i;
+ long r;
+ unsigned char buf[MIN_RAND_BYTES];
+
+ /* assert((MIN_RAND_BYTES % sizeof(long)) == 0); */
+ for (i = 0; i <= sizeof(buf) - sizeof(long); i += sizeof(long))
+ {
+ r = get_random();
+ (void) memcpy(buf + i, (void *) &r, sizeof(long));
+ }
+ RAND_seed(buf, sizeof buf);
+ if (LogLevel > logl)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: Warning: random number generator not properly seeded");
+ ok = true;
+ }
+ done = ok ? RI_SUCCESS : RI_FAIL;
+ return ok;
+# else /* ! HASURANDOMDEV */
+ return true;
+# endif /* ! HASURANDOMDEV */
+}
+/*
+** INIT_TLS_LIBRARY -- Calls functions which setup TLS library for global use.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** succeeded?
+*/
+
+bool
+init_tls_library()
+{
+ /* basic TLS initialization, ignore result for now */
+ SSL_library_init();
+ SSL_load_error_strings();
+# if 0
+ /* this is currently a macro for SSL_library_init */
+ SSLeay_add_ssl_algorithms();
+# endif /* 0 */
+
+ return tls_rand_init(RandFile, 7);
+}
+/*
+** TLS_SET_VERIFY -- request client certificate?
+**
+** Parameters:
+** ctx -- TLS context
+** ssl -- TLS structure
+** vrfy -- require certificate?
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets verification state for TLS
+**
+# if TLS_VRFY_PER_CTX
+** Notice:
+** This is per TLS context, not per TLS structure;
+** the former is global, the latter per connection.
+** It would be nice to do this per connection, but this
+** doesn't work in the current TLS libraries :-(
+# endif * TLS_VRFY_PER_CTX *
+*/
+
+void
+tls_set_verify(ctx, ssl, vrfy)
+ SSL_CTX *ctx;
+ SSL *ssl;
+ bool vrfy;
+{
+# if !TLS_VRFY_PER_CTX
+ SSL_set_verify(ssl, vrfy ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+# else /* !TLS_VRFY_PER_CTX */
+ SSL_CTX_set_verify(ctx, vrfy ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
+ NULL);
+# endif /* !TLS_VRFY_PER_CTX */
+}
+
+/*
+** status in initialization
+** these flags keep track of the status of the initialization
+** i.e., whether a file exists (_EX) and whether it can be used (_OK)
+** [due to permissions]
+*/
+
+# define TLS_S_NONE 0x00000000 /* none yet */
+# define TLS_S_CERT_EX 0x00000001 /* CERT file exists */
+# define TLS_S_CERT_OK 0x00000002 /* CERT file is ok */
+# define TLS_S_KEY_EX 0x00000004 /* KEY file exists */
+# define TLS_S_KEY_OK 0x00000008 /* KEY file is ok */
+# define TLS_S_CERTP_EX 0x00000010 /* CA CERT PATH exists */
+# define TLS_S_CERTP_OK 0x00000020 /* CA CERT PATH is ok */
+# define TLS_S_CERTF_EX 0x00000040 /* CA CERT FILE exists */
+# define TLS_S_CERTF_OK 0x00000080 /* CA CERT FILE is ok */
+
+# if _FFR_TLS_1
+# define TLS_S_CERT2_EX 0x00001000 /* 2nd CERT file exists */
+# define TLS_S_CERT2_OK 0x00002000 /* 2nd CERT file is ok */
+# define TLS_S_KEY2_EX 0x00004000 /* 2nd KEY file exists */
+# define TLS_S_KEY2_OK 0x00008000 /* 2nd KEY file is ok */
+# endif /* _FFR_TLS_1 */
+
+# define TLS_S_DH_OK 0x00200000 /* DH cert is ok */
+# define TLS_S_DHPAR_EX 0x00400000 /* DH param file exists */
+# define TLS_S_DHPAR_OK 0x00800000 /* DH param file is ok to use */
+
+/*
+** TLS_OK_F -- can var be an absolute filename?
+**
+** Parameters:
+** var -- filename
+** fn -- what is the filename used for?
+** srv -- server side?
+**
+** Returns:
+** ok?
+*/
+
+static bool
+tls_ok_f(var, fn, srv)
+ char *var;
+ char *fn;
+ bool srv;
+{
+ /* must be absolute pathname */
+ if (var != NULL && *var == '/')
+ return true;
+ if (LogLevel > 12)
+ sm_syslog(LOG_WARNING, NOQID, "STARTTLS: %s%s missing",
+ srv ? "Server" : "Client", fn);
+ return false;
+}
+/*
+** TLS_SAFE_F -- is a file safe to use?
+**
+** Parameters:
+** var -- filename
+** sff -- flags for safefile()
+** srv -- server side?
+**
+** Returns:
+** ok?
+*/
+
+static bool
+tls_safe_f(var, sff, srv)
+ char *var;
+ long sff;
+ bool srv;
+{
+ int ret;
+
+ if ((ret = safefile(var, RunAsUid, RunAsGid, RunAsUserName, sff,
+ S_IRUSR, NULL)) == 0)
+ return true;
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID, "STARTTLS=%s: file %s unsafe: %s",
+ srv ? "server" : "client", var, sm_errstring(ret));
+ return false;
+}
+
+/*
+** TLS_OK_F -- macro to simplify calls to tls_ok_f
+**
+** Parameters:
+** var -- filename
+** fn -- what is the filename used for?
+** req -- is the file required?
+** st -- status bit to set if ok
+** srv -- server side?
+**
+** Side Effects:
+** uses r, ok; may change ok and status.
+**
+*/
+
+# define TLS_OK_F(var, fn, req, st, srv) if (ok) \
+ { \
+ r = tls_ok_f(var, fn, srv); \
+ if (r) \
+ status |= st; \
+ else if (req) \
+ ok = false; \
+ }
+
+/*
+** TLS_UNR -- macro to return whether a file should be unreadable
+**
+** Parameters:
+** bit -- flag to test
+** req -- flags
+**
+** Returns:
+** 0/SFF_NORFILES
+*/
+# define TLS_UNR(bit, req) (bitset(bit, req) ? SFF_NORFILES : 0)
+# define TLS_OUNR(bit, req) (bitset(bit, req) ? SFF_NOWRFILES : 0)
+# define TLS_KEYSFF(req) \
+ (bitnset(DBS_GROUPREADABLEKEYFILE, DontBlameSendmail) ? \
+ TLS_OUNR(TLS_I_KEY_OUNR, req) : \
+ TLS_UNR(TLS_I_KEY_UNR, req))
+
+/*
+** TLS_SAFE_F -- macro to simplify calls to tls_safe_f
+**
+** Parameters:
+** var -- filename
+** sff -- flags for safefile()
+** req -- is the file required?
+** ex -- does the file exist?
+** st -- status bit to set if ok
+** srv -- server side?
+**
+** Side Effects:
+** uses r, ok, ex; may change ok and status.
+**
+*/
+
+# define TLS_SAFE_F(var, sff, req, ex, st, srv) if (ex && ok) \
+ { \
+ r = tls_safe_f(var, sff, srv); \
+ if (r) \
+ status |= st; \
+ else if (req) \
+ ok = false; \
+ }
+
+/*
+** INITTLS -- initialize TLS
+**
+** Parameters:
+** ctx -- pointer to context
+** req -- requirements for initialization (see sendmail.h)
+** srv -- server side?
+** certfile -- filename of certificate
+** keyfile -- filename of private key
+** cacertpath -- path to CAs
+** cacertfile -- file with CA(s)
+** dhparam -- parameters for DH
+**
+** Returns:
+** succeeded?
+*/
+
+bool
+inittls(ctx, req, srv, certfile, keyfile, cacertpath, cacertfile, dhparam)
+ SSL_CTX **ctx;
+ unsigned long req;
+ bool srv;
+ char *certfile, *keyfile, *cacertpath, *cacertfile, *dhparam;
+{
+# if !NO_DH
+ static DH *dh = NULL;
+# endif /* !NO_DH */
+ int r;
+ bool ok;
+ long sff, status;
+ char *who;
+# if _FFR_TLS_1
+ char *cf2, *kf2;
+# endif /* _FFR_TLS_1 */
+# if SM_CONF_SHM
+ extern int ShmId;
+# endif /* SM_CONF_SHM */
+
+ status = TLS_S_NONE;
+ who = srv ? "server" : "client";
+ if (ctx == NULL)
+ syserr("STARTTLS=%s, inittls: ctx == NULL", who);
+
+ /* already initialized? (we could re-init...) */
+ if (*ctx != NULL)
+ return true;
+ ok = true;
+
+# if _FFR_TLS_1
+ /*
+ ** look for a second filename: it must be separated by a ','
+ ** no blanks allowed (they won't be skipped).
+ ** we change a global variable here! this change will be undone
+ ** before return from the function but only if it returns true.
+ ** this isn't a problem since in a failure case this function
+ ** won't be called again with the same (overwritten) values.
+ ** otherwise each return must be replaced with a goto endinittls.
+ */
+
+ cf2 = NULL;
+ kf2 = NULL;
+ if (certfile != NULL && (cf2 = strchr(certfile, ',')) != NULL)
+ {
+ *cf2++ = '\0';
+ if (keyfile != NULL && (kf2 = strchr(keyfile, ',')) != NULL)
+ *kf2++ = '\0';
+ }
+# endif /* _FFR_TLS_1 */
+
+ /*
+ ** Check whether files/paths are defined
+ */
+
+ TLS_OK_F(certfile, "CertFile", bitset(TLS_I_CERT_EX, req),
+ TLS_S_CERT_EX, srv);
+ TLS_OK_F(keyfile, "KeyFile", bitset(TLS_I_KEY_EX, req),
+ TLS_S_KEY_EX, srv);
+ TLS_OK_F(cacertpath, "CACERTPath", bitset(TLS_I_CERTP_EX, req),
+ TLS_S_CERTP_EX, srv);
+ TLS_OK_F(cacertfile, "CACERTFile", bitset(TLS_I_CERTF_EX, req),
+ TLS_S_CERTF_EX, srv);
+
+# if _FFR_TLS_1
+ /*
+ ** if the second file is specified it must exist
+ ** XXX: it is possible here to define only one of those files
+ */
+
+ if (cf2 != NULL)
+ {
+ TLS_OK_F(cf2, "CertFile", bitset(TLS_I_CERT_EX, req),
+ TLS_S_CERT2_EX, srv);
+ }
+ if (kf2 != NULL)
+ {
+ TLS_OK_F(kf2, "KeyFile", bitset(TLS_I_KEY_EX, req),
+ TLS_S_KEY2_EX, srv);
+ }
+# endif /* _FFR_TLS_1 */
+
+ /*
+ ** valid values for dhparam are (only the first char is checked)
+ ** none no parameters: don't use DH
+ ** 512 generate 512 bit parameters (fixed)
+ ** 1024 generate 1024 bit parameters
+ ** /file/name read parameters from /file/name
+ ** default is: 1024 for server, 512 for client (OK? XXX)
+ */
+
+ if (bitset(TLS_I_TRY_DH, req))
+ {
+ if (dhparam != NULL)
+ {
+ char c = *dhparam;
+
+ if (c == '1')
+ req |= TLS_I_DH1024;
+ else if (c == '5')
+ req |= TLS_I_DH512;
+ else if (c != 'n' && c != 'N' && c != '/')
+ {
+ if (LogLevel > 12)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: illegal value '%s' for DHParam",
+ who, dhparam);
+ dhparam = NULL;
+ }
+ }
+ if (dhparam == NULL)
+ dhparam = srv ? "1" : "5";
+ else if (*dhparam == '/')
+ {
+ TLS_OK_F(dhparam, "DHParameters",
+ bitset(TLS_I_DHPAR_EX, req),
+ TLS_S_DHPAR_EX, srv);
+ }
+ }
+ if (!ok)
+ return ok;
+
+ /* certfile etc. must be "safe". */
+ sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
+ | SFF_NOGWFILES | SFF_NOWWFILES
+ | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
+ if (DontLockReadFiles)
+ sff |= SFF_NOLOCK;
+
+ TLS_SAFE_F(certfile, sff | TLS_UNR(TLS_I_CERT_UNR, req),
+ bitset(TLS_I_CERT_EX, req),
+ bitset(TLS_S_CERT_EX, status), TLS_S_CERT_OK, srv);
+ TLS_SAFE_F(keyfile, sff | TLS_KEYSFF(req),
+ bitset(TLS_I_KEY_EX, req),
+ bitset(TLS_S_KEY_EX, status), TLS_S_KEY_OK, srv);
+ TLS_SAFE_F(cacertfile, sff | TLS_UNR(TLS_I_CERTF_UNR, req),
+ bitset(TLS_I_CERTF_EX, req),
+ bitset(TLS_S_CERTF_EX, status), TLS_S_CERTF_OK, srv);
+ TLS_SAFE_F(dhparam, sff | TLS_UNR(TLS_I_DHPAR_UNR, req),
+ bitset(TLS_I_DHPAR_EX, req),
+ bitset(TLS_S_DHPAR_EX, status), TLS_S_DHPAR_OK, srv);
+ if (!ok)
+ return ok;
+# if _FFR_TLS_1
+ if (cf2 != NULL)
+ {
+ TLS_SAFE_F(cf2, sff | TLS_UNR(TLS_I_CERT_UNR, req),
+ bitset(TLS_I_CERT_EX, req),
+ bitset(TLS_S_CERT2_EX, status), TLS_S_CERT2_OK, srv);
+ }
+ if (kf2 != NULL)
+ {
+ TLS_SAFE_F(kf2, sff | TLS_KEYSFF(req),
+ bitset(TLS_I_KEY_EX, req),
+ bitset(TLS_S_KEY2_EX, status), TLS_S_KEY2_OK, srv);
+ }
+# endif /* _FFR_TLS_1 */
+
+ /* create a method and a new context */
+ if ((*ctx = SSL_CTX_new(srv ? SSLv23_server_method() :
+ SSLv23_client_method())) == NULL)
+ {
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_new(SSLv23_%s_method()) failed",
+ who, who);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ return false;
+ }
+
+# if TLS_NO_RSA
+ /* turn off backward compatibility, required for no-rsa */
+ SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2);
+# endif /* TLS_NO_RSA */
+
+
+# if !TLS_NO_RSA
+ /*
+ ** Create a temporary RSA key
+ ** XXX Maybe we shouldn't create this always (even though it
+ ** is only at startup).
+ ** It is a time-consuming operation and it is not always necessary.
+ ** maybe we should do it only on demand...
+ */
+
+ if (bitset(TLS_I_RSA_TMP, req)
+# if SM_CONF_SHM
+ && ShmId != SM_SHM_NO_ID &&
+ (rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL,
+ NULL)) == NULL
+# else /* SM_CONF_SHM */
+ && 0 /* no shared memory: no need to generate key now */
+# endif /* SM_CONF_SHM */
+ )
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: RSA_generate_key failed",
+ who);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ return false;
+ }
+# endif /* !TLS_NO_RSA */
+
+ /*
+ ** load private key
+ ** XXX change this for DSA-only version
+ */
+
+ if (bitset(TLS_S_KEY_OK, status) &&
+ SSL_CTX_use_PrivateKey_file(*ctx, keyfile,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_use_PrivateKey_file(%s) failed",
+ who, keyfile);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ if (bitset(TLS_I_USE_KEY, req))
+ return false;
+ }
+
+ /* get the certificate file */
+ if (bitset(TLS_S_CERT_OK, status) &&
+ SSL_CTX_use_certificate_file(*ctx, certfile,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_use_certificate_file(%s) failed",
+ who, certfile);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ if (bitset(TLS_I_USE_CERT, req))
+ return false;
+ }
+
+ /* check the private key */
+ if (bitset(TLS_S_KEY_OK, status) &&
+ (r = SSL_CTX_check_private_key(*ctx)) <= 0)
+ {
+ /* Private key does not match the certificate public key */
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_check_private_key failed(%s): %d",
+ who, keyfile, r);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ if (bitset(TLS_I_USE_KEY, req))
+ return false;
+ }
+
+# if _FFR_TLS_1
+ /* XXX this code is pretty much duplicated from above! */
+
+ /* load private key */
+ if (bitset(TLS_S_KEY2_OK, status) &&
+ SSL_CTX_use_PrivateKey_file(*ctx, kf2, SSL_FILETYPE_PEM) <= 0)
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_use_PrivateKey_file(%s) failed",
+ who, kf2);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ }
+
+ /* get the certificate file */
+ if (bitset(TLS_S_CERT2_OK, status) &&
+ SSL_CTX_use_certificate_file(*ctx, cf2, SSL_FILETYPE_PEM) <= 0)
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_use_certificate_file(%s) failed",
+ who, cf2);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ }
+
+ /* also check the private key */
+ if (bitset(TLS_S_KEY2_OK, status) &&
+ (r = SSL_CTX_check_private_key(*ctx)) <= 0)
+ {
+ /* Private key does not match the certificate public key */
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_check_private_key 2 failed: %d",
+ who, r);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ }
+# endif /* _FFR_TLS_1 */
+
+ /* SSL_CTX_set_quiet_shutdown(*ctx, 1); violation of standard? */
+ SSL_CTX_set_options(*ctx, SSL_OP_ALL); /* XXX bug compatibility? */
+
+# if !NO_DH
+ /* Diffie-Hellman initialization */
+ if (bitset(TLS_I_TRY_DH, req))
+ {
+ if (bitset(TLS_S_DHPAR_OK, status))
+ {
+ BIO *bio;
+
+ if ((bio = BIO_new_file(dhparam, "r")) != NULL)
+ {
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (dh == NULL && LogLevel > 7)
+ {
+ unsigned long err;
+
+ err = ERR_get_error();
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: cannot read DH parameters(%s): %s",
+ who, dhparam,
+ ERR_error_string(err, NULL));
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ }
+ else
+ {
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: BIO_new_file(%s) failed",
+ who, dhparam);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ }
+ }
+ if (dh == NULL && bitset(TLS_I_DH1024, req))
+ {
+ DSA *dsa;
+
+ /* this takes a while! (7-130s on a 450MHz AMD K6-2) */
+ dsa = DSA_generate_parameters(1024, NULL, 0, NULL,
+ NULL, 0, NULL);
+ dh = DSA_dup_DH(dsa);
+ DSA_free(dsa);
+ }
+ else
+ if (dh == NULL && bitset(TLS_I_DH512, req))
+ dh = get_dh512();
+
+ if (dh == NULL)
+ {
+ if (LogLevel > 9)
+ {
+ unsigned long err;
+
+ err = ERR_get_error();
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: cannot read or set DH parameters(%s): %s",
+ who, dhparam,
+ ERR_error_string(err, NULL));
+ }
+ if (bitset(TLS_I_REQ_DH, req))
+ return false;
+ }
+ else
+ {
+ SSL_CTX_set_tmp_dh(*ctx, dh);
+
+ /* important to avoid small subgroup attacks */
+ SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_DH_USE);
+ if (LogLevel > 13)
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=%s, Diffie-Hellman init, key=%d bit (%c)",
+ who, 8 * DH_size(dh), *dhparam);
+ DH_free(dh);
+ }
+ }
+# endif /* !NO_DH */
+
+
+ /* XXX do we need this cache here? */
+ if (bitset(TLS_I_CACHE, req))
+ SSL_CTX_sess_set_cache_size(*ctx, 128);
+ /* timeout? SSL_CTX_set_timeout(*ctx, TimeOut...); */
+
+ /* load certificate locations and default CA paths */
+ if (bitset(TLS_S_CERTP_EX, status) && bitset(TLS_S_CERTF_EX, status))
+ {
+ if ((r = SSL_CTX_load_verify_locations(*ctx, cacertfile,
+ cacertpath)) == 1)
+ {
+# if !TLS_NO_RSA
+ if (bitset(TLS_I_RSA_TMP, req))
+ SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key);
+# endif /* !TLS_NO_RSA */
+
+ /*
+ ** We have to install our own verify callback:
+ ** SSL_VERIFY_PEER requests a client cert but even
+ ** though *FAIL_IF* isn't set, the connection
+ ** will be aborted if the client presents a cert
+ ** that is not "liked" (can't be verified?) by
+ ** the TLS library :-(
+ */
+
+ /*
+ ** XXX currently we could call tls_set_verify()
+ ** but we hope that that function will later on
+ ** only set the mode per connection.
+ */
+ SSL_CTX_set_verify(*ctx,
+ bitset(TLS_I_NO_VRFY, req) ? SSL_VERIFY_NONE
+ : SSL_VERIFY_PEER,
+ NULL);
+
+ /* install verify callback */
+ SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb,
+ NULL);
+ SSL_CTX_set_client_CA_list(*ctx,
+ SSL_load_client_CA_file(cacertfile));
+ }
+ else
+ {
+ /*
+ ** can't load CA data; do we care?
+ ** the data is necessary to authenticate the client,
+ ** which in turn would be necessary
+ ** if we want to allow relaying based on it.
+ */
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: load verify locs %s, %s failed: %d",
+ who, cacertpath, cacertfile, r);
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ if (bitset(TLS_I_VRFY_LOC, req))
+ return false;
+ }
+ }
+
+ /* XXX: make this dependent on an option? */
+ if (tTd(96, 9))
+ SSL_CTX_set_info_callback(*ctx, apps_ssl_info_cb);
+
+# if _FFR_TLS_1
+ /* install our own cipher list */
+ if (CipherList != NULL && *CipherList != '\0')
+ {
+ if (SSL_CTX_set_cipher_list(*ctx, CipherList) <= 0)
+ {
+ if (LogLevel > 7)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, error: SSL_CTX_set_cipher_list(%s) failed, list ignored",
+ who, CipherList);
+
+ if (LogLevel > 9)
+ tlslogerr(who);
+ }
+ /* failure if setting to this list is required? */
+ }
+ }
+# endif /* _FFR_TLS_1 */
+ if (LogLevel > 12)
+ sm_syslog(LOG_INFO, NOQID, "STARTTLS=%s, init=%d", who, ok);
+
+# if _FFR_TLS_1
+# if 0
+ /*
+ ** this label is required if we want to have a "clean" exit
+ ** see the comments above at the initialization of cf2
+ */
+
+ endinittls:
+# endif /* 0 */
+
+ /* undo damage to global variables */
+ if (cf2 != NULL)
+ *--cf2 = ',';
+ if (kf2 != NULL)
+ *--kf2 = ',';
+# endif /* _FFR_TLS_1 */
+
+ return ok;
+}
+/*
+** TLS_GET_INFO -- get information about TLS connection
+**
+** Parameters:
+** ssl -- TLS connection structure
+** srv -- server or client
+** host -- hostname of other side
+** mac -- macro storage
+** certreq -- did we ask for a cert?
+**
+** Returns:
+** result of authentication.
+**
+** Side Effects:
+** sets macros: {cipher}, {tls_version}, {verify},
+** {cipher_bits}, {alg_bits}, {cert}, {cert_subject},
+** {cert_issuer}, {cn_subject}, {cn_issuer}
+*/
+
+int
+tls_get_info(ssl, srv, host, mac, certreq)
+ SSL *ssl;
+ bool srv;
+ char *host;
+ MACROS_T *mac;
+ bool certreq;
+{
+ SSL_CIPHER *c;
+ int b, r;
+ char *s, *who;
+ char bitstr[16];
+ X509 *cert;
+
+ c = SSL_get_current_cipher(ssl);
+
+ /* cast is just workaround for compiler warning */
+ macdefine(mac, A_TEMP, macid("{cipher}"),
+ (char *) SSL_CIPHER_get_name(c));
+ b = SSL_CIPHER_get_bits(c, &r);
+ (void) sm_snprintf(bitstr, sizeof bitstr, "%d", b);
+ macdefine(mac, A_TEMP, macid("{cipher_bits}"), bitstr);
+ (void) sm_snprintf(bitstr, sizeof bitstr, "%d", r);
+ macdefine(mac, A_TEMP, macid("{alg_bits}"), bitstr);
+ s = SSL_CIPHER_get_version(c);
+ if (s == NULL)
+ s = "UNKNOWN";
+ macdefine(mac, A_TEMP, macid("{tls_version}"), s);
+
+ who = srv ? "server" : "client";
+ cert = SSL_get_peer_certificate(ssl);
+ if (LogLevel > 14)
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=%s, get_verify: %ld get_peer: 0x%lx",
+ who, SSL_get_verify_result(ssl),
+ (unsigned long) cert);
+ if (cert != NULL)
+ {
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ char buf[MAXNAME];
+
+ X509_NAME_oneline(X509_get_subject_name(cert),
+ buf, sizeof buf);
+ macdefine(mac, A_TEMP, macid("{cert_subject}"),
+ xtextify(buf, "<>\")"));
+ X509_NAME_oneline(X509_get_issuer_name(cert),
+ buf, sizeof buf);
+ macdefine(mac, A_TEMP, macid("{cert_issuer}"),
+ xtextify(buf, "<>\")"));
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
+ NID_commonName, buf, sizeof buf);
+ macdefine(mac, A_TEMP, macid("{cn_subject}"),
+ xtextify(buf, "<>\")"));
+ X509_NAME_get_text_by_NID(X509_get_issuer_name(cert),
+ NID_commonName, buf, sizeof buf);
+ macdefine(mac, A_TEMP, macid("{cn_issuer}"),
+ xtextify(buf, "<>\")"));
+ if (X509_digest(cert, EVP_md5(), md, &n))
+ {
+ char md5h[EVP_MAX_MD_SIZE * 3];
+ static const char hexcodes[] = "0123456789ABCDEF";
+
+ SM_ASSERT((n * 3) + 2 < sizeof(md5h));
+ for (r = 0; r < (int) n; r++)
+ {
+ md5h[r * 3] = hexcodes[(md[r] & 0xf0) >> 4];
+ md5h[(r * 3) + 1] = hexcodes[(md[r] & 0x0f)];
+ md5h[(r * 3) + 2] = ':';
+ }
+ md5h[(n * 3) - 1] = '\0';
+ macdefine(mac, A_TEMP, macid("{cert_md5}"), md5h);
+ }
+ else
+ macdefine(mac, A_TEMP, macid("{cert_md5}"), "");
+ }
+ else
+ {
+ macdefine(mac, A_PERM, macid("{cert_subject}"), "");
+ macdefine(mac, A_PERM, macid("{cert_issuer}"), "");
+ macdefine(mac, A_PERM, macid("{cn_subject}"), "");
+ macdefine(mac, A_PERM, macid("{cn_issuer}"), "");
+ macdefine(mac, A_TEMP, macid("{cert_md5}"), "");
+ }
+ switch (SSL_get_verify_result(ssl))
+ {
+ case X509_V_OK:
+ if (cert != NULL)
+ {
+ s = "OK";
+ r = TLS_AUTH_OK;
+ }
+ else
+ {
+ s = certreq ? "NO" : "NOT",
+ r = TLS_AUTH_NO;
+ }
+ break;
+ default:
+ s = "FAIL";
+ r = TLS_AUTH_FAIL;
+ break;
+ }
+ macdefine(mac, A_PERM, macid("{verify}"), s);
+ if (cert != NULL)
+ X509_free(cert);
+
+ /* do some logging */
+ if (LogLevel > 8)
+ {
+ char *vers, *s1, *s2, *cbits, *algbits;
+
+ vers = macget(mac, macid("{tls_version}"));
+ cbits = macget(mac, macid("{cipher_bits}"));
+ algbits = macget(mac, macid("{alg_bits}"));
+ s1 = macget(mac, macid("{verify}"));
+ s2 = macget(mac, macid("{cipher}"));
+
+ /* XXX: maybe cut off ident info? */
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=%s, relay=%.100s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s/%.6s",
+ who,
+ host == NULL ? "local" : host,
+ vers, s1, s2, /* sm_snprintf() can deal with NULL */
+ algbits == NULL ? "0" : algbits,
+ cbits == NULL ? "0" : cbits);
+ if (LogLevel > 11)
+ {
+ /*
+ ** Maybe run xuntextify on the strings?
+ ** That is easier to read but makes it maybe a bit
+ ** more complicated to figure out the right values
+ ** for the access map...
+ */
+
+ s1 = macget(mac, macid("{cert_subject}"));
+ s2 = macget(mac, macid("{cert_issuer}"));
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=%s, cert-subject=%.128s, cert-issuer=%.128s",
+ who, s1, s2);
+ }
+ }
+ return r;
+}
+/*
+** ENDTLS -- shutdown secure connection
+**
+** Parameters:
+** ssl -- SSL connection information.
+** side -- server/client (for logging).
+**
+** Returns:
+** success? (EX_* code)
+*/
+
+int
+endtls(ssl, side)
+ SSL *ssl;
+ char *side;
+{
+ int ret = EX_OK;
+
+ if (ssl != NULL)
+ {
+ int r;
+
+ if ((r = SSL_shutdown(ssl)) < 0)
+ {
+ if (LogLevel > 11)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, SSL_shutdown failed: %d",
+ side, r);
+ tlslogerr(side);
+ }
+ ret = EX_SOFTWARE;
+ }
+# if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER > 0x0090602fL
+
+ /*
+ ** Bug in OpenSSL (at least up to 0.9.6b):
+ ** From: Lutz.Jaenicke@aet.TU-Cottbus.DE
+ ** Message-ID: <20010723152244.A13122@serv01.aet.tu-cottbus.de>
+ ** To: openssl-users@openssl.org
+ ** Subject: Re: SSL_shutdown() woes (fwd)
+ **
+ ** The side sending the shutdown alert first will
+ ** not care about the answer of the peer but will
+ ** immediately return with a return value of "0"
+ ** (ssl/s3_lib.c:ssl3_shutdown()). SSL_get_error will evaluate
+ ** the value of "0" and as the shutdown alert of the peer was
+ ** not received (actually, the program did not even wait for
+ ** the answer), an SSL_ERROR_SYSCALL is flagged, because this
+ ** is the default rule in case everything else does not apply.
+ **
+ ** For your server the problem is different, because it
+ ** receives the shutdown first (setting SSL_RECEIVED_SHUTDOWN),
+ ** then sends its response (SSL_SENT_SHUTDOWN), so for the
+ ** server the shutdown was successfull.
+ **
+ ** As is by know, you would have to call SSL_shutdown() once
+ ** and ignore an SSL_ERROR_SYSCALL returned. Then call
+ ** SSL_shutdown() again to actually get the server's response.
+ **
+ ** In the last discussion, Bodo Moeller concluded that a
+ ** rewrite of the shutdown code would be necessary, but
+ ** probably with another API, as the change would not be
+ ** compatible to the way it is now. Things do not become
+ ** easier as other programs do not follow the shutdown
+ ** guidelines anyway, so that a lot error conditions and
+ ** compitibility issues would have to be caught.
+ **
+ ** For now the recommondation is to ignore the error message.
+ */
+
+ else if (r == 0)
+ {
+ if (LogLevel > 15)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, SSL_shutdown not done",
+ side);
+ tlslogerr(side);
+ }
+ ret = EX_SOFTWARE;
+ }
+# endif /* !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER > 0x0090602fL */
+ SSL_free(ssl);
+ ssl = NULL;
+ }
+ return ret;
+}
+
+# if !TLS_NO_RSA
+/*
+** TMP_RSA_KEY -- return temporary RSA key
+**
+** Parameters:
+** s -- TLS connection structure
+** export --
+** keylength --
+**
+** Returns:
+** temporary RSA key.
+*/
+
+# ifndef MAX_RSA_TMP_CNT
+# define MAX_RSA_TMP_CNT 1000 /* XXX better value? */
+# endif /* ! MAX_RSA_TMP_CNT */
+
+/* ARGUSED0 */
+static RSA *
+tmp_rsa_key(s, export, keylength)
+ SSL *s;
+ int export;
+ int keylength;
+{
+# if SM_CONF_SHM
+ extern int ShmId;
+ extern int *PRSATmpCnt;
+
+ if (ShmId != SM_SHM_NO_ID && rsa_tmp != NULL &&
+ ++(*PRSATmpCnt) < MAX_RSA_TMP_CNT)
+ return rsa_tmp;
+# endif /* SM_CONF_SHM */
+
+ if (rsa_tmp != NULL)
+ RSA_free(rsa_tmp);
+ rsa_tmp = RSA_generate_key(RSA_KEYLENGTH, RSA_F4, NULL, NULL);
+ if (rsa_tmp == NULL)
+ {
+ if (LogLevel > 0)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=server, tmp_rsa_key: RSA_generate_key failed!");
+ }
+ else
+ {
+# if SM_CONF_SHM
+# if 0
+ /*
+ ** XXX we can't (yet) share the new key...
+ ** The RSA structure contains pointers hence it can't be
+ ** easily kept in shared memory. It must be transformed
+ ** into a continous memory region first, then stored,
+ ** and later read out again (each time re-transformed).
+ */
+
+ if (ShmId != SM_SHM_NO_ID)
+ *PRSATmpCnt = 0;
+# endif /* 0 */
+# endif /* SM_CONF_SHM */
+ if (LogLevel > 9)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=server, tmp_rsa_key: new temp RSA key");
+ }
+ return rsa_tmp;
+}
+# endif /* !TLS_NO_RSA */
+/*
+** APPS_SSL_INFO_CB -- info callback for TLS connections
+**
+** Parameters:
+** s -- TLS connection structure
+** where -- state in handshake
+** ret -- return code of last operation
+**
+** Returns:
+** none.
+*/
+
+static void
+apps_ssl_info_cb(s, where, ret)
+ SSL *s;
+ int where;
+ int ret;
+{
+ int w;
+ char *str;
+ BIO *bio_err = NULL;
+
+ if (LogLevel > 14)
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS: info_callback where=0x%x, ret=%d",
+ where, ret);
+
+ w = where & ~SSL_ST_MASK;
+ if (bio_err == NULL)
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ if (bitset(SSL_ST_CONNECT, w))
+ str = "SSL_connect";
+ else if (bitset(SSL_ST_ACCEPT, w))
+ str = "SSL_accept";
+ else
+ str = "undefined";
+
+ if (bitset(SSL_CB_LOOP, where))
+ {
+ if (LogLevel > 12)
+ sm_syslog(LOG_NOTICE, NOQID,
+ "STARTTLS: %s:%s",
+ str, SSL_state_string_long(s));
+ }
+ else if (bitset(SSL_CB_ALERT, where))
+ {
+ str = bitset(SSL_CB_READ, where) ? "read" : "write";
+ if (LogLevel > 12)
+ sm_syslog(LOG_NOTICE, NOQID,
+ "STARTTLS: SSL3 alert %s:%s:%s",
+ str, SSL_alert_type_string_long(ret),
+ SSL_alert_desc_string_long(ret));
+ }
+ else if (bitset(SSL_CB_EXIT, where))
+ {
+ if (ret == 0)
+ {
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: %s:failed in %s",
+ str, SSL_state_string_long(s));
+ }
+ else if (ret < 0)
+ {
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: %s:error in %s",
+ str, SSL_state_string_long(s));
+ }
+ }
+}
+/*
+** TLS_VERIFY_LOG -- log verify error for TLS certificates
+**
+** Parameters:
+** ok -- verify ok?
+** ctx -- x509 context
+**
+** Returns:
+** 0 -- fatal error
+** 1 -- ok
+*/
+
+static int
+tls_verify_log(ok, ctx)
+ int ok;
+ X509_STORE_CTX *ctx;
+{
+ SSL *ssl;
+ X509 *cert;
+ int reason, depth;
+ char buf[512];
+
+ cert = X509_STORE_CTX_get_current_cert(ctx);
+ reason = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+ ssl = (SSL *) X509_STORE_CTX_get_ex_data(ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+
+ if (ssl == NULL)
+ {
+ /* internal error */
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS: internal error: tls_verify_cb: ssl == NULL");
+ return 0;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof buf);
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS: cert verify: depth=%d %s, state=%d, reason=%s",
+ depth, buf, ok, X509_verify_cert_error_string(reason));
+ return 1;
+}
+/*
+** TLS_VERIFY_CB -- verify callback for TLS certificates
+**
+** Parameters:
+** ctx -- x509 context
+**
+** Returns:
+** accept connection?
+** currently: always yes.
+*/
+
+static int
+tls_verify_cb(ctx)
+ X509_STORE_CTX *ctx;
+{
+ int ok;
+
+ ok = X509_verify_cert(ctx);
+ if (ok == 0)
+ {
+ if (LogLevel > 13)
+ return tls_verify_log(ok, ctx);
+ return 1; /* override it */
+ }
+ return ok;
+}
+/*
+** TLSLOGERR -- log the errors from the TLS error stack
+**
+** Parameters:
+** who -- server/client (for logging).
+**
+** Returns:
+** none.
+*/
+
+void
+tlslogerr(who)
+ char *who;
+{
+ unsigned long l;
+ int line, flags;
+ unsigned long es;
+ char *file, *data;
+ char buf[256];
+# define CP (const char **)
+
+ es = CRYPTO_thread_id();
+ while ((l = ERR_get_error_line_data(CP &file, &line, CP &data, &flags))
+ != 0)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s: %lu:%s:%s:%d:%s", who, es,
+ ERR_error_string(l, buf),
+ file, line,
+ bitset(ERR_TXT_STRING, flags) ? data : "");
+ }
+}
+#endif /* STARTTLS */
diff --git a/contrib/sendmail/src/trace.c b/contrib/sendmail/src/trace.c
index 735ef83..701a949 100644
--- a/contrib/sendmail/src/trace.c
+++ b/contrib/sendmail/src/trace.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,11 +11,14 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: trace.c,v 8.20.22.4 2001/08/15 13:05:43 ca Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
+#include <sm/debug.h>
+#include <sm/string.h>
+
+SM_RCSID("@(#)$Id: trace.c,v 8.37 2001/09/11 04:05:17 gshapiro Exp $")
+
+static char *tTnewflag __P((char *));
+static char *tToldflag __P((char *));
/*
** TtSETUP -- set up for trace package.
@@ -32,93 +35,190 @@ static char id[] = "@(#)$Id: trace.c,v 8.20.22.4 2001/08/15 13:05:43 ca Exp $";
** environment is set up.
*/
-static u_char *tTvect;
-static int tTsize;
+static unsigned char *tTvect;
+static unsigned int tTsize;
static char *DefFlags;
void
tTsetup(vect, size, defflags)
- u_char *vect;
- int size;
+ unsigned char *vect;
+ unsigned int size;
char *defflags;
{
tTvect = vect;
tTsize = size;
DefFlags = defflags;
}
- /*
-** TtFLAG -- process an external trace flag description.
+
+/*
+** tToldflag -- process an old style trace flag
**
** Parameters:
-** s -- the trace flag.
+** s -- points to a [\0, \t] terminated string,
+** and the initial character is a digit.
**
** Returns:
-** none.
+** pointer to terminating [\0, \t] character
**
** Side Effects:
-** sets/clears trace flags.
+** modifies tTvect
*/
-void
-tTflag(s)
+static char *
+tToldflag(s)
register char *s;
{
unsigned int first, last;
register unsigned int i;
- if (*s == '\0')
- s = DefFlags;
+ /* find first flag to set */
+ i = 0;
+ while (isascii(*s) && isdigit(*s) && i < tTsize)
+ i = i * 10 + (*s++ - '0');
- for (;;)
+ /*
+ ** skip over rest of a too large number
+ ** Maybe we should complain if out-of-bounds values are used.
+ */
+
+ while (isascii(*s) && isdigit(*s) && i >= tTsize)
+ s++;
+ first = i;
+
+ /* find last flag to set */
+ if (*s == '-')
{
- /* find first flag to set */
i = 0;
- while (isascii(*s) && isdigit(*s) && i < tTsize)
- i = i * 10 + (*s++ - '0');
-
- /*
- ** skip over rest of a too large number
- ** Maybe we should complain if out-of-bounds values are used.
- */
+ while (isascii(*++s) && isdigit(*s) && i < tTsize)
+ i = i * 10 + (*s - '0');
+ /* skip over rest of a too large number */
while (isascii(*s) && isdigit(*s) && i >= tTsize)
s++;
- first = i;
+ }
+ last = i;
- /* find last flag to set */
- if (*s == '-')
- {
- i = 0;
- while (isascii(*++s) && isdigit(*s) && i < tTsize)
- i = i * 10 + (*s - '0');
+ /* find the level to set it to */
+ i = 1;
+ if (*s == '.')
+ {
+ i = 0;
+ while (isascii(*++s) && isdigit(*s))
+ i = i * 10 + (*s - '0');
+ }
- /* skip over rest of a too large number */
- while (isascii(*s) && isdigit(*s) && i >= tTsize)
- s++;
- }
- last = i;
+ /* clean up args */
+ if (first >= tTsize)
+ first = tTsize - 1;
+ if (last >= tTsize)
+ last = tTsize - 1;
+
+ /* set the flags */
+ while (first <= last)
+ tTvect[first++] = (unsigned char) i;
+
+ /* skip trailing junk */
+ while (*s != '\0' && *s != ',' && *s != ' ' && *s != '\t')
+ ++s;
+
+ return s;
+}
+
+/*
+** tTnewflag -- process a new style trace flag
+**
+** Parameters:
+** s -- Points to a non-empty [\0, \t] terminated string,
+** of which the initial character is not a digit.
+**
+** Returns:
+** pointer to terminating [\0, \t] character
+**
+** Side Effects:
+** adds trace flag to libsm debug database
+*/
- /* find the level to set it to */
- i = 1;
- if (*s == '.')
+static char *
+tTnewflag(s)
+ register char *s;
+{
+ char *pat, *endpat;
+ int level;
+
+ pat = s;
+ while (*s != '\0' && *s != ',' && *s != ' ' && *s != '\t' && *s != '.')
+ ++s;
+ endpat = s;
+ if (*s == '.')
+ {
+ ++s;
+ level = 0;
+ while (isascii(*s) && isdigit(*s))
{
- i = 0;
- while (isascii(*++s) && isdigit(*s))
- i = i * 10 + (*s - '0');
+ level = level * 10 + (*s - '0');
+ ++s;
}
+ if (level < 0)
+ level = 0;
+ }
+ else
+ {
+ level = 1;
+ }
+
+ sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
- /* clean up args */
- if (first >= tTsize)
- first = tTsize - 1;
- if (last >= tTsize)
- last = tTsize - 1;
+ /* skip trailing junk */
+ while (*s != '\0' && *s != ',' && *s != ' ' && *s != '\t')
+ ++s;
- /* set the flags */
- while (first <= last)
- tTvect[first++] = i;
+ return s;
+}
- /* more arguments? */
- if (*s++ == '\0')
+/*
+** TtFLAG -- process an external trace flag list.
+**
+** Parameters:
+** s -- the trace flag.
+**
+** The syntax of a trace flag list is as follows:
+**
+** <flags> ::= <flag> | <flags> "," <flag>
+** <flag> ::= <categories> | <categories> "." <level>
+** <categories> ::= <int> | <int> "-" <int> | <pattern>
+** <pattern> ::= <an sh glob pattern matching a C identifier>
+**
+** White space is ignored before and after a flag.
+** However, note that we skip over anything we don't
+** understand, rather than report an error.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sets/clears old-style trace flags.
+** registers new-style trace flags with the libsm debug package.
+*/
+
+void
+tTflag(s)
+ register char *s;
+{
+ if (*s == '\0')
+ s = DefFlags;
+
+ for (;;)
+ {
+ if (*s == '\0')
return;
+ if (*s == ',' || *s == ' ' || *s == '\t')
+ {
+ ++s;
+ continue;
+ }
+ if (isascii(*s) && isdigit(*s))
+ s = tToldflag(s);
+ else
+ s = tTnewflag(s);
}
}
diff --git a/contrib/sendmail/src/udb.c b/contrib/sendmail/src/udb.c
index d835326..1091cf2 100644
--- a/contrib/sendmail/src/udb.c
+++ b/contrib/sendmail/src/udb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-1999, 2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -13,17 +13,15 @@
#include <sendmail.h>
-#ifndef lint
-# if USERDB
-static char id[] = "@(#)$Id: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (with USERDB)";
-# else /* USERDB */
-static char id[] = "@(#)$Id: udb.c,v 8.111.16.2 2001/05/03 17:24:17 gshapiro Exp $ (without USERDB)";
-# endif /* USERDB */
-#endif /* ! lint */
+#if USERDB
+SM_RCSID("@(#)$Id: udb.c,v 8.153 2001/09/11 04:05:17 gshapiro Exp $ (with USERDB)")
+#else /* USERDB */
+SM_RCSID("@(#)$Id: udb.c,v 8.153 2001/09/11 04:05:17 gshapiro Exp $ (without USERDB)")
+#endif /* USERDB */
#if USERDB
-# ifdef NEWDB
+# if NEWDB
# include <db.h>
# ifndef DB_VERSION_MAJOR
# define DB_VERSION_MAJOR 1
@@ -70,7 +68,7 @@ struct udbent
} udb_forward;
# define udb_fwdhost udb_u.udb_forward._udb_fwdhost
-# ifdef NEWDB
+# if NEWDB
/* type UE_FETCH -- lookup in local database */
struct
{
@@ -99,10 +97,10 @@ struct udb_option
char *udbo_val;
};
-# ifdef HESIOD
+# if HESIOD
static int hes_udb_get __P((DBT *, DBT *));
# endif /* HESIOD */
-static char *udbmatch __P((char *, char *));
+static char *udbmatch __P((char *, char *, SM_RPOOL_T *));
static int _udbx_init __P((ENVELOPE *));
static int _udb_parsespec __P((char *, struct udb_option [], int));
@@ -125,7 +123,7 @@ static int _udb_parsespec __P((char *, struct udb_option [], int));
*/
static struct udbent UdbEnts[MAXUDBENT + 1];
-static bool UdbInitialized = FALSE;
+static bool UdbInitialized = false;
int
udbexpand(a, sendq, aliaslevel, e)
@@ -148,7 +146,7 @@ udbexpand(a, sendq, aliaslevel, e)
memset(&info, '\0', sizeof info);
if (tTd(28, 1))
- dprintf("udbexpand(%s)\n", a->q_paddr);
+ sm_dprintf("udbexpand(%s)\n", a->q_paddr);
/* make certain we are supposed to send to this address */
if (!QS_IS_SENDABLE(a->q_state))
@@ -174,20 +172,19 @@ udbexpand(a, sendq, aliaslevel, e)
if (user[0] == '\\')
return EX_OK;
- /* if name is too long, assume it won't match */
- if (strlen(user) > (SIZE_T) sizeof keybuf - 12)
- return EX_OK;
-
/* if name begins with a colon, it indicates our metadata */
if (user[0] == ':')
return EX_OK;
+ keylen = sm_strlcpyn(keybuf, sizeof keybuf, 2, user, ":maildrop");
+
+ /* if name is too long, assume it won't match */
+ if (keylen > sizeof keybuf)
+ return EX_OK;
+
/* build actual database key */
- (void) strlcpy(keybuf, user, sizeof keybuf);
- (void) strlcat(keybuf, ":maildrop", sizeof keybuf);
- keylen = strlen(keybuf);
- breakout = FALSE;
+ breakout = false;
for (up = UdbEnts; !breakout; up++)
{
int usersize;
@@ -215,12 +212,12 @@ udbexpand(a, sendq, aliaslevel, e)
switch (up->udb_type)
{
-# ifdef NEWDB
+# if NEWDB
case UDB_DBFETCH:
key.data = keybuf;
key.size = keylen;
if (tTd(28, 80))
- dprintf("udbexpand: trying %s (%d) via db\n",
+ sm_dprintf("udbexpand: trying %s (%d) via db\n",
keybuf, keylen);
# if DB_VERSION_MAJOR < 2
i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
@@ -243,7 +240,7 @@ udbexpand(a, sendq, aliaslevel, e)
if (i > 0 || info.size <= 0)
{
if (tTd(28, 2))
- dprintf("udbexpand: no match on %s (%d)\n",
+ sm_dprintf("udbexpand: no match on %s (%d)\n",
keybuf, keylen);
# if DB_VERSION_MAJOR > 1
if (dbc != NULL)
@@ -255,7 +252,7 @@ udbexpand(a, sendq, aliaslevel, e)
break;
}
if (tTd(28, 80))
- dprintf("udbexpand: match %.*s: %.*s\n",
+ sm_dprintf("udbexpand: match %.*s: %.*s\n",
(int) key.size, (char *) key.data,
(int) info.size, (char *) info.data);
@@ -278,7 +275,7 @@ udbexpand(a, sendq, aliaslevel, e)
return EX_OK;
}
- breakout = TRUE;
+ breakout = true;
if (info.size >= userleft - 1)
{
char *nuser;
@@ -286,11 +283,11 @@ udbexpand(a, sendq, aliaslevel, e)
if (info.size > MEMCHUNKSIZE)
size = info.size;
- nuser = xalloc(usersize + size);
+ nuser = sm_malloc_x(usersize + size);
memmove(nuser, user, usersize);
if (user != userbuf)
- sm_free(user);
+ sm_free(user); /* XXX */
user = nuser;
usersize += size;
userleft += size;
@@ -339,8 +336,8 @@ udbexpand(a, sendq, aliaslevel, e)
{
if (tTd(28, 5))
{
- dprintf("udbexpand: QS_EXPANDED ");
- printaddr(a, FALSE);
+ sm_dprintf("udbexpand: QS_EXPANDED ");
+ printaddr(a, false);
}
a->q_state = QS_EXPANDED;
}
@@ -358,8 +355,8 @@ udbexpand(a, sendq, aliaslevel, e)
memset(&key, '\0', sizeof key);
memset(&info, '\0', sizeof info);
- (void) strlcpy(keybuf, a->q_user, sizeof keybuf);
- (void) strlcat(keybuf, ":mailsender", sizeof keybuf);
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, a->q_user,
+ ":mailsender");
keylen = strlen(keybuf);
key.data = keybuf;
key.size = keylen;
@@ -372,28 +369,29 @@ udbexpand(a, sendq, aliaslevel, e)
# endif /* DB_VERSION_MAJOR < 2 */
if (i != 0 || info.size <= 0)
break;
- a->q_owner = xalloc(info.size + 1);
+ a->q_owner = sm_rpool_malloc_x(e->e_rpool,
+ info.size + 1);
memmove(a->q_owner, info.data, info.size);
a->q_owner[info.size] = '\0';
/* announce delivery; NORECEIPT bit set later */
if (e->e_xfp != NULL)
{
- fprintf(e->e_xfp,
- "Message delivered to mailing list %s\n",
- a->q_paddr);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "Message delivered to mailing list %s\n",
+ a->q_paddr);
}
e->e_flags |= EF_SENDRECEIPT;
a->q_flags |= QDELIVERED|QEXPANDED;
break;
# endif /* NEWDB */
-# ifdef HESIOD
+# if HESIOD
case UDB_HESIOD:
key.data = keybuf;
key.size = keylen;
if (tTd(28, 80))
- dprintf("udbexpand: trying %s (%d) via hesiod\n",
+ sm_dprintf("udbexpand: trying %s (%d) via hesiod\n",
keybuf, keylen);
/* look up the key via hesiod */
i = hes_udb_get(&key, &info);
@@ -410,11 +408,11 @@ udbexpand(a, sendq, aliaslevel, e)
# endif /* HES_GETMAILHOST */
if (tTd(28, 2))
- dprintf("udbexpand: no match on %s (%d)\n",
+ sm_dprintf("udbexpand: no match on %s (%d)\n",
(char *) keybuf, (int) keylen);
# if HES_GETMAILHOST
if (tTd(28, 8))
- dprintf(" ... trying hes_getmailhost(%s)\n",
+ sm_dprintf(" ... trying hes_getmailhost(%s)\n",
a->q_user);
hp = hes_getmailhost(a->q_user);
if (hp == NULL)
@@ -426,7 +424,7 @@ udbexpand(a, sendq, aliaslevel, e)
return EX_TEMPFAIL;
}
if (tTd(28, 2))
- dprintf("hes_getmailhost(%s): %d\n",
+ sm_dprintf("hes_getmailhost(%s): %d\n",
a->q_user, hes_error());
break;
}
@@ -434,22 +432,22 @@ udbexpand(a, sendq, aliaslevel, e)
sizeof pobuf - 2)
{
if (tTd(28, 2))
- dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
+ sm_dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
a->q_user,
hp->po_name,
hp->po_host);
break;
}
info.data = pobuf;
- snprintf(pobuf, sizeof pobuf, "%s@%s",
- hp->po_name, hp->po_host);
+ (void) sm_snprintf(pobuf, sizeof pobuf,
+ "%s@%s", hp->po_name, hp->po_host);
info.size = strlen(info.data);
# else /* HES_GETMAILHOST */
break;
# endif /* HES_GETMAILHOST */
}
if (tTd(28, 80))
- dprintf("udbexpand: match %.*s: %.*s\n",
+ sm_dprintf("udbexpand: match %.*s: %.*s\n",
(int) key.size, (char *) key.data,
(int) info.size, (char *) info.data);
a->q_flags &= ~QSELFREF;
@@ -460,9 +458,9 @@ udbexpand(a, sendq, aliaslevel, e)
return EX_OK;
}
- breakout = TRUE;
+ breakout = true;
if (info.size >= usersize)
- user = xalloc(info.size + 1);
+ user = sm_malloc_x(info.size + 1);
memmove(user, info.data, info.size);
user[info.size] = '\0';
@@ -478,8 +476,8 @@ udbexpand(a, sendq, aliaslevel, e)
{
if (tTd(28, 5))
{
- dprintf("udbexpand: QS_EXPANDED ");
- printaddr(a, FALSE);
+ sm_dprintf("udbexpand: QS_EXPANDED ");
+ printaddr(a, false);
}
a->q_state = QS_EXPANDED;
}
@@ -489,15 +487,16 @@ udbexpand(a, sendq, aliaslevel, e)
** it into the envelope.
*/
- (void) strlcpy(keybuf, a->q_user, sizeof keybuf);
- (void) strlcat(keybuf, ":mailsender", sizeof keybuf);
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, a->q_user,
+ ":mailsender");
keylen = strlen(keybuf);
key.data = keybuf;
key.size = keylen;
i = hes_udb_get(&key, &info);
if (i != 0 || info.size <= 0)
break;
- a->q_owner = xalloc(info.size + 1);
+ a->q_owner = sm_rpool_malloc_x(e->e_rpool,
+ info.size + 1);
memmove(a->q_owner, info.data, info.size);
a->q_owner[info.size] = '\0';
break;
@@ -517,10 +516,10 @@ udbexpand(a, sendq, aliaslevel, e)
if (i >= usersize)
{
usersize = i + 1;
- user = xalloc(usersize);
+ user = sm_malloc_x(usersize);
}
- (void) snprintf(user, usersize, "%s@%s",
- a->q_user, up->udb_fwdhost);
+ (void) sm_strlcpyn(user, usersize, 3,
+ a->q_user, "@", up->udb_fwdhost);
message("expanded to %s", user);
a->q_flags &= ~QSELFREF;
naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
@@ -528,36 +527,38 @@ udbexpand(a, sendq, aliaslevel, e)
{
if (tTd(28, 5))
{
- dprintf("udbexpand: QS_EXPANDED ");
- printaddr(a, FALSE);
+ sm_dprintf("udbexpand: QS_EXPANDED ");
+ printaddr(a, false);
}
a->q_state = QS_EXPANDED;
}
- breakout = TRUE;
+ breakout = true;
break;
case UDB_EOLIST:
- breakout = TRUE;
+ breakout = true;
break;
default:
/* unknown entry type */
break;
}
+ /* XXX if an exception occurs, there is a storage leak */
if (user != userbuf)
- sm_free(user);
+ sm_free(user); /* XXX */
}
return EX_OK;
}
- /*
+/*
** UDBSENDER -- return canonical external name of sender, given local name
**
** Parameters:
** sender -- the name of the sender on the local machine.
+** rpool -- resource pool from which to allocate result
**
** Returns:
** The external name for this sender, if derivable from the
-** database.
+** database. Storage allocated from rpool.
** NULL -- if nothing is changed from the database.
**
** Side Effects:
@@ -565,21 +566,23 @@ udbexpand(a, sendq, aliaslevel, e)
*/
char *
-udbsender(sender)
+udbsender(sender, rpool)
char *sender;
+ SM_RPOOL_T *rpool;
{
- return udbmatch(sender, "mailname");
+ return udbmatch(sender, "mailname", rpool);
}
- /*
+/*
** UDBMATCH -- match user in field, return result of lookup.
**
** Parameters:
** user -- the name of the user.
** field -- the field to lookup.
+** rpool -- resource pool from which to allocate result
**
** Returns:
** The external name for this sender, if derivable from the
-** database.
+** database. Storage allocated from rpool.
** NULL -- if nothing is changed from the database.
**
** Side Effects:
@@ -587,9 +590,10 @@ udbsender(sender)
*/
static char *
-udbmatch(user, field)
+udbmatch(user, field, rpool)
char *user;
char *field;
+ SM_RPOOL_T *rpool;
{
register char *p;
register struct udbent *up;
@@ -599,7 +603,7 @@ udbmatch(user, field)
char keybuf[MAXKEY];
if (tTd(28, 1))
- dprintf("udbmatch(%s, %s)\n", user, field);
+ sm_dprintf("udbmatch(%s, %s)\n", user, field);
if (!UdbInitialized)
{
@@ -627,7 +631,7 @@ udbmatch(user, field)
return NULL;
/* build database key */
- (void) snprintf(keybuf, sizeof keybuf, "%s:%s", user, field);
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 3, user, ":", field);
keylen = strlen(keybuf);
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
@@ -638,7 +642,7 @@ udbmatch(user, field)
switch (up->udb_type)
{
-# ifdef NEWDB
+# if NEWDB
case UDB_DBFETCH:
memset(&key, '\0', sizeof key);
memset(&info, '\0', sizeof info);
@@ -653,20 +657,20 @@ udbmatch(user, field)
if (i != 0 || info.size <= 0)
{
if (tTd(28, 2))
- dprintf("udbmatch: no match on %s (%d) via db\n",
+ sm_dprintf("udbmatch: no match on %s (%d) via db\n",
keybuf, keylen);
continue;
}
- p = xalloc(info.size + 1);
+ p = sm_rpool_malloc_x(rpool, info.size + 1);
memmove(p, info.data, info.size);
p[info.size] = '\0';
if (tTd(28, 1))
- dprintf("udbmatch ==> %s\n", p);
+ sm_dprintf("udbmatch ==> %s\n", p);
return p;
# endif /* NEWDB */
-# ifdef HESIOD
+# if HESIOD
case UDB_HESIOD:
key.data = keybuf;
key.size = keylen;
@@ -674,16 +678,16 @@ udbmatch(user, field)
if (i != 0 || info.size <= 0)
{
if (tTd(28, 2))
- dprintf("udbmatch: no match on %s (%d) via hesiod\n",
+ sm_dprintf("udbmatch: no match on %s (%d) via hesiod\n",
keybuf, keylen);
continue;
}
- p = xalloc(info.size + 1);
+ p = sm_rpool_malloc_x(rpool, info.size + 1);
memmove(p, info.data, info.size);
p[info.size] = '\0';
if (tTd(28, 1))
- dprintf("udbmatch ==> %s\n", p);
+ sm_dprintf("udbmatch ==> %s\n", p);
return p;
# endif /* HESIOD */
}
@@ -699,15 +703,14 @@ udbmatch(user, field)
*/
/* build database key */
- (void) strlcpy(keybuf, user, sizeof keybuf);
- (void) strlcat(keybuf, ":maildrop", sizeof keybuf);
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, user, ":maildrop");
keylen = strlen(keybuf);
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
switch (up->udb_type)
{
-# ifdef NEWDB
+# if NEWDB
case UDB_DBFETCH:
/* get the default case for this database */
if (up->udb_default == NULL)
@@ -732,7 +735,7 @@ udbmatch(user, field)
}
/* save the default case */
- up->udb_default = xalloc(info.size + 1);
+ up->udb_default = sm_pmalloc_x(info.size + 1);
memmove(up->udb_default, info.data, info.size);
up->udb_default[info.size] = '\0';
}
@@ -758,14 +761,14 @@ udbmatch(user, field)
/* they exist -- build the actual address */
i = strlen(user) + strlen(up->udb_default) + 2;
- p = xalloc(i);
- (void) snprintf(p, i, "%s@%s", user, up->udb_default);
+ p = sm_rpool_malloc_x(rpool, i);
+ (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
if (tTd(28, 1))
- dprintf("udbmatch ==> %s\n", p);
+ sm_dprintf("udbmatch ==> %s\n", p);
return p;
# endif /* NEWDB */
-# ifdef HESIOD
+# if HESIOD
case UDB_HESIOD:
/* get the default case for this database */
if (up->udb_default == NULL)
@@ -782,7 +785,7 @@ udbmatch(user, field)
}
/* save the default case */
- up->udb_default = xalloc(info.size + 1);
+ up->udb_default = sm_pmalloc_x(info.size + 1);
memmove(up->udb_default, info.data, info.size);
up->udb_default[info.size] = '\0';
}
@@ -801,10 +804,10 @@ udbmatch(user, field)
/* they exist -- build the actual address */
i = strlen(user) + strlen(up->udb_default) + 2;
- p = xalloc(i);
- (void) snprintf(p, i, "%s@%s", user, up->udb_default);
+ p = sm_rpool_malloc_x(rpool, i);
+ (void) sm_strlcpyn(p, i, 3, user, "@", up->udb_default);
if (tTd(28, 1))
- dprintf("udbmatch ==> %s\n", p);
+ sm_dprintf("udbmatch ==> %s\n", p);
return p;
break;
# endif /* HESIOD */
@@ -814,7 +817,7 @@ udbmatch(user, field)
/* still nothing.... too bad */
return NULL;
}
- /*
+/*
** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
**
** Parameters:
@@ -838,10 +841,11 @@ udb_map_lookup(map, name, av, statp)
{
char *val;
char *key;
+ char *SM_NONVOLATILE result = NULL;
char keybuf[MAXNAME + 1];
if (tTd(28, 20) || tTd(38, 20))
- dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
+ sm_dprintf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
if (bitset(MF_NOFOLDCASE, map->map_mflags))
{
@@ -858,15 +862,20 @@ udb_map_lookup(map, name, av, statp)
makelower(keybuf);
key = keybuf;
}
- val = udbmatch(key, map->map_file);
+ val = udbmatch(key, map->map_file, NULL);
if (val == NULL)
return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val, strlen(val), av);
+ SM_TRY
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ result = map_rewrite(map, name, strlen(name), NULL);
+ else
+ result = map_rewrite(map, val, strlen(val), av);
+ SM_FINALLY
+ sm_free(val);
+ SM_END_TRY
+ return result;
}
- /*
+/*
** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
**
** Parameters:
@@ -945,25 +954,25 @@ _udbx_init(e)
{
case '@': /* forward to remote host */
up->udb_type = UDB_FORWARD;
- up->udb_pid = getpid();
+ up->udb_pid = CurrentPid;
up->udb_fwdhost = spec + 1;
ents++;
up++;
break;
-# ifdef HESIOD
+# if HESIOD
case 'h': /* use hesiod */
case 'H':
- if (strcasecmp(spec, "hesiod") != 0)
+ if (sm_strcasecmp(spec, "hesiod") != 0)
goto badspec;
up->udb_type = UDB_HESIOD;
- up->udb_pid = getpid();
+ up->udb_pid = CurrentPid;
ents++;
up++;
break;
# endif /* HESIOD */
-# ifdef NEWDB
+# if NEWDB
case '/': /* look up remote name */
l = strlen(spec);
if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
@@ -972,9 +981,9 @@ _udbx_init(e)
}
else
{
- up->udb_dbname = xalloc(l + 4);
- (void) strlcpy(up->udb_dbname, spec, l + 4);
- (void) strlcat(up->udb_dbname, ".db", l + 4);
+ up->udb_dbname = sm_pmalloc_x(l + 4);
+ (void) sm_strlcpyn(up->udb_dbname, l + 4, 2,
+ spec, ".db");
}
errno = 0;
# if DB_VERSION_MAJOR < 2
@@ -1034,12 +1043,12 @@ _udbx_init(e)
int save_errno = errno;
# if DB_VERSION_MAJOR < 2
- dprintf("dbopen(%s): %s\n",
+ sm_dprintf("dbopen(%s): %s\n",
# else /* DB_VERSION_MAJOR < 2 */
- dprintf("db_open(%s): %s\n",
+ sm_dprintf("db_open(%s): %s\n",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname,
- errstring(errno));
+ sm_errstring(errno));
errno = save_errno;
}
if (errno != ENOENT && errno != EACCES)
@@ -1052,34 +1061,34 @@ _udbx_init(e)
"db_open(%s): %s",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname,
- errstring(errno));
+ sm_errstring(errno));
up->udb_type = UDB_EOLIST;
if (up->udb_dbname != spec)
- sm_free(up->udb_dbname);
+ sm_free(up->udb_dbname); /* XXX */
goto tempfail;
}
if (up->udb_dbname != spec)
- sm_free(up->udb_dbname);
+ sm_free(up->udb_dbname); /* XXX */
break;
}
if (tTd(28, 1))
{
# if DB_VERSION_MAJOR < 2
- dprintf("_udbx_init: dbopen(%s)\n",
+ sm_dprintf("_udbx_init: dbopen(%s)\n",
# else /* DB_VERSION_MAJOR < 2 */
- dprintf("_udbx_init: db_open(%s)\n",
+ sm_dprintf("_udbx_init: db_open(%s)\n",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname);
}
up->udb_type = UDB_DBFETCH;
- up->udb_pid = getpid();
+ up->udb_pid = CurrentPid;
ents++;
up++;
break;
# endif /* NEWDB */
default:
-# ifdef HESIOD
+# if HESIOD
badspec:
# endif /* HESIOD */
syserr("Unknown UDB spec %s", spec);
@@ -1094,40 +1103,38 @@ badspec:
{
switch (up->udb_type)
{
-# if DAEMON
case UDB_REMOTE:
- dprintf("REMOTE: addr %s, timeo %d\n",
- anynet_ntoa((SOCKADDR *) &up->udb_addr),
- up->udb_timeout);
+ sm_dprintf("REMOTE: addr %s, timeo %d\n",
+ anynet_ntoa((SOCKADDR *) &up->udb_addr),
+ up->udb_timeout);
break;
-# endif /* DAEMON */
case UDB_DBFETCH:
-# ifdef NEWDB
- dprintf("FETCH: file %s\n",
+# if NEWDB
+ sm_dprintf("FETCH: file %s\n",
up->udb_dbname);
# else /* NEWDB */
- dprintf("FETCH\n");
+ sm_dprintf("FETCH\n");
# endif /* NEWDB */
break;
case UDB_FORWARD:
- dprintf("FORWARD: host %s\n",
+ sm_dprintf("FORWARD: host %s\n",
up->udb_fwdhost);
break;
case UDB_HESIOD:
- dprintf("HESIOD\n");
+ sm_dprintf("HESIOD\n");
break;
default:
- dprintf("UNKNOWN\n");
+ sm_dprintf("UNKNOWN\n");
break;
}
}
}
- UdbInitialized = TRUE;
+ UdbInitialized = true;
errno = 0;
return EX_OK;
@@ -1136,7 +1143,7 @@ badspec:
*/
tempfail:
-# ifdef NEWDB
+# if NEWDB
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
if (up->udb_type == UDB_DBFETCH)
@@ -1147,7 +1154,7 @@ badspec:
errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
# endif /* DB_VERSION_MAJOR < 2 */
if (tTd(28, 1))
- dprintf("_udbx_init: db->close(%s)\n",
+ sm_dprintf("_udbx_init: db->close(%s)\n",
up->udb_dbname);
}
}
@@ -1184,7 +1191,7 @@ _udb_parsespec(udbspec, opt, maxopts)
}
return optnum;
}
- /*
+/*
** _UDBX_CLOSE -- close all file based UDB entries.
**
** Parameters:
@@ -1196,20 +1203,17 @@ _udb_parsespec(udbspec, opt, maxopts)
void
_udbx_close()
{
- pid_t pid;
struct udbent *up;
if (!UdbInitialized)
return;
- pid = getpid();
-
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
- if (up->udb_pid != pid)
+ if (up->udb_pid != CurrentPid)
continue;
-# ifdef NEWDB
+# if NEWDB
if (up->udb_type == UDB_DBFETCH)
{
# if DB_VERSION_MAJOR < 2
@@ -1219,13 +1223,13 @@ _udbx_close()
# endif /* DB_VERSION_MAJOR < 2 */
}
if (tTd(28, 1))
- dprintf("_udbx_init: db->close(%s)\n",
+ sm_dprintf("_udbx_init: db->close(%s)\n",
up->udb_dbname);
# endif /* NEWDB */
}
}
-# ifdef HESIOD
+# if HESIOD
static int
hes_udb_get(key, info)
@@ -1236,7 +1240,7 @@ hes_udb_get(key, info)
char **hp;
char kbuf[MAXKEY + 1];
- if (strlcpy(kbuf, key->data, sizeof kbuf) >= (SIZE_T) sizeof kbuf)
+ if (sm_strlcpy(kbuf, key->data, sizeof kbuf) >= sizeof kbuf)
return 0;
name = kbuf;
type = strrchr(name, ':');
@@ -1247,7 +1251,7 @@ hes_udb_get(key, info)
return 1;
if (tTd(28, 1))
- dprintf("hes_udb_get(%s, %s)\n", name, type);
+ sm_dprintf("hes_udb_get(%s, %s)\n", name, type);
/* make the hesiod query */
# ifdef HESIOD_INIT
@@ -1293,7 +1297,7 @@ hes_udb_get(key, info)
}
if (tTd(28, 80))
- dprintf("hes_udb_get => %s\n", *hp);
+ sm_dprintf("hes_udb_get => %s\n", *hp);
return 0;
}
diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c
index a9476fe..cc29982 100644
--- a/contrib/sendmail/src/usersmtp.c
+++ b/contrib/sendmail/src/usersmtp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -13,22 +13,21 @@
#include <sendmail.h>
-#ifndef lint
-# if SMTP
-static char id[] = "@(#)$Id: usersmtp.c,v 8.245.4.34 2001/06/26 21:55:23 gshapiro Exp $ (with SMTP)";
-# else /* SMTP */
-static char id[] = "@(#)$Id: usersmtp.c,v 8.245.4.34 2001/06/26 21:55:23 gshapiro Exp $ (without SMTP)";
-# endif /* SMTP */
-#endif /* ! lint */
+SM_RCSID("@(#)$Id: usersmtp.c,v 8.428 2002/01/08 00:56:23 ca Exp $")
#include <sysexits.h>
-#if SMTP
-
+extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
static void datatimeout __P((void));
static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
+static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
+
+#if SASL
+extern void *sm_sasl_malloc __P((unsigned long));
+extern void sm_sasl_free __P((void *));
+#endif /* SASL */
/*
** USERSMTP -- run SMTP protocol from the user end.
@@ -36,16 +35,19 @@ static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
** This protocol is described in RFC821.
*/
-# define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
-# define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
-# define SMTPCLOSING 421 /* "Service Shutting Down" */
+#define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
+#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
+#define SMTPCLOSING 421 /* "Service Shutting Down" */
-#define ENHSCN(e, d) (e) == NULL ? (d) : newstr(e)
+#define ENHSCN(e, d) ((e) == NULL ? (d) : (e))
+
+#define ENHSCN_RPOOL(e, d, rpool) \
+ ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
static bool SmtpNeedIntro; /* need "while talking" in transcript */
- /*
+/*
** SMTPINIT -- initialize SMTP.
**
** Opens the connection and sends the initial protocol.
@@ -78,8 +80,8 @@ smtpinit(m, mci, e, onlyhelo)
enhsc = NULL;
if (tTd(18, 1))
{
- dprintf("smtpinit ");
- mci_dump(mci, FALSE);
+ sm_dprintf("smtpinit ");
+ mci_dump(mci, false);
}
/*
@@ -90,10 +92,12 @@ smtpinit(m, mci, e, onlyhelo)
CurHostName = mci->mci_host; /* XXX UGLY XXX */
if (CurHostName == NULL)
CurHostName = MyHostName;
- SmtpNeedIntro = TRUE;
+ SmtpNeedIntro = true;
switch (mci->mci_state)
{
- case MCIS_ACTIVE:
+ case MCIS_MAIL:
+ case MCIS_RCPT:
+ case MCIS_DATA:
/* need to clear old information */
smtprset(m, mci, e);
/* FALLTHROUGH */
@@ -129,7 +133,7 @@ smtpinit(m, mci, e, onlyhelo)
*/
SmtpPhase = mci->mci_phase = "client greeting";
- sm_setproctitle(TRUE, e, "%s %s: %s",
+ sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e), CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL);
if (r < 0)
@@ -150,12 +154,16 @@ helo:
hn = mci->mci_heloname ? mci->mci_heloname : MyHostName;
tryhelo:
+#if _FFR_IGNORE_EXT_ON_HELO
+ mci->mci_flags &= ~MCIF_HELO;
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
if (bitnset(M_LMTP, m->m_flags))
{
smtpmessage("LHLO %s", m, mci, hn);
SmtpPhase = mci->mci_phase = "client LHLO";
}
- else if (bitset(MCIF_ESMTP, mci->mci_flags))
+ else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
+ !bitnset(M_FSMTP, m->m_flags))
{
smtpmessage("EHLO %s", m, mci, hn);
SmtpPhase = mci->mci_phase = "client EHLO";
@@ -164,10 +172,16 @@ tryhelo:
{
smtpmessage("HELO %s", m, mci, hn);
SmtpPhase = mci->mci_phase = "client HELO";
+#if _FFR_IGNORE_EXT_ON_HELO
+ mci->mci_flags |= MCIF_HELO;
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
}
- sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
+ sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_helo, helo_options, NULL);
+ r = reply(m, mci, e,
+ bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
+ : TimeOuts.to_helo,
+ helo_options, NULL);
if (r < 0)
goto tempfail1;
else if (REPLYTYPE(r) == 5)
@@ -195,7 +209,7 @@ tryhelo:
*p = '\0';
if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
!bitnset(M_LMTP, m->m_flags) &&
- strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
+ sm_strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
{
syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
CurHostName);
@@ -206,6 +220,7 @@ tryhelo:
return;
}
+#if !_FFR_DEPRECATE_MAILER_FLAG_I
/*
** If this is expected to be another sendmail, send some internal
** commands.
@@ -219,6 +234,7 @@ tryhelo:
if (r < 0)
goto tempfail1;
}
+#endif /* !_FFR_DEPRECATE_MAILER_FLAG_I */
if (mci->mci_state != MCIS_CLOSED)
{
@@ -229,16 +245,12 @@ tryhelo:
/* got a 421 error code during startup */
tempfail1:
- if (mci->mci_errno == 0)
- mci->mci_errno = errno;
mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
if (mci->mci_state != MCIS_CLOSED)
smtpquit(m, mci, e);
return;
tempfail2:
- if (mci->mci_errno == 0)
- mci->mci_errno = errno;
/* XXX should use code from other end iff ENHANCEDSTATUSCODES */
mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
SmtpReplyBuffer);
@@ -247,12 +259,11 @@ tryhelo:
return;
unavailable:
- mci->mci_errno = errno;
mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
smtpquit(m, mci, e);
return;
}
- /*
+/*
** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
**
** Parameters:
@@ -276,23 +287,38 @@ esmtp_check(line, firstline, m, mci, e)
{
if (strstr(line, "ESMTP") != NULL)
mci->mci_flags |= MCIF_ESMTP;
+
+ /*
+ ** Dirty hack below. Quoting the author:
+ ** This was a response to people who wanted SMTP transmission to be
+ ** just-send-8 by default. Essentially, you could put this tag into
+ ** your greeting message to behave as though the F=8 flag was set on
+ ** the mailer.
+ */
+
if (strstr(line, "8BIT-OK") != NULL)
mci->mci_flags |= MCIF_8BITOK;
}
-# if SASL
- /*
+
+#if SASL
+/* specify prototype so compiler can check calls */
+static char *str_union __P((char *, char *, SM_RPOOL_T *));
+
+/*
** STR_UNION -- create the union of two lists
**
** Parameters:
** s1, s2 -- lists of items (separated by single blanks).
+** rpool -- resource pool from which result is allocated.
**
** Returns:
** the union of both lists.
*/
static char *
-str_union(s1, s2)
+str_union(s1, s2, rpool)
char *s1, *s2;
+ SM_RPOOL_T *rpool;
{
char *hr, *h1, *h, *res;
int l1, l2, rl;
@@ -304,8 +330,14 @@ str_union(s1, s2)
l1 = strlen(s1);
l2 = strlen(s2);
rl = l1 + l2;
- res = (char *)xalloc(rl + 2);
- (void) strlcpy(res, s1, rl);
+ res = (char *) sm_rpool_malloc(rpool, rl + 2);
+ if (res == NULL)
+ {
+ if (l1 > l2)
+ return s1;
+ return s2;
+ }
+ (void) sm_strlcpy(res, s1, rl);
hr = res + l1;
h1 = s2;
h = s2;
@@ -340,8 +372,9 @@ str_union(s1, s2)
}
return res;
}
-# endif /* SASL */
- /*
+#endif /* SASL */
+
+/*
** HELO_OPTIONS -- process the options on a HELO line.
**
** Parameters:
@@ -349,7 +382,7 @@ str_union(s1, s2)
** firstline -- set if this is the first line of the reply.
** m -- the mailer.
** mci -- the mailer connection info.
-** e -- the envelope.
+** e -- the envelope (unused).
**
** Returns:
** none.
@@ -364,62 +397,85 @@ helo_options(line, firstline, m, mci, e)
ENVELOPE *e;
{
register char *p;
+#if _FFR_IGNORE_EXT_ON_HELO
+ static bool logged = false;
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
if (firstline)
{
-# if SASL
- if (mci->mci_saslcap != NULL)
- sm_free(mci->mci_saslcap);
+#if SASL
mci->mci_saslcap = NULL;
-# endif /* SASL */
+#endif /* SASL */
+#if _FFR_IGNORE_EXT_ON_HELO
+ logged = false;
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
+ return;
+ }
+#if _FFR_IGNORE_EXT_ON_HELO
+ else if (bitset(MCIF_HELO, mci->mci_flags))
+ {
+ if (LogLevel > 8 && !logged)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "server=%s [%s] returned extensions despite HELO command",
+ macvalue(macid("{server_name}"), e),
+ macvalue(macid("{server_addr}"), e));
+ logged = true;
+ }
return;
}
+#endif /* _FFR_IGNORE_EXT_ON_HELO */
- if (strlen(line) < (SIZE_T) 5)
+ if (strlen(line) < 5)
return;
line += 4;
p = strpbrk(line, " =");
if (p != NULL)
*p++ = '\0';
- if (strcasecmp(line, "size") == 0)
+ if (sm_strcasecmp(line, "size") == 0)
{
mci->mci_flags |= MCIF_SIZE;
if (p != NULL)
mci->mci_maxsize = atol(p);
}
- else if (strcasecmp(line, "8bitmime") == 0)
+ else if (sm_strcasecmp(line, "8bitmime") == 0)
{
mci->mci_flags |= MCIF_8BITMIME;
mci->mci_flags &= ~MCIF_7BIT;
}
- else if (strcasecmp(line, "expn") == 0)
+ else if (sm_strcasecmp(line, "expn") == 0)
mci->mci_flags |= MCIF_EXPN;
- else if (strcasecmp(line, "dsn") == 0)
+ else if (sm_strcasecmp(line, "dsn") == 0)
mci->mci_flags |= MCIF_DSN;
- else if (strcasecmp(line, "enhancedstatuscodes") == 0)
+ else if (sm_strcasecmp(line, "enhancedstatuscodes") == 0)
mci->mci_flags |= MCIF_ENHSTAT;
-# if STARTTLS
- else if (strcasecmp(line, "starttls") == 0)
+ else if (sm_strcasecmp(line, "pipelining") == 0)
+ mci->mci_flags |= MCIF_PIPELINED;
+#if STARTTLS
+ else if (sm_strcasecmp(line, "starttls") == 0)
mci->mci_flags |= MCIF_TLS;
-# endif /* STARTTLS */
-# if SASL
- else if (strcasecmp(line, "auth") == 0)
+#endif /* STARTTLS */
+ else if (sm_strcasecmp(line, "deliverby") == 0)
+ {
+ mci->mci_flags |= MCIF_DLVR_BY;
+ if (p != NULL)
+ mci->mci_min_by = atol(p);
+ }
+#if SASL
+ else if (sm_strcasecmp(line, "auth") == 0)
{
if (p != NULL && *p != '\0')
{
if (mci->mci_saslcap != NULL)
{
- char *h;
-
/*
- ** create the union with previous auth
+ ** Create the union with previous auth
** offerings because we recognize "auth "
** and "auth=" (old format).
*/
- h = mci->mci_saslcap;
- mci->mci_saslcap = str_union(h, p);
- if (h != mci->mci_saslcap)
- sm_free(h);
+
+ mci->mci_saslcap = str_union(mci->mci_saslcap,
+ p, mci->mci_rpool);
mci->mci_flags |= MCIF_AUTH;
}
else
@@ -427,34 +483,115 @@ helo_options(line, firstline, m, mci, e)
int l;
l = strlen(p) + 1;
- mci->mci_saslcap = (char *)xalloc(l);
- (void) strlcpy(mci->mci_saslcap, p, l);
- mci->mci_flags |= MCIF_AUTH;
+ mci->mci_saslcap = (char *)
+ sm_rpool_malloc(mci->mci_rpool, l);
+ if (mci->mci_saslcap != NULL)
+ {
+ (void) sm_strlcpy(mci->mci_saslcap, p,
+ l);
+ mci->mci_flags |= MCIF_AUTH;
+ }
}
}
}
-# endif /* SASL */
+#endif /* SASL */
+}
+#if SASL
+
+static int getsimple __P((void *, int, const char **, unsigned *));
+static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
+static int saslgetrealm __P((void *, int, const char **, const char **));
+static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
+static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *));
+static char *removemech __P((char *, char *, SM_RPOOL_T *));
+static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
+
+static sasl_callback_t callbacks[] =
+{
+ { SASL_CB_GETREALM, &saslgetrealm, NULL },
+#define CB_GETREALM_IDX 0
+ { SASL_CB_PASS, &getsecret, NULL },
+#define CB_PASS_IDX 1
+ { SASL_CB_USER, &getsimple, NULL },
+#define CB_USER_IDX 2
+ { SASL_CB_AUTHNAME, &getsimple, NULL },
+#define CB_AUTHNAME_IDX 3
+ { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
+#define CB_SAFESASL_IDX 4
+ { SASL_CB_LIST_END, NULL, NULL }
+};
+
+/*
+** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
+**
+** Parameters:
+** none.
+**
+** Returns:
+** SASL_OK -- if successful.
+** SASL error code -- otherwise.
+**
+** Side Effects:
+** checks/sets sasl_clt_init.
+*/
+
+static bool sasl_clt_init = false;
+
+static int
+init_sasl_client()
+{
+ int result;
+
+ if (sasl_clt_init)
+ return SASL_OK;
+ result = sasl_client_init(callbacks);
+
+ /* should we retry later again or just remember that it failed? */
+ if (result == SASL_OK)
+ sasl_clt_init = true;
+ return result;
}
-# if SASL
+/*
+** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** checks/sets sasl_clt_init.
+*/
- /*
+void
+stop_sasl_client()
+{
+ if (!sasl_clt_init)
+ return;
+ sasl_clt_init = false;
+ sasl_done();
+}
+/*
** GETSASLDATA -- process the challenges from the SASL protocol
**
** This gets the relevant sasl response data out of the reply
-** from the server
+** from the server.
**
** Parameters:
** line -- the response line.
** firstline -- set if this is the first line of the reply.
** m -- the mailer.
** mci -- the mailer connection info.
-** e -- the envelope.
+** e -- the envelope (unused).
**
** Returns:
** none.
*/
-void
+static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
+
+static void
getsasldata(line, firstline, m, mci, e)
char *line;
bool firstline;
@@ -463,96 +600,94 @@ getsasldata(line, firstline, m, mci, e)
ENVELOPE *e;
{
int len;
- char *out;
int result;
+ char *out;
/* if not a continue we don't care about it */
- if ((strlen(line) <= 4) ||
+ len = strlen(line);
+ if ((len <= 4) ||
(line[0] != '3') ||
- (line[1] != '3') ||
- (line[2] != '4'))
+ !isascii(line[1]) || !isdigit(line[1]) ||
+ !isascii(line[2]) || !isdigit(line[2]))
{
- mci->mci_sasl_string = NULL;
+ SM_FREE_CLR(mci->mci_sasl_string);
return;
}
/* forget about "334 " */
line += 4;
- len = strlen(line);
+ len -= 4;
- out = xalloc(len + 1);
- result = sasl_decode64(line, len, out, (u_int *)&len);
+ out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
+ result = sasl_decode64(line, len, out, (unsigned int *)&len);
if (result != SASL_OK)
{
len = 0;
*out = '\0';
}
+
+ /*
+ ** mci_sasl_string is "shared" with Cyrus-SASL library; hence
+ ** it can't be in an rpool unless we use the same memory
+ ** management mechanism (with same rpool!) for Cyrus SASL.
+ */
+
if (mci->mci_sasl_string != NULL)
{
if (mci->mci_sasl_string_len <= len)
{
- sm_free(mci->mci_sasl_string);
+ sm_free(mci->mci_sasl_string); /* XXX */
mci->mci_sasl_string = xalloc(len + 1);
}
}
else
mci->mci_sasl_string = xalloc(len + 1);
- /* XXX this is probably leaked */
+
memcpy(mci->mci_sasl_string, out, len);
mci->mci_sasl_string[len] = '\0';
mci->mci_sasl_string_len = len;
- sm_free(out);
return;
}
-
- /*
-** READAUTH -- read auth value from a file
+/*
+** READAUTH -- read auth values from a file
**
** Parameters:
-** l -- line to define.
** filename -- name of file to read.
** safe -- if set, this is a safe read.
+** sai -- where to store auth_info.
+** rpool -- resource pool for sai.
**
** Returns:
-** line from file
-**
-** Side Effects:
-** overwrites local static buffer. The caller should copy
-** the result.
-**
+** EX_OK -- data succesfully read.
+** EX_UNAVAILABLE -- no valid filename.
+** EX_TEMPFAIL -- temporary failure.
*/
-/* lines in authinfo file */
-# define SASL_USER 1
-# define SASL_AUTHID 2
-# define SASL_PASSWORD 3
-# define SASL_DEFREALM 4
-# define SASL_MECH 5
-
static char *sasl_info_name[] =
{
- "",
"user id",
- "authorization id",
+ "authentication id",
"password",
"realm",
- "mechanism"
+ "mechlist"
};
-
-static char *
-readauth(l, filename, safe)
- int l;
+static int
+readauth(filename, safe, sai, rpool)
char *filename;
bool safe;
+ SASL_AI_T *sai;
+ SM_RPOOL_T *rpool;
{
- FILE *f;
+ SM_FILE_T *f;
long sff;
pid_t pid;
int lc;
- static char buf[MAXLINE];
+ char *s;
+ char buf[MAXLINE];
if (filename == NULL || filename[0] == '\0')
- return "";
+ return EX_UNAVAILABLE;
+
#if !_FFR_ALLOW_SASLINFO
/*
** make sure we don't use a program that is not
@@ -560,6 +695,7 @@ readauth(l, filename, safe)
** However, currently we don't pass this info (authinfo file
** specified by user) around, so we just turn off program access.
*/
+
if (filename[0] == '|')
{
auto int fd;
@@ -580,22 +716,29 @@ readauth(l, filename, safe)
if (pid < 0)
f = NULL;
else
- f = fdopen(fd, "r");
+ f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &fd, SM_IO_RDONLY, NULL);
}
else
#endif /* !_FFR_ALLOW_SASLINFO */
{
pid = -1;
- sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
- | SFF_NOGWFILES | SFF_NOWWFILES | SFF_NORFILES;
+ sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
+ |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
+# if _FFR_GROUPREADABLEAUTHINFOFILE
+ if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
+# endif /* _FFR_GROUPREADABLEAUTHINFOFILE */
+ sff |= SFF_NOGRFILES;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
+
#if _FFR_ALLOW_SASLINFO
/*
** XXX: make sure we don't read or open files that are not
** accesible to the user who specified a different authinfo
** file.
*/
+
sff |= SFF_MUSTOWN;
#else /* _FFR_ALLOW_SASLINFO */
if (safe)
@@ -606,62 +749,209 @@ readauth(l, filename, safe)
}
if (f == NULL)
{
- syserr("readauth: cannot open %s", filename);
- return "";
+ if (LogLevel > 5)
+ sm_syslog(LOG_ERR, NOQID,
+ "AUTH=client, error: can't open %s: %s",
+ filename, sm_errstring(errno));
+ return EX_TEMPFAIL;
}
lc = 0;
- while (lc < l && fgets(buf, sizeof buf, f) != NULL)
+ while (lc <= SASL_MECHLIST &&
+ sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
{
if (buf[0] != '#')
+ {
+ (*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
+ if ((s = strchr((*sai)[lc], '\n')) != NULL)
+ *s = '\0';
lc++;
+ }
}
- (void) fclose(f);
+ (void) sm_io_close(f, SM_TIME_DEFAULT);
if (pid > 0)
(void) waitfor(pid);
- if (lc < l)
- {
- if (LogLevel >= 9)
- sm_syslog(LOG_WARNING, NOQID, "SASL: error: can't read %s from %s",
- sasl_info_name[l], filename);
- return "";
- }
- lc = strlen(buf) - 1;
- if (lc >= 0)
- buf[lc] = '\0';
- if (tTd(95, 6))
- dprintf("readauth(%s, %d) = '%s'\n", filename, l, buf);
- return buf;
+ if (lc < SASL_PASSWORD)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_ERR, NOQID,
+ "AUTH=client, error: can't read %s from %s",
+ sasl_info_name[lc + 1], filename);
+ return EX_TEMPFAIL;
+ }
+ return EX_OK;
}
-# ifndef __attribute__
-# define __attribute__(x)
-# endif /* ! __attribute__ */
-
-static int getsimple __P((void *, int, const char **, unsigned *));
-static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
-static int saslgetrealm __P((void *, int, const char **, const char **));
+/*
+** GETAUTH -- get authinfo from ruleset call
+**
+** {server_name}, {server_addr} must be set
+**
+** Parameters:
+** mci -- the mailer connection structure.
+** e -- the envelope (including the sender to specify).
+** sai -- pointer to authinfo (result).
+**
+** Returns:
+** EX_OK -- ruleset was succesfully called, data may not
+** be available, sai must be checked.
+** EX_UNAVAILABLE -- ruleset unavailable (or failed).
+** EX_TEMPFAIL -- temporary failure (from ruleset).
+**
+** Side Effects:
+** Fills in sai if successful.
+*/
-static sasl_callback_t callbacks[] =
+static int
+getauth(mci, e, sai)
+ MCI *mci;
+ ENVELOPE *e;
+ SASL_AI_T *sai;
{
- { SASL_CB_GETREALM, &saslgetrealm, NULL },
-# define CB_GETREALM_IDX 0
- { SASL_CB_PASS, &getsecret, NULL },
-# define CB_PASS_IDX 1
- { SASL_CB_USER, &getsimple, NULL },
-# define CB_USER_IDX 2
- { SASL_CB_AUTHNAME, &getsimple, NULL },
-# define CB_AUTHNAME_IDX 3
- { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
- { SASL_CB_LIST_END, NULL, NULL }
-};
+ int i, r, l, got, ret;
+ char **pvp;
+ char pvpbuf[PSBUFSIZE];
+
+ r = rscap("authinfo", macvalue(macid("{server_name}"), e),
+ macvalue(macid("{server_addr}"), e), e,
+ &pvp, pvpbuf, sizeof(pvpbuf));
+
+ if (r != EX_OK)
+ return EX_UNAVAILABLE;
+
+ /* other than expected return value: ok (i.e., no auth) */
+ if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
+ return EX_OK;
+ if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
+ return EX_TEMPFAIL;
- /*
+ /*
+ ** parse the data, put it into sai
+ ** format: "TDstring" (including the '"' !)
+ ** where T is a tag: 'U', ...
+ ** D is a delimiter: ':' or '='
+ */
+
+ ret = EX_OK; /* default return value */
+ i = 0;
+ got = 0;
+ while (i < SASL_ENTRIES)
+ {
+ if (pvp[i + 1] == NULL)
+ break;
+ if (pvp[i + 1][0] != '"')
+ break;
+ switch (pvp[i + 1][1])
+ {
+ case 'U':
+ case 'u':
+ r = SASL_USER;
+ break;
+ case 'I':
+ case 'i':
+ r = SASL_AUTHID;
+ break;
+ case 'P':
+ case 'p':
+ r = SASL_PASSWORD;
+ break;
+ case 'R':
+ case 'r':
+ r = SASL_DEFREALM;
+ break;
+ case 'M':
+ case 'm':
+ r = SASL_MECHLIST;
+ break;
+ default:
+ goto fail;
+ }
+ l = strlen(pvp[i + 1]);
+
+ /* check syntax */
+ if (l <= 3 || pvp[i + 1][l - 1] != '"')
+ goto fail;
+
+ /* remove closing quote */
+ pvp[i + 1][l - 1] = '\0';
+
+ /* remove "TD and " */
+ l -= 4;
+ (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
+ if ((*sai)[r] == NULL)
+ goto tempfail;
+ if (pvp[i + 1][2] == ':')
+ {
+ /* ':text' (just copy) */
+ (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
+ got |= 1 << r;
+ }
+ else if (pvp[i + 1][2] == '=')
+ {
+ unsigned int len;
+
+ /* '=base64' (decode) */
+ r = sasl_decode64(pvp[i + 1] + 3,
+ (unsigned int) l, (*sai)[r], &len);
+ if (r != SASL_OK)
+ goto fail;
+ got |= 1 << r;
+ }
+ else
+ goto fail;
+ if (tTd(95, 5))
+ sm_syslog(LOG_WARNING, NOQID, "getauth %s=%s",
+ sasl_info_name[r], (*sai)[r]);
+ ++i;
+ }
+
+ /* did we get the expected data? */
+ if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
+ bitset(SASL_PASSWORD_BIT, got)))
+ goto fail;
+
+ /* no authid? copy uid */
+ if (!bitset(SASL_AUTHID_BIT, got))
+ {
+ l = strlen((*sai)[SASL_USER]) + 1;
+ (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
+ l + 1);
+ if ((*sai)[SASL_AUTHID] == NULL)
+ goto tempfail;
+ (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
+ }
+
+ /* no uid? copy authid */
+ if (!bitset(SASL_USER_BIT, got))
+ {
+ l = strlen((*sai)[SASL_AUTHID]) + 1;
+ (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
+ l + 1);
+ if ((*sai)[SASL_USER] == NULL)
+ goto tempfail;
+ (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
+ }
+ return EX_OK;
+
+ tempfail:
+ ret = EX_TEMPFAIL;
+ fail:
+ if (LogLevel > 8)
+ sm_syslog(LOG_WARNING, NOQID,
+ "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
+ macvalue(macid("{server_name}"), e),
+ macvalue(macid("{server_addr}"), e),
+ ret == EX_TEMPFAIL ? "temp" : "");
+ for (i = 0; i <= SASL_MECHLIST; i++)
+ (*sai)[i] = NULL; /* just clear; rpool */
+ return ret;
+}
+/*
** GETSIMPLE -- callback to get userid or authid
**
** Parameters:
-** context -- unused
+** context -- sai
** id -- what to do
** result -- (pointer to) result
** len -- (pointer to) length of result
@@ -672,80 +962,128 @@ static sasl_callback_t callbacks[] =
static int
getsimple(context, id, result, len)
- void *context __attribute__((unused));
+ void *context;
int id;
const char **result;
unsigned *len;
{
- char *h;
-# if SASL > 10509
- int addrealm;
- static int addedrealm = FALSE;
-# endif /* SASL > 10509 */
- static char *user = NULL;
- static char *authid = NULL;
-
- if (result == NULL)
+ char *h, *s;
+# if SASL > 10509
+ bool addrealm;
+# endif /* SASL > 10509 */
+ size_t l;
+ SASL_AI_T *sai;
+ char *authid = NULL;
+
+ if (result == NULL || context == NULL)
return SASL_BADPARAM;
+ sai = (SASL_AI_T *) context;
+
+ /*
+ ** Unfortunately it is not clear whether this routine should
+ ** return a copy of a string or just a pointer to a string.
+ ** The Cyrus-SASL plugins treat these return values differently, e.g.,
+ ** plugins/cram.c free()s authid, plugings/digestmd5.c does not.
+ ** The best solution to this problem is to fix Cyrus-SASL, but it
+ ** seems there is nobody who creates patches... Hello CMU!?
+ ** The second best solution is to have flags that tell this routine
+ ** whether to return an malloc()ed copy.
+ ** The next best solution is to always return an malloc()ed copy,
+ ** and suffer from some memory leak, which is ugly for persistent
+ ** queue runners.
+ ** For now we go with the last solution...
+ ** We can't use rpools (which would avoid this particular problem)
+ ** as explained in sasl.c.
+ */
switch (id)
{
case SASL_CB_USER:
- if (user == NULL)
+ l = strlen((*sai)[SASL_USER]) + 1;
+ s = sm_sasl_malloc(l);
+ if (s == NULL)
{
- h = readauth(SASL_USER, SASLInfo, TRUE);
- user = newstr(h);
+ if (len != NULL)
+ *len = 0;
+ *result = NULL;
+ return SASL_NOMEM;
}
- *result = user;
+ (void) sm_strlcpy(s, (*sai)[SASL_USER], l);
+ *result = s;
if (tTd(95, 5))
- dprintf("AUTH username '%s'\n", *result);
+ sm_syslog(LOG_WARNING, NOQID, "AUTH username '%s'",
+ *result);
if (len != NULL)
- *len = user ? strlen(user) : 0;
+ *len = *result != NULL ? strlen(*result) : 0;
break;
case SASL_CB_AUTHNAME:
-# if SASL > 10509
+ h = (*sai)[SASL_AUTHID];
+# if SASL > 10509
/* XXX maybe other mechanisms too?! */
- addrealm = context != NULL &&
- strcasecmp(context, "CRAM-MD5") == 0;
- if (addedrealm != addrealm && authid != NULL)
- {
-# if SASL > 10522
- /*
- ** digest-md5 prior to 1.5.23 doesn't copy the
- ** value it gets from the callback, but free()s
- ** it later on
- ** workaround: don't free() it here
- ** this can cause a memory leak!
- */
+ addrealm = (*sai)[SASL_MECH] != NULL &&
+ sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0;
- sm_free(authid);
-# endif /* SASL > 10522 */
- authid = NULL;
- addedrealm = addrealm;
- }
-# endif /* SASL > 10509 */
- if (authid == NULL)
+ /*
+ ** Add realm to authentication id unless authid contains
+ ** '@' (i.e., a realm) or the default realm is empty.
+ */
+
+ if (addrealm && h != NULL && strchr(h, '@') == NULL)
{
- h = readauth(SASL_AUTHID, SASLInfo, TRUE);
-# if SASL > 10509
- if (addrealm && strchr(h, '@') == NULL)
+ /* has this been done before? */
+ if ((*sai)[SASL_ID_REALM] == NULL)
{
- size_t l;
char *realm;
- realm = callbacks[CB_GETREALM_IDX].context;
- l = strlen(h) + strlen(realm) + 2;
- authid = xalloc(l);
- snprintf(authid, l, "%s@%s", h, realm);
+ realm = (*sai)[SASL_DEFREALM];
+
+ /* do not add an empty realm */
+ if (*realm == '\0')
+ {
+ authid = h;
+ (*sai)[SASL_ID_REALM] = NULL;
+ }
+ else
+ {
+ l = strlen(h) + strlen(realm) + 2;
+
+ /* should use rpool, but from where? */
+ authid = sm_sasl_malloc(l);
+ if (authid != NULL)
+ {
+ (void) sm_snprintf(authid, l,
+ "%s@%s",
+ h, realm);
+ (*sai)[SASL_ID_REALM] = authid;
+ }
+ else
+ {
+ authid = h;
+ (*sai)[SASL_ID_REALM] = NULL;
+ }
+ }
}
else
-# endif /* SASL > 10509 */
- authid = newstr(h);
+ authid = (*sai)[SASL_ID_REALM];
+ }
+ else
+# endif /* SASL > 10509 */
+ authid = h;
+ l = strlen(authid) + 1;
+ s = sm_sasl_malloc(l);
+ if (s == NULL)
+ {
+ if (len != NULL)
+ *len = 0;
+ *result = NULL;
+ return SASL_NOMEM;
}
- *result = authid;
+ (void) sm_strlcpy(s, authid, l);
+ *result = s;
if (tTd(95, 5))
- dprintf("AUTH authid '%s'\n", *result);
+ sm_syslog(LOG_WARNING, NOQID, "AUTH authid '%s'",
+ *result);
if (len != NULL)
*len = authid ? strlen(authid) : 0;
break;
@@ -761,13 +1099,12 @@ getsimple(context, id, result, len)
}
return SASL_OK;
}
-
- /*
+/*
** GETSECRET -- callback to get password
**
** Parameters:
** conn -- connection information
-** context -- unused
+** context -- sai
** id -- what to do
** psecret -- (pointer to) result
**
@@ -778,30 +1115,29 @@ getsimple(context, id, result, len)
static int
getsecret(conn, context, id, psecret)
sasl_conn_t *conn;
- void *context __attribute__((unused));
+ SM_UNUSED(void *context);
int id;
sasl_secret_t **psecret;
{
- char *h;
int len;
- static char *authpass = NULL;
+ char *authpass;
+ SASL_AI_T *sai;
if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
return SASL_BADPARAM;
- if (authpass == NULL)
- {
- h = readauth(SASL_PASSWORD, SASLInfo, TRUE);
- authpass = newstr(h);
- }
+ sai = (SASL_AI_T *) context;
+ authpass = (*sai)[SASL_PASSWORD];
len = strlen(authpass);
- *psecret = (sasl_secret_t *) xalloc(sizeof(sasl_secret_t) + len + 1);
- (void) strlcpy((*psecret)->data, authpass, len + 1);
- (*psecret)->len = len;
+ *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
+ len + 1);
+ if (*psecret == NULL)
+ return SASL_FAIL;
+ (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
+ (*psecret)->len = (unsigned long) len;
return SASL_OK;
}
-
- /*
+/*
** SAFESASLFILE -- callback for sasl: is file safe?
**
** Parameters:
@@ -810,66 +1146,70 @@ getsecret(conn, context, id, psecret)
** type -- type of file to check
**
** Returns:
-** SASL_OK: file can be used
-** SASL_CONTINUE: don't use file
-** SASL_FAIL: failure (not used here)
+** SASL_OK -- file can be used
+** SASL_CONTINUE -- don't use file
+** SASL_FAIL -- failure (not used here)
**
*/
+
int
-# if SASL > 10515
+#if SASL > 10515
safesaslfile(context, file, type)
-# else /* SASL > 10515 */
+#else /* SASL > 10515 */
safesaslfile(context, file)
-# endif /* SASL > 10515 */
+#endif /* SASL > 10515 */
void *context;
char *file;
-# if SASL > 10515
+#if SASL > 10515
int type;
-# endif /* SASL > 10515 */
+#endif /* SASL > 10515 */
{
long sff;
int r;
+#if SASL <= 10515
+ size_t len;
+#endif /* SASL <= 10515 */
char *p;
if (file == NULL || *file == '\0')
return SASL_OK;
-
- sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOGWFILES|SFF_NOWWFILES|SFF_ROOTOK;
+ sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
+#if SASL <= 10515
if ((p = strrchr(file, '/')) == NULL)
p = file;
else
++p;
-# if SASL <= 10515
/* everything beside libs and .conf files must not be readable */
- r = strlen(p);
- if ((r <= 3 || strncmp(p, "lib", 3) != 0) &&
- (r <= 5 || strncmp(p + r - 5, ".conf", 5) != 0)
-# if _FFR_UNSAFE_SASL
- && !bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail)
-# endif /* _FFR_UNSAFE_SASL */
- )
- sff |= SFF_NORFILES;
-# else /* SASL > 10515 */
+ len = strlen(p);
+ if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
+ (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
+ {
+ if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
+ sff |= SFF_NORFILES;
+ if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
+ sff |= SFF_NOGWFILES;
+ }
+#else /* SASL <= 10515 */
/* files containing passwords should be not readable */
if (type == SASL_VRFY_PASSWD)
{
-# if _FFR_UNSAFE_SASL
- if (bitnset(DBS_GROUPREADABLESASLFILE, DontBlameSendmail))
+ if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
sff |= SFF_NOWRFILES;
else
-# endif /* _FFR_UNSAFE_SASL */
sff |= SFF_NORFILES;
+ if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
+ sff |= SFF_NOGWFILES;
}
-# endif /* SASL <= 10515 */
+#endif /* SASL <= 10515 */
p = file;
if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
S_IRUSR, NULL)) == 0)
return SASL_OK;
- if (LogLevel >= 11 || (r != ENOENT && LogLevel >= 9))
+ if (LogLevel > (r != ENOENT ? 8 : 10))
sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
- p, errstring(r));
+ p, sm_errstring(r));
return SASL_CONTINUE;
}
@@ -880,7 +1220,6 @@ safesaslfile(context, file)
**
** Parameters:
** context -- context shared between invocations
-** here: realm to return
** availrealms -- list of available realms
** {realm, realm, ...}
** result -- pointer to result
@@ -888,6 +1227,7 @@ safesaslfile(context, file)
** Returns:
** failure/success
*/
+
static int
saslgetrealm(context, id, availrealms, result)
void *context;
@@ -895,14 +1235,22 @@ saslgetrealm(context, id, availrealms, result)
const char **availrealms;
const char **result;
{
- if (LogLevel > 12)
- sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s",
- context == NULL ? "<No Context>" : (char *) context,
- (availrealms == NULL || *availrealms == NULL) ? "<No Realms>" : *availrealms);
- if (context == NULL)
+ char *r;
+ SASL_AI_T *sai;
+
+ sai = (SASL_AI_T *) context;
+ if (sai == NULL)
return SASL_FAIL;
+ r = (*sai)[SASL_DEFREALM];
+
+ if (LogLevel > 12)
+ sm_syslog(LOG_INFO, NOQID,
+ "AUTH=client, realm=%s, available realms=%s",
+ r == NULL ? "<No Realm>" : r,
+ (availrealms == NULL || *availrealms == NULL)
+ ? "<No Realms>" : *availrealms);
- /* check whether context is in list? */
+ /* check whether context is in list */
if (availrealms != NULL && *availrealms != NULL)
{
if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
@@ -910,15 +1258,15 @@ saslgetrealm(context, id, availrealms, result)
{
if (LogLevel > 8)
sm_syslog(LOG_ERR, NOQID,
- "saslgetrealm: realm %s not in list %s",
- context, *availrealms);
+ "AUTH=client, realm=%s not in list=%s",
+ r, *availrealms);
return SASL_FAIL;
}
}
- *result = (char *)context;
+ *result = r;
return SASL_OK;
}
- /*
+/*
** ITEMINLIST -- does item appear in list?
**
** Check whether item appears in list (which must be separated by a
@@ -952,7 +1300,7 @@ iteminlist(item, list, delim)
len = strlen(item);
while (s != NULL && *s != '\0')
{
- if (strncasecmp(s, item, len) == 0 &&
+ if (sm_strncasecmp(s, item, len) == 0 &&
(s[len] == '\0' || strchr(delim, s[len]) != NULL))
return s;
s = strpbrk(s, delim);
@@ -962,21 +1310,23 @@ iteminlist(item, list, delim)
}
return NULL;
}
- /*
+/*
** REMOVEMECH -- remove item [rem] from list [list]
**
** Parameters:
** rem -- item to remove
** list -- list of items
+** rpool -- resource pool from which result is allocated.
**
** Returns:
** pointer to new list (NULL in case of error).
*/
-char *
-removemech(rem, list)
+static char *
+removemech(rem, list, rpool)
char *rem;
char *list;
+ SM_RPOOL_T *rpool;
{
char *ret;
char *needle;
@@ -999,13 +1349,13 @@ removemech(rem, list)
/* length of string without rem */
len = strlen(list) - strlen(rem);
- if (len == 0)
+ if (len <= 0)
{
- ret = xalloc(1); /* XXX leaked */
+ ret = (char *) sm_rpool_malloc_x(rpool, 1);
*ret = '\0';
return ret;
}
- ret = xalloc(len); /* XXX leaked */
+ ret = (char *) sm_rpool_malloc_x(rpool, len);
memset(ret, '\0', len);
/* copy from start to removed item */
@@ -1024,126 +1374,69 @@ removemech(rem, list)
ret[(needle - list) - 1] = '\0';
return ret;
}
- /*
-** INTERSECT -- create the intersection between two lists
-**
-** Parameters:
-** s1, s2 -- lists of items (separated by single blanks).
-**
-** Returns:
-** the intersection of both lists.
-*/
-
-char *
-intersect(s1, s2)
- char *s1, *s2;
-{
- char *hr, *h1, *h, *res;
- int l1, l2, rl;
-
- if (s1 == NULL || s2 == NULL) /* NULL string(s) -> NULL result */
- return NULL;
- l1 = strlen(s1);
- l2 = strlen(s2);
- rl = min(l1, l2);
- res = (char *)xalloc(rl + 1);
- *res = '\0';
- if (rl == 0) /* at least one string empty? */
- return res;
- hr = res;
- h1 = s1;
- h = s1;
-
- /* walk through s1 */
- while (h != NULL && *h1 != '\0')
- {
- /* is there something after the current word? */
- if ((h = strchr(h1, ' ')) != NULL)
- *h = '\0';
- l1 = strlen(h1);
-
- /* does the current word appear in s2 ? */
- if (iteminlist(h1, s2, " ") != NULL)
- {
- /* add a blank if not first item */
- if (hr != res)
- *hr++ = ' ';
-
- /* copy the item */
- memcpy(hr, h1, l1);
-
- /* advance pointer in result list */
- hr += l1;
- *hr = '\0';
- }
- if (h != NULL)
- {
- /* there are more items */
- *h = ' ';
- h1 = h + 1;
- }
- }
- return res;
-}
- /*
+/*
** ATTEMPTAUTH -- try to AUTHenticate using one mechanism
**
** Parameters:
** m -- the mailer.
** mci -- the mailer connection structure.
** e -- the envelope (including the sender to specify).
-** mechused - filled in with mechanism used
+** sai - sasl authinfo
**
** Returns:
-** EX_OK/EX_TEMPFAIL
+** EX_OK -- authentication was successful.
+** EX_NOPERM -- authentication failed.
+** EX_IOERR -- authentication dialogue failed (I/O problem?).
+** EX_TEMPFAIL -- temporary failure.
+**
*/
-int
-attemptauth(m, mci, e, mechused)
+static int
+attemptauth(m, mci, e, sai)
MAILER *m;
MCI *mci;
ENVELOPE *e;
- char **mechused;
+ SASL_AI_T *sai;
{
int saslresult, smtpresult;
sasl_external_properties_t ssf;
sasl_interact_t *client_interact = NULL;
char *out;
unsigned int outlen;
- static char *mechusing;
+ char *mechusing;
sasl_security_properties_t ssp;
char in64[MAXOUTLEN];
-# if NETINET
+#if NETINET
extern SOCKADDR CurHostAddr;
-# endif /* NETINET */
+#endif /* NETINET */
+
+ /* no mechanism selected (yet) */
+ (*sai)[SASL_MECH] = NULL;
- *mechused = NULL;
+ /* dispose old connection */
if (mci->mci_conn != NULL)
- {
sasl_dispose(&(mci->mci_conn));
- /* just in case, sasl_dispose() should take care of it */
- mci->mci_conn = NULL;
- }
-
/* make a new client sasl connection */
saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
: "smtp",
CurHostName, NULL, 0, &mci->mci_conn);
+ if (saslresult != SASL_OK)
+ return EX_TEMPFAIL;
/* set properties */
(void) memset(&ssp, '\0', sizeof ssp);
-# if SFIO
+
/* XXX should these be options settable via .cf ? */
- /* ssp.min_ssf = 0; is default due to memset() */
+# if STARTTLS
+#endif /* STARTTLS */
{
- ssp.max_ssf = INT_MAX;
+ ssp.max_ssf = MaxSLBits;
ssp.maxbufsize = MAXOUTLEN;
-# if 0
+# if 0
ssp.security_flags = SASL_SEC_NOPLAINTEXT;
-# endif /* 0 */
+# endif /* 0 */
}
-# endif /* SFIO */
saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
@@ -1151,19 +1444,19 @@ attemptauth(m, mci, e, mechused)
/* external security strength factor, authentication id */
ssf.ssf = 0;
ssf.auth_id = NULL;
-# if _FFR_EXT_MECH
- out = macvalue(macid("{cert_subject}", NULL), e);
+#if STARTTLS
+ out = macvalue(macid("{cert_subject}"), e);
if (out != NULL && *out != '\0')
ssf.auth_id = out;
- out = macvalue(macid("{cipher_bits}", NULL), e);
+ out = macvalue(macid("{cipher_bits}"), e);
if (out != NULL && *out != '\0')
ssf.ssf = atoi(out);
-# endif /* _FFR_EXT_MECH */
+#endif /* STARTTLS */
saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
if (saslresult != SASL_OK)
return EX_TEMPFAIL;
-# if NETINET
+#if NETINET
/* set local/remote ipv4 addresses */
if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
{
@@ -1175,7 +1468,8 @@ attemptauth(m, mci, e, mechused)
!= SASL_OK)
return EX_TEMPFAIL;
addrsize = sizeof(struct sockaddr_in);
- if (getsockname(fileno(mci->mci_out),
+ if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
+ NULL),
(struct sockaddr *) &saddr_l, &addrsize) == 0)
{
if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
@@ -1183,28 +1477,26 @@ attemptauth(m, mci, e, mechused)
return EX_TEMPFAIL;
}
}
-# endif /* NETINET */
+#endif /* NETINET */
/* start client side of sasl */
saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
NULL, &client_interact,
&out, &outlen,
(const char **)&mechusing);
- callbacks[CB_AUTHNAME_IDX].context = mechusing;
if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
{
-# if SFIO
if (saslresult == SASL_NOMECH && LogLevel > 8)
{
sm_syslog(LOG_NOTICE, e->e_id,
- "available AUTH mechanisms do not fulfill requirements");
+ "AUTH=client, available mechanisms do not fulfill requirements");
}
-# endif /* SFIO */
return EX_TEMPFAIL;
}
- *mechused = mechusing;
+ /* just point current mechanism to the data in the sasl library */
+ (*sai)[SASL_MECH] = mechusing;
/* send the info across the wire */
if (outlen > 0)
@@ -1223,30 +1515,30 @@ attemptauth(m, mci, e, mechused)
{
smtpmessage("AUTH %s", m, mci, mechusing);
}
+ sm_sasl_free(out); /* XXX only if no rpool is used */
/* get the reply */
- smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL);
- /* which timeout? XXX */
+ smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL);
for (;;)
{
/* check return code from server */
if (smtpresult == 235)
{
- define(macid("{auth_type}", NULL),
- newstr(mechusing), e);
-# if !SFIO
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, NOQID,
- "SASL: outgoing connection to %.64s: mech=%.16s",
- mci->mci_host, mechusing);
-# endif /* !SFIO */
+ macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
+ mechusing);
return EX_OK;
}
if (smtpresult == -1)
return EX_IOERR;
- if (smtpresult != 334)
+ if (REPLYTYPE(smtpresult) == 5)
+ return EX_NOPERM; /* ugly, but ... */
+ if (REPLYTYPE(smtpresult) != 3)
+ {
+ /* should we fail deliberately, see RFC 2554 4. ? */
+ /* smtpmessage("*", m, mci); */
return EX_TEMPFAIL;
+ }
saslresult = sasl_client_step(mci->mci_conn,
mci->mci_sasl_string,
@@ -1257,11 +1549,11 @@ attemptauth(m, mci, e, mechused)
if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
{
if (tTd(95, 5))
- dprintf("AUTH FAIL: %s (%d)\n",
+ sm_dprintf("AUTH FAIL=%s (%d)\n",
sasl_errstring(saslresult, NULL, NULL),
saslresult);
- /* fail deliberately, see RFC 2254 4. */
+ /* fail deliberately, see RFC 2554 4. */
smtpmessage("*", m, mci);
/*
@@ -1269,9 +1561,9 @@ attemptauth(m, mci, e, mechused)
** mechanism; how to do that?
*/
- smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
+ smtpresult = reply(m, mci, e, TimeOuts.to_auth,
getsasldata, NULL);
- return EX_TEMPFAIL;
+ return EX_NOPERM;
}
if (outlen > 0)
@@ -1287,15 +1579,14 @@ attemptauth(m, mci, e, mechused)
}
else
in64[0] = '\0';
+ sm_sasl_free(out); /* XXX only if no rpool is used */
smtpmessage("%s", m, mci, in64);
- smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
+ smtpresult = reply(m, mci, e, TimeOuts.to_auth,
getsasldata, NULL);
- /* which timeout? XXX */
}
/* NOTREACHED */
}
-
- /*
+/*
** SMTPAUTH -- try to AUTHenticate
**
** This will try mechanisms in the order the sasl library decided until:
@@ -1309,7 +1600,16 @@ attemptauth(m, mci, e, mechused)
** e -- the envelope.
**
** Returns:
-** EX_OK/EX_TEMPFAIL
+** EX_OK -- authentication was successful
+** EX_UNAVAILABLE -- authentication not possible, e.g.,
+** no data available.
+** EX_NOPERM -- authentication failed.
+** EX_TEMPFAIL -- temporary failure.
+**
+** Notice: AuthInfo is used for all connections, hence we must
+** return EX_TEMPFAIL only if we really want to retry, i.e.,
+** iff getauth() tempfailed or getauth() was used and
+** authentication tempfailed.
*/
int
@@ -1319,59 +1619,94 @@ smtpauth(m, mci, e)
ENVELOPE *e;
{
int result;
- char *mechused;
- char *h;
- static char *defrealm = NULL;
- static char *mechs = NULL;
+ int i;
+ bool usedgetauth;
- mci->mci_sasl_auth = FALSE;
- if (defrealm == NULL)
- {
- h = readauth(SASL_DEFREALM, SASLInfo, TRUE);
- if (h != NULL && *h != '\0')
- defrealm = newstr(h);
- }
- if (defrealm == NULL || *defrealm == '\0')
- defrealm = newstr(macvalue('j', CurEnv));
- callbacks[CB_GETREALM_IDX].context = defrealm;
+ mci->mci_sasl_auth = false;
+ for (i = 0; i < SASL_MECH ; i++)
+ mci->mci_sai[i] = NULL;
-# if _FFR_DEFAUTHINFO_MECHS
- if (mechs == NULL)
+ result = getauth(mci, e, &(mci->mci_sai));
+ if (result == EX_TEMPFAIL)
+ return result;
+ usedgetauth = true;
+
+ /* no data available: don't try to authenticate */
+ if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
+ return result;
+ if (result != EX_OK)
{
- h = readauth(SASL_MECH, SASLInfo, TRUE);
- if (h != NULL && *h != '\0')
- mechs = newstr(h);
+ if (SASLInfo == NULL)
+ return EX_UNAVAILABLE;
+
+ /* read authinfo from file */
+ result = readauth(SASLInfo, true, &(mci->mci_sai),
+ mci->mci_rpool);
+ if (result != EX_OK)
+ return result;
+ usedgetauth = false;
}
-# endif /* _FFR_DEFAUTHINFO_MECHS */
- if (mechs == NULL || *mechs == '\0')
- mechs = AuthMechanisms;
- mci->mci_saslcap = intersect(mechs, mci->mci_saslcap);
+
+ /* check whether sufficient data is available */
+ if (mci->mci_sai[SASL_PASSWORD] == NULL ||
+ *(mci->mci_sai)[SASL_PASSWORD] == '\0')
+ return EX_UNAVAILABLE;
+ if ((mci->mci_sai[SASL_AUTHID] == NULL ||
+ *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
+ (mci->mci_sai[SASL_USER] == NULL ||
+ *(mci->mci_sai)[SASL_USER] == '\0'))
+ return EX_UNAVAILABLE;
+
+ /* set the context for the callback function to sai */
+ callbacks[CB_PASS_IDX].context = (void *)&mci->mci_sai;
+ callbacks[CB_USER_IDX].context = (void *)&mci->mci_sai;
+ callbacks[CB_AUTHNAME_IDX].context = (void *)&mci->mci_sai;
+ callbacks[CB_GETREALM_IDX].context = (void *)&mci->mci_sai;
+#if 0
+ callbacks[CB_SAFESASL_IDX].context = (void *)&mci->mci_sai;
+#endif /* 0 */
+
+ /* set default value for realm */
+ if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
+ (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
+ macvalue('j', CurEnv));
+
+ /* set default value for list of mechanism to use */
+ if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
+ *(mci->mci_sai)[SASL_MECHLIST] == '\0')
+ (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
+
+ /* create list of mechanisms to try */
+ mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
+ mci->mci_saslcap, mci->mci_rpool);
/* initialize sasl client library */
- result = sasl_client_init(callbacks);
+ result = init_sasl_client();
if (result != SASL_OK)
- return EX_TEMPFAIL;
+ return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
do
{
- result = attemptauth(m, mci, e, &mechused);
+ result = attemptauth(m, mci, e, &(mci->mci_sai));
if (result == EX_OK)
- mci->mci_sasl_auth = TRUE;
- else if (result == EX_TEMPFAIL)
+ mci->mci_sasl_auth = true;
+ else if (result == EX_TEMPFAIL || result == EX_NOPERM)
{
- mci->mci_saslcap = removemech(mechused,
- mci->mci_saslcap);
+ mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
+ mci->mci_saslcap,
+ mci->mci_rpool);
if (mci->mci_saslcap == NULL ||
*(mci->mci_saslcap) == '\0')
- return EX_TEMPFAIL;
+ return usedgetauth ? result
+ : EX_UNAVAILABLE;
}
- else /* all others for now */
- return EX_TEMPFAIL;
+ else
+ return result;
} while (result != EX_OK);
return result;
}
-# endif /* SASL */
+#endif /* SASL */
- /*
+/*
** SMTPMAILFROM -- send MAIL command
**
** Parameters:
@@ -1389,18 +1724,31 @@ smtpmailfrom(m, mci, e)
int r;
char *bufp;
char *bodytype;
+ char *enhsc;
char buf[MAXNAME + 1];
char optbuf[MAXLINE];
- char *enhsc;
if (tTd(18, 2))
- dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
+ sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
enhsc = NULL;
+ /*
+ ** Check if connection is gone, if so
+ ** it's a tempfail and we use mci_errno
+ ** for the reason.
+ */
+
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ errno = mci->mci_errno;
+ return EX_TEMPFAIL;
+ }
+
/* set up appropriate options to include */
if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
{
- snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
+ (void) sm_snprintf(optbuf, sizeof optbuf, " SIZE=%ld",
+ e->e_msgsize);
bufp = &optbuf[strlen(optbuf)];
}
else
@@ -1421,7 +1769,7 @@ smtpmailfrom(m, mci, e)
if (bodytype != NULL &&
SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
{
- snprintf(bufp, SPACELEFT(optbuf, bufp),
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
" BODY=%s", bodytype);
bufp += strlen(bufp);
}
@@ -1433,7 +1781,7 @@ smtpmailfrom(m, mci, e)
/* EMPTY */
/* just pass it through */
}
-# if MIME8TO7
+#if MIME8TO7
else if (bitset(MM_CVTMIME, MimeMode) &&
!bitset(EF_DONT_MIME, e->e_flags) &&
(!bitset(MM_PASS8BIT, MimeMode) ||
@@ -1442,7 +1790,7 @@ smtpmailfrom(m, mci, e)
/* must convert from 8bit MIME format to 7bit encoded */
mci->mci_flags |= MCIF_CVT8TO7;
}
-# endif /* MIME8TO7 */
+#endif /* MIME8TO7 */
else if (!bitset(MM_PASS8BIT, MimeMode))
{
/* cannot just send a 8-bit version */
@@ -1458,7 +1806,7 @@ smtpmailfrom(m, mci, e)
if (e->e_envid != NULL &&
SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
{
- snprintf(bufp, SPACELEFT(optbuf, bufp),
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
" ENVID=%s", e->e_envid);
bufp += strlen(bufp);
}
@@ -1467,7 +1815,7 @@ smtpmailfrom(m, mci, e)
if (bitset(EF_RET_PARAM, e->e_flags) &&
SPACELEFT(optbuf, bufp) > 9)
{
- snprintf(bufp, SPACELEFT(optbuf, bufp),
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
" RET=%s",
bitset(EF_NO_BODY_RETN, e->e_flags) ?
"HDRS" : "FULL");
@@ -1477,22 +1825,50 @@ smtpmailfrom(m, mci, e)
if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
-# if SASL
+#if SASL
&& (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
-# endif /* SASL */
+#endif /* SASL */
)
{
- snprintf(bufp, SPACELEFT(optbuf, bufp),
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
" AUTH=%s", e->e_auth_param);
bufp += strlen(bufp);
}
/*
+ ** 17 is the max length required, we could use log() to compute
+ ** the exact length (and check IS_DLVR_TRACE())
+ */
+
+ if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
+ IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
+ {
+ long dby;
+
+ /*
+ ** Avoid problems with delays (for R) since the check
+ ** in deliver() whether min-deliver-time is sufficient.
+ ** Alternatively we could pass the computed time to this
+ ** function.
+ */
+
+ dby = e->e_deliver_by - (curtime() - e->e_ctime);
+ if (dby <= 0 && IS_DLVR_RETURN(e))
+ dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
+ " BY=%ld;%c%s",
+ dby,
+ IS_DLVR_RETURN(e) ? 'R' : 'N',
+ IS_DLVR_TRACE(e) ? "T" : "");
+ bufp += strlen(bufp);
+ }
+
+ /*
** Send the MAIL command.
** Designates the sender.
*/
- mci->mci_state = MCIS_ACTIVE;
+ mci->mci_state = MCIS_MAIL;
if (bitset(EF_RESPONSE, e->e_flags) &&
!bitnset(M_NO_NULL_FROM, m->m_flags))
@@ -1520,13 +1896,12 @@ smtpmailfrom(m, mci, e)
*bufp == '@' ? ',' : ':', bufp, optbuf);
}
SmtpPhase = mci->mci_phase = "client MAIL";
- sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
+ sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc);
if (r < 0)
{
/* communications failure */
- mci->mci_errno = errno;
mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
smtpquit(m, mci, e);
return EX_TEMPFAIL;
@@ -1594,7 +1969,7 @@ smtpmailfrom(m, mci, e)
smtpquit(m, mci, e);
return EX_PROTOCOL;
}
- /*
+/*
** SMTPRCPT -- designate recipient.
**
** Parameters:
@@ -1611,58 +1986,104 @@ smtpmailfrom(m, mci, e)
*/
int
-smtprcpt(to, m, mci, e)
+smtprcpt(to, m, mci, e, ctladdr, xstart)
ADDRESS *to;
register MAILER *m;
MCI *mci;
ENVELOPE *e;
+ ADDRESS *ctladdr;
+ time_t xstart;
{
- register int r;
char *bufp;
char optbuf[MAXLINE];
- char *enhsc;
- enhsc = NULL;
+#if PIPELINING
+ /*
+ ** If there is status waiting from the other end, read it.
+ ** This should normally happen because of SMTP pipelining.
+ */
+
+ while (mci->mci_nextaddr != NULL &&
+ sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL))
+ {
+ int r;
+
+ r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
+ if (r != EX_OK)
+ {
+ markfailure(e, mci->mci_nextaddr, mci, r, false);
+ giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
+ ctladdr, xstart, e, to);
+ }
+ mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
+ }
+#endif /* PIPELINING */
+
+ /*
+ ** Check if connection is gone, if so
+ ** it's a tempfail and we use mci_errno
+ ** for the reason.
+ */
+
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ errno = mci->mci_errno;
+ return EX_TEMPFAIL;
+ }
+
optbuf[0] = '\0';
bufp = optbuf;
/*
- ** warning: in the following it is assumed that the free space
+ ** Warning: in the following it is assumed that the free space
** in bufp is sizeof optbuf
*/
+
if (bitset(MCIF_DSN, mci->mci_flags))
{
+ if (IS_DLVR_NOTIFY(e) &&
+ !bitset(MCIF_DLVR_BY, mci->mci_flags))
+ {
+ /* RFC 2852: 4.1.4.2 */
+ if (!bitset(QHASNOTIFY, to->q_flags))
+ to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
+ else if (bitset(QPINGONSUCCESS, to->q_flags) ||
+ bitset(QPINGONFAILURE, to->q_flags) ||
+ bitset(QPINGONDELAY, to->q_flags))
+ to->q_flags |= QPINGONDELAY;
+ }
+
/* NOTIFY= parameter */
if (bitset(QHASNOTIFY, to->q_flags) &&
bitset(QPRIMARY, to->q_flags) &&
!bitnset(M_LOCALMAILER, m->m_flags))
{
- bool firstone = TRUE;
+ bool firstone = true;
- (void) strlcat(bufp, " NOTIFY=", sizeof optbuf);
+ (void) sm_strlcat(bufp, " NOTIFY=", sizeof optbuf);
if (bitset(QPINGONSUCCESS, to->q_flags))
{
- (void) strlcat(bufp, "SUCCESS", sizeof optbuf);
- firstone = FALSE;
+ (void) sm_strlcat(bufp, "SUCCESS", sizeof optbuf);
+ firstone = false;
}
if (bitset(QPINGONFAILURE, to->q_flags))
{
if (!firstone)
- (void) strlcat(bufp, ",",
+ (void) sm_strlcat(bufp, ",",
sizeof optbuf);
- (void) strlcat(bufp, "FAILURE", sizeof optbuf);
- firstone = FALSE;
+ (void) sm_strlcat(bufp, "FAILURE", sizeof optbuf);
+ firstone = false;
}
if (bitset(QPINGONDELAY, to->q_flags))
{
if (!firstone)
- (void) strlcat(bufp, ",",
+ (void) sm_strlcat(bufp, ",",
sizeof optbuf);
- (void) strlcat(bufp, "DELAY", sizeof optbuf);
- firstone = FALSE;
+ (void) sm_strlcat(bufp, "DELAY", sizeof optbuf);
+ firstone = false;
}
if (firstone)
- (void) strlcat(bufp, "NEVER", sizeof optbuf);
+ (void) sm_strlcat(bufp, "NEVER", sizeof optbuf);
bufp += strlen(bufp);
}
@@ -1670,39 +2091,113 @@ smtprcpt(to, m, mci, e)
if (to->q_orcpt != NULL &&
SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
{
- snprintf(bufp, SPACELEFT(optbuf, bufp),
+ (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
" ORCPT=%s", to->q_orcpt);
bufp += strlen(bufp);
}
}
smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
+ mci->mci_state = MCIS_RCPT;
SmtpPhase = mci->mci_phase = "client RCPT";
- sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
+ sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
+
+#if PIPELINING
+ /*
+ ** If running SMTP pipelining, we will pick up status later
+ */
+
+ if (bitset(MCIF_PIPELINED, mci->mci_flags))
+ return EX_OK;
+#endif /* PIPELINING */
+
+ return smtprcptstat(to, m, mci, e);
+}
+/*
+** SMTPRCPTSTAT -- get recipient status
+**
+** This is only called during SMTP pipelining
+**
+** Parameters:
+** to -- address of recipient.
+** m -- mailer being sent to.
+** mci -- the mailer connection information.
+** e -- the envelope for this message.
+**
+** Returns:
+** EX_* -- protocol status
+*/
+
+static int
+smtprcptstat(to, m, mci, e)
+ ADDRESS *to;
+ MAILER *m;
+ register MCI *mci;
+ register ENVELOPE *e;
+{
+ int r;
+ int save_errno;
+ char *enhsc;
+
+ /*
+ ** Check if connection is gone, if so
+ ** it's a tempfail and we use mci_errno
+ ** for the reason.
+ */
+
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ errno = mci->mci_errno;
+ return EX_TEMPFAIL;
+ }
+
+ enhsc = NULL;
r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc);
- to->q_rstatus = newstr(SmtpReplyBuffer);
- to->q_status = ENHSCN(enhsc, smtptodsn(r));
+ save_errno = errno;
+ to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
+ to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
if (!bitnset(M_LMTP, m->m_flags))
to->q_statmta = mci->mci_host;
if (r < 0 || REPLYTYPE(r) == 4)
+ {
+ mci->mci_retryrcpt = true;
+ errno = save_errno;
return EX_TEMPFAIL;
+ }
else if (REPLYTYPE(r) == 2)
+ {
+ char *t;
+
+ if ((t = mci->mci_tolist) != NULL)
+ {
+ char *p;
+
+ *t++ = ',';
+ for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
+ continue;
+ *t = '\0';
+ mci->mci_tolist = t;
+ }
+#if PIPELINING
+ mci->mci_okrcpts++;
+#endif /* PIPELINING */
return EX_OK;
+ }
else if (r == 550)
{
- to->q_status = ENHSCN(enhsc, "5.1.1");
+ to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
return EX_NOUSER;
}
else if (r == 551)
{
- to->q_status = ENHSCN(enhsc, "5.1.6");
+ to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
return EX_NOUSER;
}
else if (r == 553)
{
- to->q_status = ENHSCN(enhsc, "5.1.3");
+ to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
return EX_NOUSER;
}
else if (REPLYTYPE(r) == 5)
@@ -1722,7 +2217,7 @@ smtprcpt(to, m, mci, e)
SmtpReplyBuffer);
return EX_PROTOCOL;
}
- /*
+/*
** SMTPDATA -- send the data and clean up the transaction.
**
** Parameters:
@@ -1732,19 +2227,18 @@ smtprcpt(to, m, mci, e)
**
** Returns:
** exit status corresponding to DATA command.
-**
-** Side Effects:
-** none.
*/
static jmp_buf CtxDataTimeout;
-static EVENT *volatile DataTimeout = NULL;
+static SM_EVENT *volatile DataTimeout = NULL;
int
-smtpdata(m, mci, e)
+smtpdata(m, mci, e, ctladdr, xstart)
MAILER *m;
register MCI *mci;
register ENVELOPE *e;
+ ADDRESS *ctladdr;
+ time_t xstart;
{
register int r;
int rstat;
@@ -1752,30 +2246,79 @@ smtpdata(m, mci, e)
time_t timeout;
char *enhsc;
+ /*
+ ** Check if connection is gone, if so
+ ** it's a tempfail and we use mci_errno
+ ** for the reason.
+ */
+
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ errno = mci->mci_errno;
+ return EX_TEMPFAIL;
+ }
+
enhsc = NULL;
/*
** Send the data.
** First send the command and check that it is ok.
- ** Then send the data.
+ ** Then send the data (if there are valid recipients).
** Follow it up with a dot to terminate.
** Finally get the results of the transaction.
*/
/* send the command and check ok to proceed */
smtpmessage("DATA", m, mci);
+
+#if PIPELINING
+ if (mci->mci_nextaddr != NULL)
+ {
+ char *oldto = e->e_to;
+
+ /* pick up any pending RCPT responses for SMTP pipelining */
+ while (mci->mci_nextaddr != NULL)
+ {
+ int r;
+
+ e->e_to = mci->mci_nextaddr->q_paddr;
+ r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
+ if (r != EX_OK)
+ {
+ markfailure(e, mci->mci_nextaddr, mci, r,
+ false);
+ giveresponse(r, mci->mci_nextaddr->q_status, m,
+ mci, ctladdr, xstart, e,
+ mci->mci_nextaddr);
+ if (r == EX_TEMPFAIL)
+ mci->mci_nextaddr->q_state = QS_RETRY;
+ }
+ mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
+ }
+ e->e_to = oldto;
+ }
+#endif /* PIPELINING */
+
+ /* now proceed with DATA phase */
SmtpPhase = mci->mci_phase = "client DATA 354";
- sm_setproctitle(TRUE, e, "%s %s: %s",
+ mci->mci_state = MCIS_DATA;
+ sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e), CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc);
if (r < 0 || REPLYTYPE(r) == 4)
{
smtpquit(m, mci, e);
+ errno = mci->mci_errno;
return EX_TEMPFAIL;
}
else if (REPLYTYPE(r) == 5)
{
smtprset(m, mci, e);
+#if PIPELINING
+ if (mci->mci_okrcpts <= 0)
+ return mci->mci_retryrcpt ? EX_TEMPFAIL
+ : EX_UNAVAILABLE;
+#endif /* PIPELINING */
return EX_UNAVAILABLE;
}
else if (REPLYTYPE(r) != 3)
@@ -1790,9 +2333,19 @@ smtpdata(m, mci, e)
smtprset(m, mci, e);
mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
SmtpReplyBuffer);
+#if PIPELINING
+ if (mci->mci_okrcpts <= 0)
+ return mci->mci_retryrcpt ? EX_TEMPFAIL
+ : EX_PROTOCOL;
+#endif /* PIPELINING */
return EX_PROTOCOL;
}
+#if PIPELINING
+ if (mci->mci_okrcpts > 0)
+ {
+#endif /* PIPELINING */
+
/*
** Set timeout around data writes. Make it at least large
** enough for DNS timeouts on all recipients plus some fudge
@@ -1828,7 +2381,7 @@ smtpdata(m, mci, e)
else
timeout = DATA_PROGRESS_TIMEOUT;
- DataTimeout = setevent(timeout, datatimeout, 0);
+ DataTimeout = sm_setevent(timeout, datatimeout, 0);
/*
@@ -1850,42 +2403,36 @@ smtpdata(m, mci, e)
*/
if (DataTimeout != NULL)
- clrevent(DataTimeout);
+ sm_clrevent(DataTimeout);
-# if _FFR_CATCH_BROKEN_MTAS
- {
- fd_set readfds;
- struct timeval timeout;
+#if PIPELINING
+ }
+#endif /* PIPELINING */
- FD_ZERO(&readfds);
- FD_SET(fileno(mci->mci_in), &readfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- if (select(fileno(mci->mci_in) + 1, FDSET_CAST &readfds,
- NULL, NULL, &timeout) > 0 &&
- FD_ISSET(fileno(mci->mci_in), &readfds))
- {
- /* terminate the message */
- fprintf(mci->mci_out, ".%s", m->m_eol);
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> .\n",
- (int) getpid());
- if (Verbose)
- nmessage(">>> .");
+#if _FFR_CATCH_BROKEN_MTAS
+ if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL))
+ {
+ /* terminate the message */
+ (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
+ m->m_eol);
+ if (TrafficLogFile != NULL)
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> .\n", (int) CurrentPid);
+ if (Verbose)
+ nmessage(">>> .");
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
- CurHostName);
- mci->mci_errno = EIO;
- mci->mci_state = MCIS_ERROR;
- mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
- smtpquit(m, mci, e);
- return EX_PROTOCOL;
- }
+ sm_syslog(LOG_CRIT, e->e_id,
+ "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
+ CurHostName);
+ mci->mci_errno = EIO;
+ mci->mci_state = MCIS_ERROR;
+ mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
+ smtpquit(m, mci, e);
+ return EX_PROTOCOL;
}
-# endif /* _FFR_CATCH_BROKEN_MTAS */
+#endif /* _FFR_CATCH_BROKEN_MTAS */
- if (ferror(mci->mci_out))
+ if (sm_io_error(mci->mci_out))
{
/* error during processing -- don't send the dot */
mci->mci_errno = EIO;
@@ -1896,15 +2443,16 @@ smtpdata(m, mci, e)
}
/* terminate the message */
- fprintf(mci->mci_out, ".%s", m->m_eol);
+ (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", m->m_eol);
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid());
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> .\n", (int) CurrentPid);
if (Verbose)
nmessage(">>> .");
/* check for the results of the transaction */
SmtpPhase = mci->mci_phase = "client DATA status";
- sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
+ sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
if (bitnset(M_LMTP, m->m_flags))
return EX_OK;
@@ -1920,26 +2468,24 @@ smtpdata(m, mci, e)
rstat = EX_TEMPFAIL;
else if (REPLYTYPE(r) == 4)
rstat = xstat = EX_TEMPFAIL;
- else if (REPLYCLASS(r) != 5)
- rstat = xstat = EX_PROTOCOL;
else if (REPLYTYPE(r) == 2)
rstat = xstat = EX_OK;
+ else if (REPLYCLASS(r) != 5)
+ rstat = xstat = EX_PROTOCOL;
else if (REPLYTYPE(r) == 5)
rstat = EX_UNAVAILABLE;
else
rstat = EX_PROTOCOL;
mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
SmtpReplyBuffer);
- if (e->e_statmsg != NULL)
- sm_free(e->e_statmsg);
if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
(r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
r += 5;
else
r = 4;
- e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
+ e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
SmtpPhase = mci->mci_phase = "idle";
- sm_setproctitle(TRUE, e, "%s: %s", CurHostName, mci->mci_phase);
+ sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
if (rstat != EX_PROTOCOL)
return rstat;
if (LogLevel > 1)
@@ -1952,7 +2498,6 @@ smtpdata(m, mci, e)
return rstat;
}
-
static void
datatimeout()
{
@@ -1978,8 +2523,8 @@ datatimeout()
timeout = DATA_PROGRESS_TIMEOUT;
/* reset the timeout */
- DataTimeout = sigsafe_setevent(timeout, datatimeout, 0);
- DataProgress = FALSE;
+ DataTimeout = sm_sigsafe_setevent(timeout, datatimeout, 0);
+ DataProgress = false;
}
else
{
@@ -1993,10 +2538,9 @@ datatimeout()
errno = ETIMEDOUT;
longjmp(CtxDataTimeout, 1);
}
-
errno = save_errno;
}
- /*
+/*
** SMTPGETSTAT -- get status code from DATA in LMTP
**
** Parameters:
@@ -2015,10 +2559,11 @@ smtpgetstat(m, mci, e)
ENVELOPE *e;
{
int r;
- int status;
+ int status, xstat;
char *enhsc;
enhsc = NULL;
+
/* check for the results of the transaction */
r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
if (r < 0)
@@ -2026,25 +2571,24 @@ smtpgetstat(m, mci, e)
smtpquit(m, mci, e);
return EX_TEMPFAIL;
}
+ xstat = EX_NOTSTICKY;
if (REPLYTYPE(r) == 4)
status = EX_TEMPFAIL;
- else if (REPLYCLASS(r) != 5)
- status = EX_PROTOCOL;
else if (REPLYTYPE(r) == 2)
- status = EX_OK;
+ status = xstat = EX_OK;
+ else if (REPLYCLASS(r) != 5)
+ status = xstat = EX_PROTOCOL;
else if (REPLYTYPE(r) == 5)
status = EX_UNAVAILABLE;
else
status = EX_PROTOCOL;
- if (e->e_statmsg != NULL)
- sm_free(e->e_statmsg);
if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
(r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
r += 5;
else
r = 4;
- e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
- mci_setstat(mci, status, ENHSCN(enhsc, smtptodsn(r)),
+ e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
+ mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
SmtpReplyBuffer);
if (LogLevel > 1 && status == EX_PROTOCOL)
{
@@ -2055,7 +2599,7 @@ smtpgetstat(m, mci, e)
}
return status;
}
- /*
+/*
** SMTPQUIT -- close the SMTP connection.
**
** Parameters:
@@ -2078,11 +2622,17 @@ smtpquit(m, mci, e)
{
bool oldSuprErrs = SuprErrs;
int rcode;
+ char *oldcurhost;
+ oldcurhost = CurHostName;
CurHostName = mci->mci_host; /* XXX UGLY XXX */
if (CurHostName == NULL)
CurHostName = MyHostName;
+#if PIPELINING
+ mci->mci_okrcpts = 0;
+#endif /* PIPELINING */
+
/*
** Suppress errors here -- we may be processing a different
** job when we do the quit connection, and we don't want the
@@ -2090,7 +2640,7 @@ smtpquit(m, mci, e)
** problem.
*/
- SuprErrs = TRUE;
+ SuprErrs = true;
/* send the quit message if we haven't gotten I/O error */
if (mci->mci_state != MCIS_ERROR &&
@@ -2105,7 +2655,7 @@ smtpquit(m, mci, e)
SuprErrs = oldSuprErrs;
if (mci->mci_state == MCIS_CLOSED ||
origstate == MCIS_CLOSED)
- return;
+ goto end;
}
/* now actually close the connection and pick up the zombie */
@@ -2127,8 +2677,12 @@ smtpquit(m, mci, e)
}
SuprErrs = oldSuprErrs;
+
+ end:
+ CurHostName = oldcurhost;
+ return;
}
- /*
+/*
** SMTPRSET -- send a RSET (reset) command
**
** Parameters:
@@ -2155,6 +2709,22 @@ smtprset(m, mci, e)
if (CurHostName == NULL)
CurHostName = MyHostName;
+#if PIPELINING
+ mci->mci_okrcpts = 0;
+#endif /* PIPELINING */
+
+ /*
+ ** Check if connection is gone, if so
+ ** it's a tempfail and we use mci_errno
+ ** for the reason.
+ */
+
+ if (mci->mci_state == MCIS_CLOSED)
+ {
+ errno = mci->mci_errno;
+ return;
+ }
+
SmtpPhase = "client RSET";
smtpmessage("RSET", m, mci);
r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL);
@@ -2177,7 +2747,7 @@ smtprset(m, mci, e)
}
smtpquit(m, mci, e);
}
- /*
+/*
** SMTPPROBE -- check the connection state
**
** Parameters:
@@ -2211,7 +2781,7 @@ smtpprobe(mci)
smtpquit(m, mci, e);
return r;
}
- /*
+/*
** REPLY -- read arpanet reply
**
** Parameters:
@@ -2221,6 +2791,7 @@ smtpprobe(mci)
** timeout -- the timeout for reads.
** pfunc -- processing function called on each line of response.
** If null, no special processing is done.
+** enhstat -- optional, returns enhanced error code string (if set)
**
** Returns:
** reply code it reads.
@@ -2240,16 +2811,25 @@ reply(m, mci, e, timeout, pfunc, enhstat)
{
register char *bufp;
register int r;
- bool firstline = TRUE;
+ bool firstline = true;
char junkbuf[MAXLINE];
static char enhstatcode[ENHSCLEN];
int save_errno;
+ /*
+ ** Flush the output before reading response.
+ **
+ ** For SMTP pipelining, it would be better if we didn't do
+ ** this if there was already data waiting to be read. But
+ ** to do it properly means pushing it to the I/O library,
+ ** since it really needs to be done below the buffer layer.
+ */
+
if (mci->mci_out != NULL)
- (void) fflush(mci->mci_out);
+ (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
if (tTd(18, 1))
- dprintf("reply\n");
+ sm_dprintf("reply\n");
/*
** Read the input line, being careful not to hang.
@@ -2261,18 +2841,28 @@ reply(m, mci, e, timeout, pfunc, enhstat)
register char *p;
/* actually do the read */
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
+ if (e->e_xfp != NULL) /* for debugging */
+ (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
/* if we are in the process of closing just give the code */
if (mci->mci_state == MCIS_CLOSED)
return SMTPCLOSING;
+ /* don't try to read from a non-existant fd */
+ if (mci->mci_in == NULL)
+ {
+ if (mci->mci_errno == 0)
+ mci->mci_errno = EBADF;
+ errno = mci->mci_errno;
+ return -1;
+ }
+
if (mci->mci_out != NULL)
- (void) fflush(mci->mci_out);
+ (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
/* get the line from the other side */
p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
+ save_errno = errno;
mci->mci_lastuse = curtime();
if (p == NULL)
@@ -2281,18 +2871,25 @@ reply(m, mci, e, timeout, pfunc, enhstat)
extern char MsgBuf[];
/* if the remote end closed early, fake an error */
+ errno = save_errno;
if (errno == 0)
-# ifdef ECONNRESET
+ {
+ (void) sm_snprintf(SmtpReplyBuffer,
+ sizeof SmtpReplyBuffer,
+ "421 4.4.1 Connection reset by %s",
+ CURHOSTNAME);
+#ifdef ECONNRESET
errno = ECONNRESET;
-# else /* ECONNRESET */
+#else /* ECONNRESET */
errno = EPIPE;
-# endif /* ECONNRESET */
+#endif /* ECONNRESET */
+ }
mci->mci_errno = errno;
oldholderrs = HoldErrs;
- HoldErrs = TRUE;
+ HoldErrs = true;
usrerr("451 4.4.1 reply: read error from %s",
- CurHostName == NULL ? "NO_HOST" : CurHostName);
+ CURHOSTNAME);
/* errors on QUIT should not be persistent */
if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
@@ -2302,35 +2899,31 @@ reply(m, mci, e, timeout, pfunc, enhstat)
if (tTd(18, 100))
(void) pause();
mci->mci_state = MCIS_ERROR;
- save_errno = errno;
smtpquit(m, mci, e);
-# if XDEBUG
+#if XDEBUG
{
char wbuf[MAXLINE];
- int wbufleft = sizeof wbuf;
p = wbuf;
if (e->e_to != NULL)
{
- int plen;
-
- snprintf(p, wbufleft, "%s... ",
- shortenstring(e->e_to, MAXSHORTSTR));
- plen = strlen(p);
- p += plen;
- wbufleft -= plen;
+ (void) sm_snprintf(p,
+ SPACELEFT(wbuf, p),
+ "%s... ",
+ shortenstring(e->e_to, MAXSHORTSTR));
+ p += strlen(p);
}
- snprintf(p, wbufleft, "reply(%.100s) during %s",
- CurHostName == NULL ? "NO_HOST" : CurHostName,
- SmtpPhase);
+ (void) sm_snprintf(p, SPACELEFT(wbuf, p),
+ "reply(%.100s) during %s",
+ CURHOSTNAME, SmtpPhase);
checkfd012(wbuf);
}
-# endif /* XDEBUG */
- errno = save_errno;
+#endif /* XDEBUG */
HoldErrs = oldholderrs;
+ errno = save_errno;
return -1;
}
- fixcrlf(bufp, TRUE);
+ fixcrlf(bufp, true);
/* EHLO failure is not a real error */
if (e->e_xfp != NULL && (bufp[0] == '4' ||
@@ -2340,17 +2933,20 @@ reply(m, mci, e, timeout, pfunc, enhstat)
if (SmtpNeedIntro)
{
/* inform user who we are chatting with */
- fprintf(CurEnv->e_xfp,
- "... while talking to %s:\n",
- CurHostName == NULL ? "NO_HOST" : CurHostName);
- SmtpNeedIntro = FALSE;
+ (void) sm_io_fprintf(CurEnv->e_xfp,
+ SM_TIME_DEFAULT,
+ "... while talking to %s:\n",
+ CURHOSTNAME);
+ SmtpNeedIntro = false;
}
if (SmtpMsgBuffer[0] != '\0')
- fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ ">>> %s\n", SmtpMsgBuffer);
SmtpMsgBuffer[0] = '\0';
/* now log the message as from the other side */
- fprintf(e->e_xfp, "<<< %s\n", bufp);
+ (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
+ "<<< %s\n", bufp);
}
/* display the input for verbose mode */
@@ -2370,7 +2966,7 @@ reply(m, mci, e, timeout, pfunc, enhstat)
if (pfunc != NULL)
(*pfunc)(bufp, firstline, m, mci, e);
- firstline = FALSE;
+ firstline = false;
/* decode the reply code */
r = atoi(bufp);
@@ -2393,9 +2989,8 @@ reply(m, mci, e, timeout, pfunc, enhstat)
*/
/* save temporary failure messages for posterity */
- if (SmtpReplyBuffer[0] == '4' &&
- (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0'))
- snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);
+ if (SmtpReplyBuffer[0] == '4')
+ (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof SmtpError);
/* reply code 421 is "Service Shutting Down" */
if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
@@ -2407,7 +3002,7 @@ reply(m, mci, e, timeout, pfunc, enhstat)
return r;
}
- /*
+/*
** SMTPMESSAGE -- send message to server
**
** Parameters:
@@ -2424,36 +3019,36 @@ reply(m, mci, e, timeout, pfunc, enhstat)
/*VARARGS1*/
void
-# ifdef __STDC__
+#ifdef __STDC__
smtpmessage(char *f, MAILER *m, MCI *mci, ...)
-# else /* __STDC__ */
+#else /* __STDC__ */
smtpmessage(f, m, mci, va_alist)
char *f;
MAILER *m;
MCI *mci;
va_dcl
-# endif /* __STDC__ */
+#endif /* __STDC__ */
{
- VA_LOCAL_DECL
+ SM_VA_LOCAL_DECL
- VA_START(mci);
- (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
- VA_END;
+ SM_VA_START(ap, mci);
+ (void) sm_vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
+ SM_VA_END(ap);
if (tTd(18, 1) || Verbose)
nmessage(">>> %s", SmtpMsgBuffer);
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> %s\n",
- (int) getpid(), SmtpMsgBuffer);
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> %s\n", (int) CurrentPid,
+ SmtpMsgBuffer);
if (mci->mci_out != NULL)
{
- fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
- m == NULL ? "\r\n" : m->m_eol);
+ (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
+ SmtpMsgBuffer, m == NULL ? "\r\n"
+ : m->m_eol);
}
else if (tTd(18, 1))
{
- dprintf("smtpmessage: NULL mci_out\n");
+ sm_dprintf("smtpmessage: NULL mci_out\n");
}
}
-
-#endif /* SMTP */
diff --git a/contrib/sendmail/src/util.c b/contrib/sendmail/src/util.c
index 2017211..c11d085 100644
--- a/contrib/sendmail/src/util.c
+++ b/contrib/sendmail/src/util.c
@@ -11,73 +11,30 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: util.c,v 8.225.2.1.2.26 2001/06/01 08:23:25 gshapiro Exp $";
-#endif /* ! lint */
-
#include <sendmail.h>
-#include <sysexits.h>
-
-
-static void readtimeout __P((time_t));
- /*
-** STRIPQUOTES -- Strip quotes & quote bits from a string.
-**
-** Runs through a string and strips off unquoted quote
-** characters and quote bits. This is done in place.
-**
-** Parameters:
-** s -- the string to strip.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
+SM_RCSID("@(#)$Id: util.c,v 8.357 2001/11/28 19:19:27 gshapiro Exp $")
-void
-stripquotes(s)
- char *s;
-{
- register char *p;
- register char *q;
- register char c;
-
- if (s == NULL)
- return;
+#include <sysexits.h>
+#include <sm/xtrap.h>
- p = q = s;
- do
- {
- c = *p++;
- if (c == '\\')
- c = *p++;
- else if (c == '"')
- continue;
- *q++ = c;
- } while (c != '\0');
-}
- /*
+/*
** ADDQUOTES -- Adds quotes & quote bits to a string.
**
-** Runs through a string and adds characters and quote bits.
+** Runs through a string and adds backslashes and quote bits.
**
** Parameters:
** s -- the string to modify.
+** rpool -- resource pool from which to allocate result
**
** Returns:
** pointer to quoted string.
-**
-** Side Effects:
-** none.
-**
*/
char *
-addquotes(s)
+addquotes(s, rpool)
char *s;
+ SM_RPOOL_T *rpool;
{
int len = 0;
char c;
@@ -94,7 +51,7 @@ addquotes(s)
len++;
}
- q = r = xalloc(len + 3);
+ q = r = sm_rpool_malloc_x(rpool, len + 3);
p = s;
/* add leading quote */
@@ -110,7 +67,7 @@ addquotes(s)
*q = '\0';
return r;
}
- /*
+/*
** RFC822_STRING -- Checks string for proper RFC822 string quoting.
**
** Runs through a string and verifies RFC822 special characters
@@ -121,24 +78,19 @@ addquotes(s)
** s -- the string to modify.
**
** Returns:
-** TRUE -- if the string is RFC822 compliant.
-** FALSE -- if the string is not RFC822 compliant.
-**
-** Side Effects:
-** none.
-**
+** true iff the string is RFC822 compliant, false otherwise.
*/
bool
rfc822_string(s)
char *s;
{
- bool quoted = FALSE;
+ bool quoted = false;
int commentlev = 0;
char *c = s;
if (s == NULL)
- return FALSE;
+ return false;
while (*c != '\0')
{
@@ -147,7 +99,7 @@ rfc822_string(s)
{
c++;
if (*c == '\0')
- return FALSE;
+ return false;
}
else if (commentlev == 0 && *c == '"')
quoted = !quoted;
@@ -157,7 +109,7 @@ rfc822_string(s)
{
/* unbalanced ')' */
if (commentlev == 0)
- return FALSE;
+ return false;
else
commentlev--;
}
@@ -165,17 +117,15 @@ rfc822_string(s)
commentlev++;
else if (commentlev == 0 &&
strchr(MustQuoteChars, *c) != NULL)
- return FALSE;
+ return false;
}
c++;
}
+
/* unbalanced '"' or '(' */
- if (quoted || commentlev != 0)
- return FALSE;
- else
- return TRUE;
+ return !quoted && commentlev == 0;
}
- /*
+/*
** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
**
** Arbitrarily shorten (in place) an RFC822 string and rebalance
@@ -186,7 +136,7 @@ rfc822_string(s)
** length -- the maximum size, 0 if no maximum
**
** Returns:
-** TRUE if string is changed, FALSE otherwise
+** true if string is changed, false otherwise
**
** Side Effects:
** Changes string in place, possibly resulting
@@ -198,9 +148,9 @@ shorten_rfc822_string(string, length)
char *string;
size_t length;
{
- bool backslash = FALSE;
- bool modified = FALSE;
- bool quoted = FALSE;
+ bool backslash = false;
+ bool modified = false;
+ bool quoted = false;
size_t slen;
int parencount = 0;
char *ptr = string;
@@ -218,12 +168,12 @@ shorten_rfc822_string(string, length)
{
if (backslash)
{
- backslash = FALSE;
+ backslash = false;
goto increment;
}
if (*ptr == '\\')
- backslash = TRUE;
+ backslash = true;
else if (*ptr == '(')
{
if (!quoted)
@@ -247,11 +197,11 @@ increment:
{
/* Not enough, backtrack */
if (*ptr == '\\')
- backslash = FALSE;
+ backslash = false;
else if (*ptr == '(' && !quoted)
parencount--;
else if (*ptr == '"' && parencount == 0)
- quoted = FALSE;
+ quoted = false;
break;
}
ptr++;
@@ -262,7 +212,7 @@ increment:
{
if (*ptr != ')')
{
- modified = TRUE;
+ modified = true;
*ptr = ')';
}
ptr++;
@@ -271,19 +221,19 @@ increment:
{
if (*ptr != '"')
{
- modified = TRUE;
+ modified = true;
*ptr = '"';
}
ptr++;
}
if (*ptr != '\0')
{
- modified = TRUE;
+ modified = true;
*ptr = '\0';
}
return modified;
}
- /*
+/*
** FIND_CHARACTER -- find an unquoted character in an RFC822 string
**
** Find an unquoted, non-commented character in an RFC822
@@ -304,15 +254,15 @@ find_character(string, character)
char *string;
int character;
{
- bool backslash = FALSE;
- bool quoted = FALSE;
+ bool backslash = false;
+ bool quoted = false;
int parencount = 0;
while (string != NULL && *string != '\0')
{
if (backslash)
{
- backslash = FALSE;
+ backslash = false;
if (!quoted && character == '\\' && *string == '\\')
break;
string++;
@@ -321,7 +271,7 @@ find_character(string, character)
switch (*string)
{
case '\\':
- backslash = TRUE;
+ backslash = true;
break;
case '(':
@@ -352,170 +302,142 @@ find_character(string, character)
/* Return pointer to the character */
return string;
}
- /*
-** XALLOC -- Allocate memory and bitch wildly on failure.
-**
-** THIS IS A CLUDGE. This should be made to give a proper
-** error -- but after all, what can we do?
+
+/*
+** CHECK_BODYTYPE -- check bodytype parameter
**
** Parameters:
-** sz -- size of area to allocate.
+** bodytype -- bodytype parameter
**
** Returns:
-** pointer to data region.
+** BODYTYPE_* according to parameter
**
-** Side Effects:
-** Memory is allocated.
*/
-char *
-xalloc(sz)
- register int sz;
+int
+check_bodytype(bodytype)
+ char *bodytype;
{
- register char *p;
-
- /* some systems can't handle size zero mallocs */
- if (sz <= 0)
- sz = 1;
-
- ENTER_CRITICAL();
- p = malloc((unsigned) sz);
- LEAVE_CRITICAL();
- if (p == NULL)
- {
- syserr("!Out of memory!!");
-
- /* NOTREACHED */
- exit(EX_UNAVAILABLE);
- }
- return p;
+ /* check body type for legality */
+ if (bodytype == NULL)
+ return BODYTYPE_NONE;
+ if (sm_strcasecmp(bodytype, "7BIT") == 0)
+ return BODYTYPE_7BIT;
+ if (sm_strcasecmp(bodytype, "8BITMIME") == 0)
+ return BODYTYPE_8BITMIME;
+ return BODYTYPE_ILLEGAL;
}
- /*
-** XREALLOC -- Reallocate memory and bitch wildly on failure.
-**
-** THIS IS A CLUDGE. This should be made to give a proper
-** error -- but after all, what can we do?
+
+#if _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI
+/*
+** TRUNCATE_AT_DELIM -- truncate string at a delimiter and append "..."
**
** Parameters:
-** ptr -- original area.
-** sz -- size of new area to allocate.
+** str -- string to truncate
+** len -- maximum length (including '\0') (0 for unlimited)
+** delim -- delimiter character
**
** Returns:
-** pointer to data region.
-**
-** Side Effects:
-** Memory is allocated.
+** None.
*/
-char *
-xrealloc(ptr, sz)
- void *ptr;
- size_t sz;
+void
+truncate_at_delim(str, len, delim)
+ char *str;
+ size_t len;
+ int delim;
{
- register char *p;
+ char *p;
- /* some systems can't handle size zero mallocs */
- if (sz <= 0)
- sz = 1;
+ if (str == NULL || len == 0 || strlen(str) < len)
+ return;
- ENTER_CRITICAL();
- p = realloc(ptr, (unsigned) sz);
- LEAVE_CRITICAL();
- if (p == NULL)
+ *(str + len - 1) = '\0';
+ while ((p = strrchr(str, delim)) != NULL)
{
- syserr("!Out of memory!!");
-
- /* NOTREACHED */
- exit(EX_UNAVAILABLE);
+ *p = '\0';
+ if (p - str + 4 < len)
+ {
+ *p++ = ':';
+ *p = '\0';
+ (void) sm_strlcat(str, "...", len);
+ return;
+ }
}
- return p;
+
+ /* Couldn't find a place to append "..." */
+ if (len > 3)
+ (void) sm_strlcpy(str, "...", len);
+ else
+ str[0] = '\0';
}
- /*
-** XCALLOC -- Allocate memory and bitch wildly on failure.
-**
-** THIS IS A CLUDGE. This should be made to give a proper
-** error -- but after all, what can we do?
+#endif /* _FFR_BESTMX_BETTER_TRUNCATION || _FFR_DNSMAP_MULTI */
+/*
+** XALLOC -- Allocate memory, raise an exception on error
**
** Parameters:
-** num -- number of items to allocate
-** sz -- size of new area to allocate.
+** sz -- size of area to allocate.
**
** Returns:
** pointer to data region.
**
+** Exceptions:
+** SmHeapOutOfMemory (F:sm.heap) -- cannot allocate memory
+**
** Side Effects:
** Memory is allocated.
*/
char *
-xcalloc(num, sz)
- size_t num;
- size_t sz;
+#if SM_HEAP_CHECK
+xalloc_tagged(sz, file, line)
+ register int sz;
+ char *file;
+ int line;
+#else /* SM_HEAP_CHECK */
+xalloc(sz)
+ register int sz;
+#endif /* SM_HEAP_CHECK */
{
register char *p;
/* some systems can't handle size zero mallocs */
- if (num <= 0)
- num = 1;
if (sz <= 0)
sz = 1;
- ENTER_CRITICAL();
- p = calloc((unsigned) num, (unsigned) sz);
- LEAVE_CRITICAL();
+ /* scaffolding for testing error handling code */
+ sm_xtrap_raise_x(&SmHeapOutOfMemory);
+
+ p = sm_malloc_tagged((unsigned) sz, file, line, sm_heap_group());
if (p == NULL)
{
- syserr("!Out of memory!!");
-
- /* NOTREACHED */
- exit(EX_UNAVAILABLE);
+ sm_exc_raise_x(&SmHeapOutOfMemory);
}
return p;
}
- /*
-** SM_FREE -- Free memory safely.
-**
-** Parameters:
-** ptr -- area to free
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Memory is freed.
-*/
-
-void
-sm_free(ptr)
- void *ptr;
-{
- ENTER_CRITICAL();
- free(ptr);
- LEAVE_CRITICAL();
-}
- /*
+/*
** COPYPLIST -- copy list of pointers.
**
-** This routine is the equivalent of newstr for lists of
+** This routine is the equivalent of strdup for lists of
** pointers.
**
** Parameters:
** list -- list of pointers to copy.
** Must be NULL terminated.
-** copycont -- if TRUE, copy the contents of the vector
+** copycont -- if true, copy the contents of the vector
** (which must be a string) also.
+** rpool -- resource pool from which to allocate storage,
+** or NULL
**
** Returns:
** a copy of 'list'.
-**
-** Side Effects:
-** none.
*/
char **
-copyplist(list, copycont)
+copyplist(list, copycont, rpool)
char **list;
bool copycont;
+ SM_RPOOL_T *rpool;
{
register char **vp;
register char **newvp;
@@ -525,36 +447,35 @@ copyplist(list, copycont)
vp++;
- newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
+ newvp = (char **) sm_rpool_malloc_x(rpool, (vp - list) * sizeof *vp);
memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof *vp);
if (copycont)
{
for (vp = newvp; *vp != NULL; vp++)
- *vp = newstr(*vp);
+ *vp = sm_rpool_strdup_x(rpool, *vp);
}
return newvp;
}
- /*
+/*
** COPYQUEUE -- copy address queue.
**
-** This routine is the equivalent of newstr for address queues
+** This routine is the equivalent of strdup for address queues;
** addresses marked as QS_IS_DEAD() aren't copied
**
** Parameters:
** addr -- list of address structures to copy.
+** rpool -- resource pool from which to allocate storage
**
** Returns:
** a copy of 'addr'.
-**
-** Side Effects:
-** none.
*/
ADDRESS *
-copyqueue(addr)
+copyqueue(addr, rpool)
ADDRESS *addr;
+ SM_RPOOL_T *rpool;
{
register ADDRESS *newaddr;
ADDRESS *ret;
@@ -564,7 +485,8 @@ copyqueue(addr)
{
if (!QS_IS_DEAD(addr->q_state))
{
- newaddr = (ADDRESS *) xalloc(sizeof *newaddr);
+ newaddr = (ADDRESS *) sm_rpool_malloc_x(rpool,
+ sizeof *newaddr);
STRUCTCOPY(*addr, *newaddr);
*tail = newaddr;
tail = &newaddr->q_next;
@@ -575,7 +497,7 @@ copyqueue(addr)
return ret;
}
- /*
+/*
** LOG_SENDMAIL_PID -- record sendmail pid and command line.
**
** Parameters:
@@ -585,7 +507,7 @@ copyqueue(addr)
** none.
**
** Side Effects:
-** writes pidfile.
+** writes pidfile, logs command line.
*/
void
@@ -593,8 +515,9 @@ log_sendmail_pid(e)
ENVELOPE *e;
{
long sff;
- FILE *pidf;
+ SM_FILE_T *pidf;
char pidpath[MAXPATHLEN + 1];
+ extern char *CommandLineArgs;
/* write the pid to the log file for posterity */
sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
@@ -605,26 +528,29 @@ log_sendmail_pid(e)
if (pidf == NULL)
{
sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
- pidpath, errstring(errno));
+ pidpath, sm_errstring(errno));
}
else
{
pid_t pid;
- extern char *CommandLineArgs;
pid = getpid();
/* write the process id on line 1 */
- fprintf(pidf, "%ld\n", (long) pid);
+ (void) sm_io_fprintf(pidf, SM_TIME_DEFAULT, "%ld\n",
+ (long) pid);
/* line 2 contains all command line flags */
- fprintf(pidf, "%s\n", CommandLineArgs);
+ (void) sm_io_fprintf(pidf, SM_TIME_DEFAULT, "%s\n",
+ CommandLineArgs);
/* flush and close */
- (void) fclose(pidf);
+ (void) sm_io_close(pidf, SM_TIME_DEFAULT);
}
+ if (LogLevel > 9)
+ sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs);
}
- /*
+/*
** SET_DELIVERY_MODE -- set and record the delivery mode
**
** Parameters:
@@ -635,7 +561,7 @@ log_sendmail_pid(e)
** none.
**
** Side Effects:
-** sets $&{deliveryMode} macro
+** sets {deliveryMode} macro
*/
void
@@ -645,12 +571,38 @@ set_delivery_mode(mode, e)
{
char buf[2];
- e->e_sendmode = (char)mode;
- buf[0] = (char)mode;
+ e->e_sendmode = (char) mode;
+ buf[0] = (char) mode;
+ buf[1] = '\0';
+ macdefine(&e->e_macro, A_TEMP, macid("{deliveryMode}"), buf);
+}
+/*
+** SET_OP_MODE -- set and record the op mode
+**
+** Parameters:
+** mode -- op mode
+** e -- the current envelope.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** sets {opMode} macro
+*/
+
+void
+set_op_mode(mode)
+ int mode;
+{
+ char buf[2];
+ extern ENVELOPE BlankEnvelope;
+
+ OpMode = (char) mode;
+ buf[0] = (char) mode;
buf[1] = '\0';
- define(macid("{deliveryMode}", NULL), newstr(buf), e);
+ macdefine(&BlankEnvelope.e_macro, A_TEMP, MID_OPMODE, buf);
}
- /*
+/*
** PRINTAV -- print argument vector.
**
** Parameters:
@@ -670,33 +622,14 @@ printav(av)
while (*av != NULL)
{
if (tTd(0, 44))
- dprintf("\n\t%08lx=", (u_long) *av);
+ sm_dprintf("\n\t%08lx=", (unsigned long) *av);
else
- (void) putchar(' ');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, ' ');
xputs(*av++);
}
- (void) putchar('\n');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '\n');
}
- /*
-** LOWER -- turn letter into lower case.
-**
-** Parameters:
-** c -- character to turn into lower case.
-**
-** Returns:
-** c, in lower case.
-**
-** Side Effects:
-** none.
-*/
-
-char
-lower(c)
- register int c;
-{
- return ((isascii(c) && isupper(c)) ? tolower(c) : c);
-}
- /*
+/*
** XPUTS -- put string doing control escapes.
**
** Parameters:
@@ -715,27 +648,53 @@ xputs(s)
{
register int c;
register struct metamac *mp;
- bool shiftout = FALSE;
+ bool shiftout = false;
extern struct metamac MetaMacros[];
+ static SM_DEBUG_T DebugANSI = SM_DEBUG_INITIALIZER("ANSI",
+ "@(#)$Debug: ANSI - enable reverse video in debug output $");
+
+ /*
+ ** TermEscape is set here, rather than in main(),
+ ** because ANSI mode can be turned on or off at any time
+ ** if we are in -bt rule testing mode.
+ */
+
+ if (sm_debug_unknown(&DebugANSI))
+ {
+ if (sm_debug_active(&DebugANSI, 1))
+ {
+ TermEscape.te_rv_on = "\033[7m";
+ TermEscape.te_rv_off = "\033[0m";
+ }
+ else
+ {
+ TermEscape.te_rv_on = "";
+ TermEscape.te_rv_off = "";
+ }
+ }
if (s == NULL)
{
- printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s<null>%s",
+ TermEscape.te_rv_on, TermEscape.te_rv_off);
return;
}
while ((c = (*s++ & 0377)) != '\0')
{
if (shiftout)
{
- printf("%s", TermEscape.te_rv_off);
- shiftout = FALSE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s",
+ TermEscape.te_rv_off);
+ shiftout = false;
}
if (!isascii(c))
{
if (c == MATCHREPL)
{
- printf("%s$", TermEscape.te_rv_on);
- shiftout = TRUE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s$",
+ TermEscape.te_rv_on);
+ shiftout = true;
if (*s == '\0')
continue;
c = *s++ & 0377;
@@ -743,50 +702,70 @@ xputs(s)
}
if (c == MACROEXPAND || c == MACRODEXPAND)
{
- printf("%s$", TermEscape.te_rv_on);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%s$",
+ TermEscape.te_rv_on);
if (c == MACRODEXPAND)
- (void) putchar('&');
- shiftout = TRUE;
+ (void) sm_io_putc(smioout,
+ SM_TIME_DEFAULT, '&');
+ shiftout = true;
if (*s == '\0')
continue;
if (strchr("=~&?", *s) != NULL)
- (void) putchar(*s++);
+ (void) sm_io_putc(smioout,
+ SM_TIME_DEFAULT,
+ *s++);
if (bitset(0200, *s))
- printf("{%s}", macname(bitidx(*s++)));
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "{%s}",
+ macname(bitidx(*s++)));
else
- printf("%c", *s++);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%c",
+ *s++);
continue;
}
for (mp = MetaMacros; mp->metaname != '\0'; mp++)
{
- if ((mp->metaval & 0377) == c)
+ if (bitidx(mp->metaval) == c)
{
- printf("%s$%c",
- TermEscape.te_rv_on,
- mp->metaname);
- shiftout = TRUE;
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%s$%c",
+ TermEscape.te_rv_on,
+ mp->metaname);
+ shiftout = true;
break;
}
}
if (c == MATCHCLASS || c == MATCHNCLASS)
{
if (bitset(0200, *s))
- printf("{%s}", macname(*s++ & 0377));
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "{%s}",
+ macname(bitidx(*s++)));
else if (*s != '\0')
- printf("%c", *s++);
+ (void) sm_io_fprintf(smioout,
+ SM_TIME_DEFAULT,
+ "%c",
+ *s++);
}
if (mp->metaname != '\0')
continue;
/* unrecognized meta character */
- printf("%sM-", TermEscape.te_rv_on);
- shiftout = TRUE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%sM-",
+ TermEscape.te_rv_on);
+ shiftout = true;
c &= 0177;
}
printchar:
if (isprint(c))
{
- (void) putchar(c);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
continue;
}
@@ -807,25 +786,27 @@ xputs(s)
}
if (!shiftout)
{
- printf("%s", TermEscape.te_rv_on);
- shiftout = TRUE;
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s",
+ TermEscape.te_rv_on);
+ shiftout = true;
}
if (isprint(c))
{
- (void) putchar('\\');
- (void) putchar(c);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '\\');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c);
}
else
{
- (void) putchar('^');
- (void) putchar(c ^ 0100);
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, '^');
+ (void) sm_io_putc(smioout, SM_TIME_DEFAULT, c ^ 0100);
}
}
if (shiftout)
- printf("%s", TermEscape.te_rv_off);
- (void) fflush(stdout);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s",
+ TermEscape.te_rv_off);
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
}
- /*
+/*
** MAKELOWER -- Translate a line into lower case
**
** Parameters:
@@ -851,60 +832,7 @@ makelower(p)
if (isascii(c) && isupper(c))
*p = tolower(c);
}
- /*
-** BUILDFNAME -- build full name from gecos style entry.
-**
-** This routine interprets the strange entry that would appear
-** in the GECOS field of the password file.
-**
-** Parameters:
-** p -- name to build.
-** user -- the login name of this user (for &).
-** buf -- place to put the result.
-** buflen -- length of buf.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-void
-buildfname(gecos, user, buf, buflen)
- register char *gecos;
- char *user;
- char *buf;
- int buflen;
-{
- register char *p;
- register char *bp = buf;
-
- if (*gecos == '*')
- gecos++;
-
- /* copy gecos, interpolating & to be full name */
- for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
- {
- if (bp >= &buf[buflen - 1])
- {
- /* buffer overflow -- just use login name */
- snprintf(buf, buflen, "%s", user);
- return;
- }
- if (*p == '&')
- {
- /* interpolate full name */
- snprintf(bp, buflen - (bp - buf), "%s", user);
- *bp = toupper(*bp);
- bp += strlen(bp);
- }
- else
- *bp++ = *p;
- }
- *bp = '\0';
-}
- /*
+/*
** FIXCRLF -- fix <CR><LF> in line.
**
** Looks for the <CR><LF> combination and turns it into the
@@ -939,7 +867,7 @@ fixcrlf(line, stripnl)
*p++ = '\n';
*p = '\0';
}
- /*
+/*
** PUTLINE -- put a line like fputs obeying SMTP conventions
**
** This routine always guarantees outputing a newline (or CRLF,
@@ -953,7 +881,7 @@ fixcrlf(line, stripnl)
** none
**
** Side Effects:
-** output of l to fp.
+** output of l to mci->mci_out.
*/
void
@@ -963,7 +891,7 @@ putline(l, mci)
{
putxline(l, strlen(l), mci, PXLF_MAPFROM);
}
- /*
+/*
** PUTXLINE -- putline with flags bits.
**
** This routine always guarantees outputing a newline (or CRLF,
@@ -982,7 +910,7 @@ putline(l, mci)
** none
**
** Side Effects:
-** output of l to fp.
+** output of l to mci->mci_out.
*/
void
@@ -992,7 +920,7 @@ putxline(l, len, mci, pxflags)
register MCI *mci;
int pxflags;
{
- bool dead = FALSE;
+ bool dead = false;
register char *p, *end;
int slop = 0;
@@ -1016,7 +944,8 @@ putxline(l, len, mci, pxflags)
p = end;
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> ", (int) getpid());
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> ", (int) CurrentPid);
/* check for line overflow */
while (mci->mci_mailer->m_linelimit > 0 &&
@@ -1028,71 +957,82 @@ putxline(l, len, mci, pxflags)
if (l[0] == '.' && slop == 0 &&
bitnset(M_XDOT, mci->mci_mailer->m_flags))
{
- if (putc('.', mci->mci_out) == EOF)
- dead = TRUE;
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ '.') == SM_IO_EOF)
+ dead = true;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
- (void) putc('.', TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT, '.');
}
else if (l[0] == 'F' && slop == 0 &&
bitset(PXLF_MAPFROM, pxflags) &&
strncmp(l, "From ", 5) == 0 &&
bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
{
- if (putc('>', mci->mci_out) == EOF)
- dead = TRUE;
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ '>') == SM_IO_EOF)
+ dead = true;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
- (void) putc('>', TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ '>');
}
if (dead)
break;
while (l < q)
{
- if (putc((unsigned char) *l++, mci->mci_out) ==
- EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ (unsigned char) *l++) == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
if (dead)
break;
- if (putc('!', mci->mci_out) == EOF ||
- fputs(mci->mci_mailer->m_eol,
- mci->mci_out) == EOF ||
- putc(' ', mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '!') ==
+ SM_IO_EOF ||
+ sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol) ==
+ SM_IO_EOF ||
+ sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, ' ') ==
+ SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
{
for (l = l_base; l < q; l++)
- (void) putc((unsigned char)*l,
- TrafficLogFile);
- fprintf(TrafficLogFile, "!\n%05d >>> ",
- (int) getpid());
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char)*l);
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "!\n%05d >>> ",
+ (int) CurrentPid);
}
slop = 1;
}
@@ -1104,107 +1044,125 @@ putxline(l, len, mci, pxflags)
if (l[0] == '.' && slop == 0 &&
bitnset(M_XDOT, mci->mci_mailer->m_flags))
{
- if (putc('.', mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') ==
+ SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
- (void) putc('.', TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT, '.');
}
else if (l[0] == 'F' && slop == 0 &&
bitset(PXLF_MAPFROM, pxflags) &&
strncmp(l, "From ", 5) == 0 &&
bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
{
- if (putc('>', mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') ==
+ SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (TrafficLogFile != NULL)
- (void) putc('>', TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT, '>');
}
for ( ; l < p; ++l)
{
if (TrafficLogFile != NULL)
- (void) putc((unsigned char)*l, TrafficLogFile);
- if (putc((unsigned char) *l, mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ (unsigned char)*l);
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ (unsigned char) *l) == SM_IO_EOF)
{
- dead = TRUE;
+ dead = true;
break;
}
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
}
if (dead)
break;
if (TrafficLogFile != NULL)
- (void) putc('\n', TrafficLogFile);
- if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF)
+ (void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT,
+ '\n');
+ if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol) == SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
if (l < end && *l == '\n')
{
if (*++l != ' ' && *l != '\t' && *l != '\0' &&
bitset(PXLF_HEADER, pxflags))
{
- if (putc(' ', mci->mci_out) == EOF)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ ' ') == SM_IO_EOF)
break;
else
{
/* record progress for DATA timeout */
- DataProgress = TRUE;
+ DataProgress = true;
}
+
if (TrafficLogFile != NULL)
- (void) putc(' ', TrafficLogFile);
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT, ' ');
}
}
+
+ /* record progress for DATA timeout */
+ DataProgress = true;
} while (l < end);
}
- /*
+/*
** XUNLINK -- unlink a file, doing logging as appropriate.
**
** Parameters:
** f -- name of file to unlink.
**
** Returns:
-** none.
+** return value of unlink()
**
** Side Effects:
** f is unlinked.
*/
-void
+int
xunlink(f)
char *f;
{
register int i;
+ int save_errno;
if (LogLevel > 98)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "unlink %s",
- f);
+ sm_syslog(LOG_DEBUG, CurEnv->e_id, "unlink %s", f);
i = unlink(f);
+ save_errno = errno;
if (i < 0 && LogLevel > 97)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "%s: unlink-fail %d",
+ sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s: unlink-fail %d",
f, errno);
+ if (i >= 0)
+ SYNC_DIR(f, false);
+ errno = save_errno;
+ return i;
}
- /*
+/*
** SFGETS -- "safe" fgets -- times out and ignores random interrupts.
**
** Parameters:
@@ -1215,86 +1173,85 @@ xunlink(f)
** during -- what we are trying to read (for error messages).
**
** Returns:
-** NULL on error (including timeout). This will also leave
+** NULL on error (including timeout). This may also leave
** buf containing a null string.
** buf otherwise.
-**
-** Side Effects:
-** none.
*/
-static jmp_buf CtxReadTimeout;
-
char *
sfgets(buf, siz, fp, timeout, during)
char *buf;
int siz;
- FILE *fp;
+ SM_FILE_T *fp;
time_t timeout;
char *during;
{
- register EVENT *ev = NULL;
register char *p;
int save_errno;
+ int io_timeout;
+
+ SM_REQUIRE(siz > 0);
+ SM_REQUIRE(buf != NULL);
if (fp == NULL)
{
buf[0] = '\0';
+ errno = EBADF;
return NULL;
}
- /* set the timeout */
- if (timeout != 0)
+ /* try to read */
+ p = NULL;
+ errno = 0;
+
+ /* convert the timeout to sm_io notation */
+ io_timeout = (timeout <= 0) ? SM_TIME_DEFAULT : timeout * 1000;
+ while (!sm_io_eof(fp) && !sm_io_error(fp))
{
- if (setjmp(CtxReadTimeout) != 0)
+ errno = 0;
+ p = sm_io_fgets(fp, io_timeout, buf, siz);
+ if (p == NULL && errno == EAGAIN)
{
+ /* The sm_io_fgets() call timedout */
if (LogLevel > 1)
sm_syslog(LOG_NOTICE, CurEnv->e_id,
"timeout waiting for input from %.100s during %s",
- CurHostName ? CurHostName : "local",
+ CURHOSTNAME,
during);
buf[0] = '\0';
#if XDEBUG
checkfd012(during);
#endif /* XDEBUG */
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n",
- (int) getpid());
- errno = 0;
+ (void) sm_io_fprintf(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ "%05d <<< [TIMEOUT]\n",
+ (int) CurrentPid);
+ errno = ETIMEDOUT;
return NULL;
}
- ev = setevent(timeout, readtimeout, 0);
- }
-
- /* try to read */
- p = NULL;
- errno = 0;
- while (!feof(fp) && !ferror(fp))
- {
- errno = 0;
- p = fgets(buf, siz, fp);
if (p != NULL || errno != EINTR)
break;
- clearerr(fp);
+ (void) sm_io_clearerr(fp);
}
save_errno = errno;
- /* clear the event if it has not sprung */
- clrevent(ev);
-
/* clean up the books and exit */
LineNumber++;
if (p == NULL)
{
buf[0] = '\0';
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid());
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d <<< [EOF]\n",
+ (int) CurrentPid);
errno = save_errno;
return NULL;
}
if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf);
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d <<< %s", (int) CurrentPid, buf);
if (SevenBitInput)
{
for (p = buf; *p != '\0'; p++)
@@ -1306,30 +1263,15 @@ sfgets(buf, siz, fp, timeout, during)
{
if (bitset(0200, *p))
{
- HasEightBits = TRUE;
+ HasEightBits = true;
break;
}
}
}
return buf;
}
-
-/* ARGSUSED */
-static void
-readtimeout(timeout)
- time_t timeout;
-{
- /*
- ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
- ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
- ** DOING.
- */
-
- errno = ETIMEDOUT;
- longjmp(CtxReadTimeout, 1);
-}
- /*
-** FGETFOLDED -- like fgets, but know about folded lines.
+/*
+** FGETFOLDED -- like fgets, but knows about folded lines.
**
** Parameters:
** buf -- place to put result.
@@ -1337,9 +1279,9 @@ readtimeout(timeout)
** f -- file to read from.
**
** Returns:
-** input line(s) on success, NULL on error or EOF.
+** input line(s) on success, NULL on error or SM_IO_EOF.
** This will normally be buf -- unless the line is too
-** long, when it will be xalloc()ed.
+** long, when it will be sm_malloc_x()ed.
**
** Side Effects:
** buf gets lines from f, with continuation lines (lines
@@ -1351,22 +1293,32 @@ char *
fgetfolded(buf, n, f)
char *buf;
register int n;
- FILE *f;
+ SM_FILE_T *f;
{
register char *p = buf;
char *bp = buf;
register int i;
+ SM_REQUIRE(n > 0);
+ SM_REQUIRE(buf != NULL);
+ if (f == NULL)
+ {
+ buf[0] = '\0';
+ errno = EBADF;
+ return NULL;
+ }
+
n--;
- while ((i = getc(f)) != EOF)
+ while ((i = sm_io_getc(f, SM_TIME_DEFAULT)) != SM_IO_EOF)
{
if (i == '\r')
{
- i = getc(f);
+ i = sm_io_getc(f, SM_TIME_DEFAULT);
if (i != '\n')
{
- if (i != EOF)
- (void) ungetc(i, f);
+ if (i != SM_IO_EOF)
+ (void) sm_io_ungetc(f, SM_TIME_DEFAULT,
+ i);
i = '\r';
}
}
@@ -1381,7 +1333,7 @@ fgetfolded(buf, n, f)
nn *= 2;
else
nn += MEMCHUNKSIZE;
- nbp = xalloc(nn);
+ nbp = sm_malloc_x(nn);
memmove(nbp, bp, p - bp);
p = &nbp[p - bp];
if (bp != buf)
@@ -1393,9 +1345,9 @@ fgetfolded(buf, n, f)
if (i == '\n')
{
LineNumber++;
- i = getc(f);
- if (i != EOF)
- (void) ungetc(i, f);
+ i = sm_io_getc(f, SM_TIME_DEFAULT);
+ if (i != SM_IO_EOF)
+ (void) sm_io_ungetc(f, SM_TIME_DEFAULT, i);
if (i != ' ' && i != '\t')
break;
}
@@ -1407,7 +1359,7 @@ fgetfolded(buf, n, f)
*p = '\0';
return bp;
}
- /*
+/*
** CURTIME -- return current time.
**
** Parameters:
@@ -1415,9 +1367,6 @@ fgetfolded(buf, n, f)
**
** Returns:
** the current time.
-**
-** Side Effects:
-** none.
*/
time_t
@@ -1428,20 +1377,17 @@ curtime()
(void) time(&t);
return t;
}
- /*
+/*
** ATOBOOL -- convert a string representation to boolean.
**
-** Defaults to "TRUE"
+** Defaults to false
**
** Parameters:
-** s -- string to convert. Takes "tTyY" as true,
+** s -- string to convert. Takes "tTyY", empty, and NULL as true,
** others as false.
**
** Returns:
** A boolean representation of the string.
-**
-** Side Effects:
-** none.
*/
bool
@@ -1449,10 +1395,10 @@ atobool(s)
register char *s;
{
if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
- /*
+/*
** ATOOCT -- convert a string representation to octal.
**
** Parameters:
@@ -1461,9 +1407,6 @@ atobool(s)
** Returns:
** An integer representing the string interpreted as an
** octal number.
-**
-** Side Effects:
-** none.
*/
int
@@ -1476,18 +1419,15 @@ atooct(s)
i = (i << 3) | (*s++ - '0');
return i;
}
- /*
+/*
** BITINTERSECT -- tell if two bitmaps intersect
**
** Parameters:
** a, b -- the bitmaps in question
**
** Returns:
-** TRUE if they have a non-null intersection
-** FALSE otherwise
-**
-** Side Effects:
-** none.
+** true if they have a non-null intersection
+** false otherwise
*/
bool
@@ -1500,22 +1440,19 @@ bitintersect(a, b)
for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
{
if ((a[i] & b[i]) != 0)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- /*
+/*
** BITZEROP -- tell if a bitmap is all zero
**
** Parameters:
** map -- the bit map to check
**
** Returns:
-** TRUE if map is all zero.
-** FALSE if there are any bits set in map.
-**
-** Side Effects:
-** none.
+** true if map is all zero.
+** false if there are any bits set in map.
*/
bool
@@ -1527,24 +1464,26 @@ bitzerop(map)
for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
{
if (map[i] != 0)
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
- /*
+/*
** STRCONTAINEDIN -- tell if one string is contained in another
**
** Parameters:
+** icase -- ignore case?
** a -- possible substring.
** b -- possible superstring.
**
** Returns:
-** TRUE if a is contained in b.
-** FALSE otherwise.
+** true if a is contained in b (case insensitive).
+** false otherwise.
*/
bool
-strcontainedin(a, b)
+strcontainedin(icase, a, b)
+ bool icase;
register char *a;
register char *b;
{
@@ -1555,18 +1494,29 @@ strcontainedin(a, b)
la = strlen(a);
lb = strlen(b);
c = *a;
- if (isascii(c) && isupper(c))
+ if (icase && isascii(c) && isupper(c))
c = tolower(c);
for (; lb-- >= la; b++)
{
- if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
- continue;
- if (strncasecmp(a, b, la) == 0)
- return TRUE;
+ if (icase)
+ {
+ if (*b != c &&
+ isascii(*b) && isupper(*b) && tolower(*b) != c)
+ continue;
+ if (sm_strncasecmp(a, b, la) == 0)
+ return true;
+ }
+ else
+ {
+ if (*b != c)
+ continue;
+ if (strncmp(a, b, la) == 0)
+ return true;
+ }
}
- return FALSE;
+ return false;
}
- /*
+/*
** CHECKFD012 -- check low numbered file descriptors
**
** File descriptors 0, 1, and 2 should be open at all times.
@@ -1590,7 +1540,7 @@ checkfd012(where)
fill_fd(i, where);
#endif /* XDEBUG */
}
- /*
+/*
** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
**
** Parameters:
@@ -1612,11 +1562,11 @@ checkfdopen(fd, where)
if (fstat(fd, &st) < 0 && errno == EBADF)
{
syserr("checkfdopen(%d): %s not open as expected!", fd, where);
- printopenfds(TRUE);
+ printopenfds(true);
}
#endif /* XDEBUG */
}
- /*
+/*
** CHECKFDS -- check for new or missing file descriptors
**
** Parameters:
@@ -1635,7 +1585,7 @@ checkfds(where)
{
int maxfd;
register int fd;
- bool printhdr = TRUE;
+ bool printhdr = true;
int save_errno = errno;
static BITMAP256 baseline;
extern int DtableSize;
@@ -1670,13 +1620,13 @@ checkfds(where)
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"%s: changed fds:",
where);
- printhdr = FALSE;
+ printhdr = false;
}
- dumpfd(fd, TRUE, TRUE);
+ dumpfd(fd, true, true);
}
errno = save_errno;
}
- /*
+/*
** PRINTOPENFDS -- print the open file descriptors (for debugging)
**
** Parameters:
@@ -1699,9 +1649,9 @@ printopenfds(logit)
extern int DtableSize;
for (fd = 0; fd < DtableSize; fd++)
- dumpfd(fd, FALSE, logit);
+ dumpfd(fd, false, logit);
}
- /*
+/*
** DUMPFD -- dump a file descriptor
**
** Parameters:
@@ -1709,6 +1659,9 @@ printopenfds(logit)
** printclosed -- if set, print a notification even if
** it is closed; otherwise print nothing.
** logit -- if set, send output to syslog instead of stdout.
+**
+** Returns:
+** none.
*/
void
@@ -1732,7 +1685,7 @@ dumpfd(fd, printclosed, logit)
char buf[200];
p = buf;
- snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
p += strlen(p);
if (
@@ -1745,13 +1698,14 @@ dumpfd(fd, printclosed, logit)
{
if (errno != EBADF)
{
- snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)",
- errstring(errno));
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "CANNOT STAT (%s)",
+ sm_errstring(errno));
goto printit;
}
else if (printclosed)
{
- snprintf(p, SPACELEFT(buf, p), "CLOSED");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "CLOSED");
goto printit;
}
return;
@@ -1760,23 +1714,24 @@ dumpfd(fd, printclosed, logit)
i = fcntl(fd, F_GETFL, NULL);
if (i != -1)
{
- snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
p += strlen(p);
}
- snprintf(p, SPACELEFT(buf, p), "mode=%o: ", (int) st.st_mode);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ",
+ (int) st.st_mode);
p += strlen(p);
switch (st.st_mode & S_IFMT)
{
#ifdef S_IFSOCK
case S_IFSOCK:
- snprintf(p, SPACELEFT(buf, p), "SOCK ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "SOCK ");
p += strlen(p);
memset(&sa, '\0', sizeof sa);
slen = sizeof sa;
if (getsockname(fd, &sa.sa, &slen) < 0)
- snprintf(p, SPACELEFT(buf, p), "(%s)",
- errstring(errno));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
+ sm_errstring(errno));
else
{
hp = hostnamebyanyaddr(&sa);
@@ -1787,23 +1742,25 @@ dumpfd(fd, printclosed, logit)
}
# if NETINET
else if (sa.sa.sa_family == AF_INET)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin.sin_port));
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s/%d", hp, ntohs(sa.sin.sin_port));
# endif /* NETINET */
# if NETINET6
else if (sa.sa.sa_family == AF_INET6)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin6.sin6_port));
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s/%d", hp, ntohs(sa.sin6.sin6_port));
# endif /* NETINET6 */
else
- snprintf(p, SPACELEFT(buf, p), "%s", hp);
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s", hp);
}
p += strlen(p);
- snprintf(p, SPACELEFT(buf, p), "->");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "->");
p += strlen(p);
slen = sizeof sa;
if (getpeername(fd, &sa.sa, &slen) < 0)
- snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
+ sm_errstring(errno));
else
{
hp = hostnamebyanyaddr(&sa);
@@ -1814,75 +1771,65 @@ dumpfd(fd, printclosed, logit)
}
# if NETINET
else if (sa.sa.sa_family == AF_INET)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin.sin_port));
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s/%d", hp, ntohs(sa.sin.sin_port));
# endif /* NETINET */
# if NETINET6
else if (sa.sa.sa_family == AF_INET6)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin6.sin6_port));
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s/%d", hp, ntohs(sa.sin6.sin6_port));
# endif /* NETINET6 */
else
- snprintf(p, SPACELEFT(buf, p), "%s", hp);
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "%s", hp);
}
break;
#endif /* S_IFSOCK */
case S_IFCHR:
- snprintf(p, SPACELEFT(buf, p), "CHR: ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "CHR: ");
p += strlen(p);
goto defprint;
+#ifdef S_IFBLK
case S_IFBLK:
- snprintf(p, SPACELEFT(buf, p), "BLK: ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: ");
p += strlen(p);
goto defprint;
+#endif /* S_IFBLK */
#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
case S_IFIFO:
- snprintf(p, SPACELEFT(buf, p), "FIFO: ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: ");
p += strlen(p);
goto defprint;
#endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */
#ifdef S_IFDIR
case S_IFDIR:
- snprintf(p, SPACELEFT(buf, p), "DIR: ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: ");
p += strlen(p);
goto defprint;
#endif /* S_IFDIR */
#ifdef S_IFLNK
case S_IFLNK:
- snprintf(p, SPACELEFT(buf, p), "LNK: ");
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: ");
p += strlen(p);
goto defprint;
#endif /* S_IFLNK */
default:
defprint:
- /*CONSTCOND*/
- if (sizeof st.st_ino > sizeof (long))
- snprintf(p, SPACELEFT(buf, p),
- "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ",
- major(st.st_dev), minor(st.st_dev),
- quad_to_string(st.st_ino),
- (int) st.st_nlink, (int) st.st_uid,
- (int) st.st_gid);
- else
- snprintf(p, SPACELEFT(buf, p),
- "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ",
- major(st.st_dev), minor(st.st_dev),
- (unsigned long) st.st_ino,
- (int) st.st_nlink, (int) st.st_uid,
- (int) st.st_gid);
- /*CONSTCOND*/
- if (sizeof st.st_size > sizeof (long))
- snprintf(p, SPACELEFT(buf, p), "size=%s",
- quad_to_string(st.st_size));
- else
- snprintf(p, SPACELEFT(buf, p), "size=%lu",
- (unsigned long) st.st_size);
+ (void) sm_snprintf(p, SPACELEFT(buf, p),
+ "dev=%d/%d, ino=%llu, nlink=%d, u/gid=%d/%d, ",
+ major(st.st_dev), minor(st.st_dev),
+ (ULONGLONG_T) st.st_ino,
+ (int) st.st_nlink, (int) st.st_uid,
+ (int) st.st_gid);
+ p += strlen(p);
+ (void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu",
+ (ULONGLONG_T) st.st_size);
break;
}
@@ -1891,16 +1838,16 @@ printit:
sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
"%.800s", buf);
else
- printf("%s\n", buf);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", buf);
}
- /*
+/*
** SHORTEN_HOSTNAME -- strip local domain information off of hostname.
**
** Parameters:
** host -- the host to shorten (stripped in place).
**
** Returns:
-** place where string was trunacted, NULL if not truncated.
+** place where string was truncated, NULL if not truncated.
*/
char *
@@ -1910,14 +1857,15 @@ shorten_hostname(host)
register char *p;
char *mydom;
int i;
- bool canon = FALSE;
+ bool canon = false;
/* strip off final dot */
- p = &host[strlen(host) - 1];
+ i = strlen(host);
+ p = &host[(i == 0) ? 0 : i - 1];
if (*p == '.')
{
*p = '\0';
- canon = TRUE;
+ canon = true;
}
/* see if there is any domain at all -- if not, we are done */
@@ -1930,15 +1878,16 @@ shorten_hostname(host)
if (mydom == NULL)
mydom = "";
i = strlen(++p);
- if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 &&
- (mydom[i] == '.' || mydom[i] == '\0'))
+ if ((canon ? sm_strcasecmp(p, mydom)
+ : sm_strncasecmp(p, mydom, i)) == 0 &&
+ (mydom[i] == '.' || mydom[i] == '\0'))
{
*--p = '\0';
return p;
}
return NULL;
}
- /*
+/*
** PROG_OPEN -- open a program for reading
**
** Parameters:
@@ -1959,6 +1908,8 @@ prog_open(argv, pfd, e)
pid_t pid;
int i;
int save_errno;
+ int sff;
+ int ret;
int fdv[2];
char *p, *q;
char buf[MAXLINE + 1];
@@ -1985,13 +1936,22 @@ prog_open(argv, pfd, e)
return pid;
}
- /* child -- close stdin */
- (void) close(0);
-
/* Reset global flags */
RestartRequest = NULL;
+ RestartWorkGroup = false;
ShutdownRequest = NULL;
PendingSignal = 0;
+ CurrentPid = getpid();
+
+ /*
+ ** Initialize exception stack and default exception
+ ** handler for child process.
+ */
+
+ sm_exc_newthread(fatal_error);
+
+ /* child -- close stdin */
+ (void) close(0);
/* stdout goes back to parent */
(void) close(fdv[0]);
@@ -2007,7 +1967,7 @@ prog_open(argv, pfd, e)
{
int xfd;
- xfd = fileno(e->e_xfp);
+ xfd = sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL);
if (xfd >= 0 && dup2(xfd, 2) < 0)
{
syserr("%s: cannot dup2 for stderr", argv[0]);
@@ -2017,7 +1977,7 @@ prog_open(argv, pfd, e)
/* this process has no right to the queue file */
if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
+ (void) close(sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL));
/* chroot to the program mailer directory, if defined */
if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL)
@@ -2037,6 +1997,7 @@ prog_open(argv, pfd, e)
/* run as default user */
endpwent();
+ sm_mbdb_terminate();
if (setgid(DefGid) < 0 && geteuid() == 0)
{
syserr("prog_open: setgid(%ld) failed", (long) DefGid);
@@ -2071,6 +2032,20 @@ prog_open(argv, pfd, e)
(void) chdir("/");
}
+ /* Check safety of program to be run */
+ sff = SFF_ROOTOK|SFF_EXECOK;
+ if (!bitnset(DBS_RUNWRITABLEPROGRAM, DontBlameSendmail))
+ sff |= SFF_NOGWFILES|SFF_NOWWFILES;
+ if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, DontBlameSendmail))
+ sff |= SFF_NOPATHCHECK;
+ else
+ sff |= SFF_SAFEDIRPATH;
+ ret = safefile(argv[0], DefUid, DefGid, DefUser, sff, 0, NULL);
+ if (ret != 0)
+ sm_syslog(LOG_INFO, e->e_id,
+ "Warning: prog_open: program %s unsafe: %s",
+ argv[0], sm_errstring(ret));
+
/* arrange for all the files to be closed */
for (i = 3; i < DtableSize; i++)
{
@@ -2091,7 +2066,7 @@ prog_open(argv, pfd, e)
_exit(EX_CONFIG);
return -1; /* avoid compiler warning on IRIX */
}
- /*
+/*
** GET_COLUMN -- look up a Column in a line buffer
**
** Parameters:
@@ -2120,23 +2095,23 @@ get_column(line, col, delim, buf, buflen)
int i;
char delimbuf[4];
- if ((char)delim == '\0')
- (void) strlcpy(delimbuf, "\n\t ", sizeof delimbuf);
+ if ((char) delim == '\0')
+ (void) sm_strlcpy(delimbuf, "\n\t ", sizeof delimbuf);
else
{
- delimbuf[0] = (char)delim;
+ delimbuf[0] = (char) delim;
delimbuf[1] = '\0';
}
p = line;
if (*p == '\0')
return NULL; /* line empty */
- if (*p == (char)delim && col == 0)
+ if (*p == (char) delim && col == 0)
return NULL; /* first column empty */
begin = line;
- if (col == 0 && (char)delim == '\0')
+ if (col == 0 && (char) delim == '\0')
{
while (*begin != '\0' && isascii(*begin) && isspace(*begin))
begin++;
@@ -2147,7 +2122,7 @@ get_column(line, col, delim, buf, buflen)
if ((begin = strpbrk(begin, delimbuf)) == NULL)
return NULL; /* no such column */
begin++;
- if ((char)delim == '\0')
+ if ((char) delim == '\0')
{
while (*begin != '\0' && isascii(*begin) && isspace(*begin))
begin++;
@@ -2161,10 +2136,10 @@ get_column(line, col, delim, buf, buflen)
i = end - begin;
if (i >= buflen)
i = buflen - 1;
- (void) strlcpy(buf, begin, i + 1);
+ (void) sm_strlcpy(buf, begin, i + 1);
return buf;
}
- /*
+/*
** CLEANSTRCPY -- copy string keeping out bogus characters
**
** Parameters:
@@ -2183,7 +2158,7 @@ cleanstrcpy(t, f, l)
int l;
{
/* check for newlines and log if necessary */
- (void) denlstring(f, TRUE, TRUE);
+ (void) denlstring(f, true, true);
if (l <= 0)
syserr("!cleanstrcpy: length == 0");
@@ -2201,8 +2176,7 @@ cleanstrcpy(t, f, l)
}
*t = '\0';
}
-
- /*
+/*
** DENLSTRING -- convert newlines in a string to spaces
**
** Parameters:
@@ -2237,12 +2211,14 @@ denlstring(s, strict, logattacks)
if (bl < l)
{
/* allocate more space */
+ char *nbp = sm_pmalloc_x(l);
+
if (bp != NULL)
sm_free(bp);
- bp = xalloc(l);
+ bp = nbp;
bl = l;
}
- (void) strlcpy(bp, s, l);
+ (void) sm_strlcpy(bp, s, l);
for (p = bp; (p = strchr(p, '\n')) != NULL; )
*p++ = ' ';
@@ -2256,7 +2232,100 @@ denlstring(s, strict, logattacks)
return bp;
}
- /*
+/*
+** STR2PRT -- convert "unprintable" characters in a string to \oct
+**
+** Parameters:
+** s -- string to convert
+**
+** Returns:
+** converted string.
+** This is a static local buffer, string must be copied
+** before this function is called again!
+*/
+
+char *
+str2prt(s)
+ char *s;
+{
+ int l;
+ char c, *h;
+ bool ok;
+ static int len = 0;
+ static char *buf = NULL;
+
+ if (s == NULL)
+ return NULL;
+ ok = true;
+ for (h = s, l = 1; *h != '\0'; h++, l++)
+ {
+ if (*h == '\\')
+ {
+ ++l;
+ ok = false;
+ }
+ else if (!(isascii(*h) && isprint(*h)))
+ {
+ l += 3;
+ ok = false;
+ }
+ }
+ if (ok)
+ return s;
+ if (l > len)
+ {
+ char *nbuf = sm_pmalloc_x(l);
+
+ if (buf != NULL)
+ sm_free(buf);
+ len = l;
+ buf = nbuf;
+ }
+ for (h = buf; *s != '\0' && l > 0; s++, l--)
+ {
+ c = *s;
+ if (isascii(c) && isprint(c) && c != '\\')
+ {
+ *h++ = c;
+ }
+ else
+ {
+ *h++ = '\\';
+ --l;
+ switch (c)
+ {
+ case '\\':
+ *h++ = '\\';
+ break;
+ case '\t':
+ *h++ = 't';
+ break;
+ case '\n':
+ *h++ = 'n';
+ break;
+ case '\r':
+ *h++ = 'r';
+ break;
+ default:
+ (void) sm_snprintf(h, l, "%03o", (int) c);
+
+ /*
+ ** XXX since l is unsigned this may
+ ** wrap around if the calculation is screwed
+ ** up...
+ */
+
+ l -= 2;
+ h += 3;
+ break;
+ }
+ }
+ }
+ *h = '\0';
+ buf[len - 1] = '\0';
+ return buf;
+}
+/*
** PATH_IS_DIR -- check to see if file exists and is a directory.
**
** There are some additional checks for security violations in
@@ -2268,8 +2337,8 @@ denlstring(s, strict, logattacks)
** createflag -- if set, create directory if needed.
**
** Returns:
-** TRUE -- if the indicated pathname is a directory
-** FALSE -- otherwise
+** true -- if the indicated pathname is a directory
+** false -- otherwise
*/
int
@@ -2286,46 +2355,63 @@ path_is_dir(pathname, createflag)
#endif /* HASLSTAT */
{
if (errno != ENOENT || !createflag)
- return FALSE;
+ return false;
if (mkdir(pathname, 0755) < 0)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
if (!S_ISDIR(statbuf.st_mode))
{
errno = ENOTDIR;
- return FALSE;
+ return false;
}
/* security: don't allow writable directories */
if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
{
errno = EACCES;
- return FALSE;
+ return false;
}
-
- return TRUE;
+ return true;
}
- /*
+/*
** PROC_LIST_ADD -- add process id to list of our children
**
** Parameters:
** pid -- pid to add to list.
** task -- task of pid.
** type -- type of process.
+** count -- number of processes.
+** other -- other information for this type.
**
** Returns:
** none
+**
+** Side Effects:
+** May increase CurChildren. May grow ProcList.
*/
-static struct procs *volatile ProcListVec = NULL;
-static int ProcListSize = 0;
+typedef struct procs PROCS_T;
+
+struct procs
+{
+ pid_t proc_pid;
+ char *proc_task;
+ int proc_type;
+ int proc_count;
+ int proc_other;
+};
+
+static PROCS_T *volatile ProcListVec = NULL;
+static int ProcListSize = 0;
void
-proc_list_add(pid, task, type)
+proc_list_add(pid, task, type, count, other)
pid_t pid;
char *task;
int type;
+ int count;
+ int other;
{
int i;
@@ -2349,16 +2435,19 @@ proc_list_add(pid, task, type)
if (i >= ProcListSize)
{
/* grow process list */
- struct procs *npv;
+ PROCS_T *npv;
- npv = (struct procs *) xalloc((sizeof *npv) *
- (ProcListSize + PROC_LIST_SEG));
+ SM_ASSERT(ProcListSize < INT_MAX - PROC_LIST_SEG);
+ npv = (PROCS_T *) sm_pmalloc_x((sizeof *npv) *
+ (ProcListSize + PROC_LIST_SEG));
if (ProcListSize > 0)
{
memmove(npv, ProcListVec,
- ProcListSize * sizeof (struct procs));
+ ProcListSize * sizeof (PROCS_T));
sm_free(ProcListVec);
}
+
+ /* XXX just use memset() to initialize this part? */
for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
{
npv[i].proc_pid = NO_PID;
@@ -2370,16 +2459,19 @@ proc_list_add(pid, task, type)
ProcListVec = npv;
}
ProcListVec[i].proc_pid = pid;
- if (ProcListVec[i].proc_task != NULL)
- sm_free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = newstr(task);
+ PSTRSET(ProcListVec[i].proc_task, task);
ProcListVec[i].proc_type = type;
+ ProcListVec[i].proc_count = count;
+ ProcListVec[i].proc_other = other;
/* if process adding itself, it's not a child */
- if (pid != getpid())
+ if (pid != CurrentPid)
+ {
+ SM_ASSERT(CurChildren < INT_MAX);
CurChildren++;
+ }
}
- /*
+/*
** PROC_LIST_SET -- set pid task in process list
**
** Parameters:
@@ -2401,30 +2493,36 @@ proc_list_set(pid, task)
{
if (ProcListVec[i].proc_pid == pid)
{
- if (ProcListVec[i].proc_task != NULL)
- sm_free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = newstr(task);
+ PSTRSET(ProcListVec[i].proc_task, task);
break;
}
}
}
- /*
+/*
** PROC_LIST_DROP -- drop pid from process list
**
** Parameters:
** pid -- pid to drop
+** st -- process status
+** other -- storage for proc_other (return).
**
** Returns:
-** type of process
+** none.
+**
+** Side Effects:
+** May decrease CurChildren, CurRunners, or
+** set RestartRequest or ShutdownRequest.
**
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
** DOING.
*/
-int
-proc_list_drop(pid)
+void
+proc_list_drop(pid, st, other)
pid_t pid;
+ int st;
+ int *other;
{
int i;
int type = PROC_NONE;
@@ -2435,6 +2533,8 @@ proc_list_drop(pid)
{
ProcListVec[i].proc_pid = NO_PID;
type = ProcListVec[i].proc_type;
+ if (other != NULL)
+ *other = ProcListVec[i].proc_other;
break;
}
}
@@ -2442,9 +2542,24 @@ proc_list_drop(pid)
CurChildren--;
- return type;
+ if (type == PROC_CONTROL && WIFEXITED(st))
+ {
+ /* if so, see if we need to restart or shutdown */
+ if (WEXITSTATUS(st) == EX_RESTART)
+ RestartRequest = "control socket";
+ else if (WEXITSTATUS(st) == EX_SHUTDOWN)
+ ShutdownRequest = "control socket";
+ }
+ else if (type == PROC_QUEUE_CHILD && !WIFSTOPPED(st) &&
+ ProcListVec[i].proc_other > -1)
+ {
+ /* restart this persistent runner */
+ mark_work_group_restart(ProcListVec[i].proc_other, st);
+ }
+ else if (type == PROC_QUEUE)
+ CurRunners -= ProcListVec[i].proc_count;
}
- /*
+/*
** PROC_LIST_CLEAR -- clear the process list
**
** Parameters:
@@ -2452,6 +2567,9 @@ proc_list_drop(pid)
**
** Returns:
** none.
+**
+** Side Effects:
+** Sets CurChildren to zero.
*/
void
@@ -2461,12 +2579,10 @@ proc_list_clear()
/* start from 1 since 0 is the daemon itself */
for (i = 1; i < ProcListSize; i++)
- {
ProcListVec[i].proc_pid = NO_PID;
- }
CurChildren = 0;
}
- /*
+/*
** PROC_LIST_PROBE -- probe processes in the list to see if they still exist
**
** Parameters:
@@ -2474,6 +2590,9 @@ proc_list_clear()
**
** Returns:
** none
+**
+** Side Effects:
+** May decrease CurChildren.
*/
void
@@ -2493,25 +2612,29 @@ proc_list_probe()
"proc_list_probe: lost pid %d",
(int) ProcListVec[i].proc_pid);
ProcListVec[i].proc_pid = NO_PID;
+ SM_FREE_CLR(ProcListVec[i].proc_task);
CurChildren--;
}
}
if (CurChildren < 0)
CurChildren = 0;
}
- /*
+
+/*
** PROC_LIST_DISPLAY -- display the process list
**
** Parameters:
** out -- output file pointer
+** prefix -- string to output in front of each line.
**
** Returns:
** none.
*/
void
-proc_list_display(out)
- FILE *out;
+proc_list_display(out, prefix)
+ SM_FILE_T *out;
+ char *prefix;
{
int i;
@@ -2520,202 +2643,60 @@ proc_list_display(out)
if (ProcListVec[i].proc_pid == NO_PID)
continue;
- fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid,
- ProcListVec[i].proc_task != NULL ?
- ProcListVec[i].proc_task : "(unknown)",
- (OpMode == MD_SMTP ||
- OpMode == MD_DAEMON ||
- OpMode == MD_ARPAFTP) ? "\r" : "");
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "%s%d %s%s\n",
+ prefix,
+ (int) ProcListVec[i].proc_pid,
+ ProcListVec[i].proc_task != NULL ?
+ ProcListVec[i].proc_task : "(unknown)",
+ (OpMode == MD_SMTP ||
+ OpMode == MD_DAEMON ||
+ OpMode == MD_ARPAFTP) ? "\r" : "");
}
}
- /*
-** SAFEFOPEN -- do a file open with extra checking
+
+/*
+** PROC_LIST_SIGNAL -- send a signal to a type of process in the list
**
** Parameters:
-** fn -- the file name to open.
-** omode -- the open-style mode flags.
-** cmode -- the create-style mode flags.
-** sff -- safefile flags.
+** type -- type of process to signal
+** signal -- the type of signal to send
**
-** Returns:
-** Same as fopen.
+** Results:
+** none.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
*/
-FILE *
-safefopen(fn, omode, cmode, sff)
- char *fn;
- int omode;
- int cmode;
- long sff;
+void
+proc_list_signal(type, signal)
+ int type;
+ int signal;
{
- int fd;
- int save_errno;
- FILE *fp;
- char *fmode;
-
- switch (omode & O_ACCMODE)
- {
- case O_RDONLY:
- fmode = "r";
- break;
-
- case O_WRONLY:
- if (bitset(O_APPEND, omode))
- fmode = "a";
- else
- fmode = "w";
- break;
+ int chldwasblocked;
+ int alrmwasblocked;
+ int i;
+ pid_t mypid = getpid();
- case O_RDWR:
- if (bitset(O_TRUNC, omode))
- fmode = "w+";
- else if (bitset(O_APPEND, omode))
- fmode = "a+";
- else
- fmode = "r+";
- break;
+ /* block these signals so that we may signal cleanly */
+ chldwasblocked = sm_blocksignal(SIGCHLD);
+ alrmwasblocked = sm_blocksignal(SIGALRM);
- default:
- syserr("554 5.3.5 safefopen: unknown omode %o", omode);
- fmode = "x";
- }
- fd = safeopen(fn, omode, cmode, sff);
- if (fd < 0)
- {
- save_errno = errno;
- if (tTd(44, 10))
- dprintf("safefopen: safeopen failed: %s\n",
- errstring(errno));
- errno = save_errno;
- return NULL;
- }
- fp = fdopen(fd, fmode);
- if (fp != NULL)
- return fp;
-
- save_errno = errno;
- if (tTd(44, 10))
+ /* Find all processes of type and send signal */
+ for (i = 0; i < ProcListSize; i++)
{
- dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n",
- fn, fmode, omode, sff, errstring(errno));
+ if (ProcListVec[i].proc_pid == NO_PID ||
+ ProcListVec[i].proc_pid == mypid)
+ continue;
+ if (ProcListVec[i].proc_type != type)
+ continue;
+ (void) kill(ProcListVec[i].proc_pid, signal);
}
- (void) close(fd);
- errno = save_errno;
- return NULL;
-}
- /*
-** SM_STRCASECMP -- 8-bit clean version of strcasecmp
-**
-** Thank you, vendors, for making this all necessary.
-*/
-
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
-#endif /* defined(LIBC_SCCS) && !defined(lint) */
-
-/*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
- * based upon ascii character sequences.
- */
-static const u_char charmap[] = {
- 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
- 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
- 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
- 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
- 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
- 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
- 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
- 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
- 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
- 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
- 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
- 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
- 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
- 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
- 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
- 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
- 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
- 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
- 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
- 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
-};
-
-int
-sm_strcasecmp(s1, s2)
- const char *s1, *s2;
-{
- register const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- while (cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return 0;
- return (cm[*us1] - cm[*--us2]);
-}
-
-int
-sm_strncasecmp(s1, s2, n)
- const char *s1, *s2;
- register size_t n;
-{
- if (n != 0) {
- register const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- do {
- if (cm[*us1] != cm[*us2++])
- return (cm[*us1] - cm[*--us2]);
- if (*us1++ == '\0')
- break;
- } while (--n != 0);
- }
- return 0;
+ /* restore the signals */
+ if (alrmwasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+ if (chldwasblocked == 0)
+ (void) sm_releasesignal(SIGCHLD);
}
diff --git a/contrib/sendmail/src/version.c b/contrib/sendmail/src/version.c
index ce675c7..95c7ee2 100644
--- a/contrib/sendmail/src/version.c
+++ b/contrib/sendmail/src/version.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -11,8 +11,8 @@
*
*/
-#ifndef lint
-static char id[] = "@(#)$Id: version.c,v 8.43.4.39 2001/08/20 14:45:34 gshapiro Exp $";
-#endif /* ! lint */
+#include <sm/gen.h>
-char Version[] = "8.11.6";
+SM_RCSID("@(#)$Id: version.c,v 8.91 2002/01/13 18:23:00 ca Exp $")
+
+char Version[] = "8.12.2";
diff --git a/contrib/sendmail/test/Makefile b/contrib/sendmail/test/Makefile
new file mode 100644
index 0000000..7ca1b40
--- /dev/null
+++ b/contrib/sendmail/test/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.1 2001/09/23 22:39:24 ca Exp $
+
+SHELL= /bin/sh
+BUILD= ./Build
+OPTIONS= $(CONFIG) $(FLAGS)
+
+all: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+clean: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+install: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+
+fresh: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) -c
+
+FRC:
diff --git a/contrib/sendmail/test/Makefile.m4 b/contrib/sendmail/test/Makefile.m4
new file mode 100644
index 0000000..14868a9
--- /dev/null
+++ b/contrib/sendmail/test/Makefile.m4
@@ -0,0 +1,18 @@
+include(confBUILDTOOLSDIR`/M4/switch.m4')
+
+bldPRODUCT_START(`executable', `test')
+define(`bldSOURCES', `t_dropgid.c ')
+bldPRODUCT_END
+
+include(confBUILDTOOLSDIR`/M4/'bldM4_TYPE_DIR`/sm-test.m4')
+dnl smtest(`getipnode')
+smtest(`t_dropgid')
+smtest(`t_exclopen')
+smtest(`t_pathconf')
+smtest(`t_seteuid')
+smtest(`t_setgid')
+smtest(`t_setreuid')
+smtest(`t_setuid')
+dnl smtest(`t_snprintf')
+
+bldFINISH
diff --git a/contrib/sendmail/test/README b/contrib/sendmail/test/README
new file mode 100644
index 0000000..d715bbb
--- /dev/null
+++ b/contrib/sendmail/test/README
@@ -0,0 +1,27 @@
+# Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+# $Id: README,v 1.2 2001/09/28 16:36:28 ca Exp $
+#
+
+This directory contains several programs to test various OS calls.
+If your OS is not listed in the Results file, you should run those
+test programs. Most of them have instructions at the begin of source
+code, at least those which are important.
+
+Notice: most of these programs require set-user-ID or set-group-ID
+installation. Hence they are not tested automatically.
+
+t_dropgid.c test how to drop saved-gid for a set-group-ID program
+t_exclopen.c test for security-defeating semantics that an open with
+ O_CREAT|O_EXCL set will successfully open a file named
+ by a symbolic link that to a non-existent file
+t_seteuid.c test whether seteuid works
+t_setgid.c test whether setgid works
+t_setreuid.c test whether setreuid works
+t_setuid.c test whether setuid works
+
diff --git a/contrib/sendmail/test/Results b/contrib/sendmail/test/Results
index 192f778..934f9a1 100644
--- a/contrib/sendmail/test/Results
+++ b/contrib/sendmail/test/Results
@@ -1,3 +1,7 @@
++------------+
+| t_setreuid |
++------------+
+
The following are results of running t_setreuid on various architectures.
OPSYS VERSION STATUS DATE TESTER/NOTES
@@ -69,6 +73,9 @@ DELL 2.2 OK 93.11.15 Peter Wemm (using -DSETEUID)
Pyramid 5.0d OK 95.01.14 David Miller <davem@nadzieja.rutgers.edu>
++-----------+
+| t_seteuid |
++-----------+
The following are results of running t_seteuid on various architectures.
@@ -101,6 +108,10 @@ OSF/1 4.0 OK 96.09.18 Gregory Neil Shapiro <gshapiro@wpi.edu>
CxOS 11.5 FAIL 96.07.08 Eric Schnoebelen <eric@cirr.com>
++------------+
+| t_pathconf |
++------------+
+
The following are the results of running t_pathconf.c. Safe means that
the underlying filesystem (in NFS, the filesystem on the server) does not
permit regular (non-root) users to chown their files to another user.
@@ -157,4 +168,31 @@ NCR MP-RAS 3 -1/0
Linux 2.0.27 1/0 1/0
-$Revision: 8.1 $, Last updated $Date: 1999/02/06 18:44:07 $
+
++-----------+
+| t_dropgid |
++-----------+
+
+The following are results of running t_dropgid on various architectures.
+
+OPSYS VERSION STATUS DATE TESTER/NOTES
+===== ======= ====== ==== ============
+AIX 4.3.3 FAILS 2001-09-22 Valdis Kletnieks
+BSD/OS 4.2 OK 2001-09-22 Vernon Schryver
+FreeBSD 3.2 OK 2001-09-22 ca
+FreeBSD 4.4 OK 2001-09-29 ca
+HP-UX 11.00 HASSETRESGID 2001-09-22 ca
+IRIX 6.5 FAILS 2001-09-22 Mark D. Roth
+Linux 2.0.35 HASSETREGID 2001-09-22 Neil W Rickert
+Linux 2.2.12 HASSETREGID 2001-09-22 ca
+Linux 2.2.16 HASSETREGID 2001-09-22 Neil W Rickert
+Linux 2.4.9 HASSETREGID 2001-09-22 Derek Balling
+NetBSD 1.5 OK 2001-09-22 Kimmo Suominen
+OpenBSD 2.8 HASSETEGID 2001-09-22 ca
+SCO 5.0.5 FAILS 2001-09-22 Phillip Porch
+SunOS 5.7 HASSETREGID 2001-09-22 Neil W Rickert
+SunOS 5.8 HASSETREGID 2001-09-22 ca
+SunOS 5.9 HASSETREGID 2001-09-22 Neil W Rickert
+
+
+$Revision: 8.3 $, Last updated $Date: 2001/09/30 01:32:33 $
diff --git a/contrib/sendmail/test/t_dropgid.c b/contrib/sendmail/test/t_dropgid.c
new file mode 100644
index 0000000..cb166d0
--- /dev/null
+++ b/contrib/sendmail/test/t_dropgid.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
+** This program checks to see if your version of setgid works.
+** Compile it, make it set-group-ID guest, and run it as yourself (NOT as
+** root and not as member of the group guest).
+**
+** Compilation is trivial -- just "cc t_dropgid.c". Make it set-group-ID
+** guest and then execute it as a non-root user.
+*/
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifndef lint
+static char id[] = "@(#)$Id: t_dropgid.c,v 1.6 2001/09/28 16:36:28 ca Exp $";
+#endif /* ! lint */
+
+static void
+printgids(str, r, e)
+ char *str;
+ gid_t r, e;
+{
+ printf("%s (should be %d/%d): r/egid=%d/%d\n", str, (int) r, (int) e,
+ (int) getgid(), (int) getegid());
+}
+
+/* define only one of these */
+#if HASSETEGID
+# define SETGIDCALL "setegid"
+#endif /* HASSETEGID */
+#if HASSETREGID
+# define SETGIDCALL "setregid"
+#endif /* HASSETREGID */
+#if HASSETRESGID
+# define SETGIDCALL "setresgid"
+#endif /* HASSETRESGID */
+
+#ifndef SETGIDCALL
+# define SETGIDCALL "setgid"
+#endif /* ! SETGIDCALL */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int fail = 0;
+ int res;
+ gid_t realgid = getgid();
+ gid_t effgid = getegid();
+ char *prg = argv[0];
+
+ printgids("initial gids", realgid, effgid);
+
+ if (effgid == realgid)
+ {
+ printf("SETUP ERROR: re-run set-group-ID guest\n");
+ printf("Use chgrp(1) and chmod(1)\n");
+ printf("For example, do this as root ");
+ printf("(nobody is the name of a group in this example):\n");
+ printf("# chgrp nobody %s\n", prg);
+ printf("# chmod g+s nobody %s\n", prg);
+ exit(1);
+ }
+
+#if HASSETREGID
+ res = setregid(realgid, realgid);
+ printf("setregid(%d)=%d %s\n", (int) realgid, res,
+ res < 0 ? "failure" : "ok");
+ printgids("after setregid()", realgid, realgid);
+#endif /* HASSETREGID */
+#if HASSETRESGID
+ res = setresgid(realgid, realgid, realgid);
+ printf("setresgid(%d)=%d %s\n", (int) realgid, res,
+ res < 0 ? "failure" : "ok");
+ printgids("after setresgid()", realgid, realgid);
+#endif /* HASSETRESGID */
+#if HASSETEGID
+ res = setegid(realgid);
+ printf("setegid(%d)=%d %s\n", (int) realgid, res,
+ res < 0 ? "failure" : "ok");
+ printgids("after setegid()", realgid, realgid);
+#endif /* HASSETEGID */
+ res = setgid(realgid);
+ printf("setgid(%d)=%d %s\n", (int) realgid, res,
+ res < 0 ? "failure" : "ok");
+ printgids("after setgid()", realgid, realgid);
+
+ if (getegid() != realgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong effective gid\n");
+ }
+
+ if (getgid() != realgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real gid\n");
+ }
+
+ /* do activity here */
+ if (setgid(effgid) == 0)
+ {
+ fail++;
+ printf("MAYDAY! setgid(%d) succeeded (should have failed)\n",
+ effgid);
+ }
+ else
+ {
+ printf("setgid(%d) failed (this is correct)\n", effgid);
+ }
+ printgids("after setgid() to egid", realgid, realgid);
+
+ if (getegid() != realgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong effective gid\n");
+ }
+ if (getgid() != realgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real gid\n");
+ }
+ printf("\n");
+
+ if (fail > 0)
+ {
+ printf("\nThis system cannot use %s to give up set-group-ID rights\n",
+ SETGIDCALL);
+#if !HASSETEGID
+ printf("Maybe compile with -DHASSETEGID and try again\n");
+#endif /* !HASSETEGID */
+#if !HASSETREGID
+ printf("Maybe compile with -DHASSETREGID and try again\n");
+#endif /* !HASSETREGID */
+#if !HASSETRESGID
+ printf("Maybe compile with -DHASSETRESGID and try again\n");
+#endif /* !HASSETRESGID */
+ exit(1);
+ }
+
+ printf("\nIt is possible to use %s on this system\n", SETGIDCALL);
+ exit(0);
+}
diff --git a/contrib/sendmail/test/t_exclopen.c b/contrib/sendmail/test/t_exclopen.c
index 22ef693..f1bde72 100644
--- a/contrib/sendmail/test/t_exclopen.c
+++ b/contrib/sendmail/test/t_exclopen.c
@@ -1,4 +1,14 @@
/*
+ * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
** This program tests your system to see if you have the lovely
** security-defeating semantics that an open with O_CREAT|O_EXCL
** set will successfully open a file named by a symbolic link that
@@ -36,7 +46,7 @@
#include <unistd.h>
#ifndef lint
-static char id[] = "@(#)$Id: t_exclopen.c,v 8.5 1999/08/28 00:25:28 gshapiro Exp $";
+static char id[] = "@(#)$Id: t_exclopen.c,v 8.6 2001/09/23 03:35:41 ca Exp $";
#endif /* ! lint */
static char Attacker[128];
diff --git a/contrib/sendmail/test/t_pathconf.c b/contrib/sendmail/test/t_pathconf.c
index 5355fd6..2baaaa6 100644
--- a/contrib/sendmail/test/t_pathconf.c
+++ b/contrib/sendmail/test/t_pathconf.c
@@ -1,4 +1,14 @@
/*
+ * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
** The following test program tries the pathconf(2) routine. It should
** be run in a non-NFS-mounted directory (e.g., /tmp) and on remote (NFS)
** mounted directories running both NFS-v2 and NFS-v3 from systems that
@@ -16,7 +26,7 @@
#include <sysexits.h>
#ifndef lint
-static char id[] = "@(#)$Id: t_pathconf.c,v 8.5 1999/08/28 00:25:28 gshapiro Exp $";
+static char id[] = "@(#)$Id: t_pathconf.c,v 8.6 2001/09/23 03:35:41 ca Exp $";
#endif /* ! lint */
int
diff --git a/contrib/sendmail/test/t_seteuid.c b/contrib/sendmail/test/t_seteuid.c
index b912b60..9fab898 100644
--- a/contrib/sendmail/test/t_seteuid.c
+++ b/contrib/sendmail/test/t_seteuid.c
@@ -1,13 +1,23 @@
/*
+ * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
** This program checks to see if your version of seteuid works.
-** Compile it, make it setuid root, and run it as yourself (NOT as
+** Compile it, make it set-user-ID root, and run it as yourself (NOT as
** root). If it won't compile or outputs any MAYDAY messages, don't
** define USESETEUID in conf.h.
**
** NOTE: It is not sufficient to have seteuid in your library.
** You must also have saved uids that function properly.
**
-** Compilation is trivial -- just "cc t_seteuid.c". Make it setuid,
+** Compilation is trivial -- just "cc t_seteuid.c". Make it set-user-ID
** root and then execute it as a non-root user.
*/
@@ -16,7 +26,7 @@
#include <stdio.h>
#ifndef lint
-static char id[] = "@(#)$Id: t_seteuid.c,v 8.4 1999/08/28 00:25:28 gshapiro Exp $";
+static char id[] = "@(#)$Id: t_seteuid.c,v 8.8 2001/09/23 03:35:41 ca Exp $";
#endif /* ! lint */
#ifdef __hpux
@@ -26,10 +36,10 @@ static char id[] = "@(#)$Id: t_seteuid.c,v 8.4 1999/08/28 00:25:28 gshapiro Exp
static void
printuids(str, r, e)
char *str;
- int r, e;
+ uid_t r, e;
{
- printf("%s (should be %d/%d): r/euid=%d/%d\n", str, r, e,
- getuid(), geteuid());
+ printf("%s (should be %d/%d): r/euid=%d/%d\n", str, (int) r, (int) e,
+ (int) getuid(), (int) geteuid());
}
int
@@ -44,7 +54,7 @@ main(argc, argv)
if (geteuid() != 0)
{
- printf("SETUP ERROR: re-run setuid root\n");
+ printf("SETUP ERROR: re-run set-user-ID root\n");
exit(1);
}
diff --git a/contrib/sendmail/test/t_setgid.c b/contrib/sendmail/test/t_setgid.c
new file mode 100644
index 0000000..dfe1805
--- /dev/null
+++ b/contrib/sendmail/test/t_setgid.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
+** This program checks to see if your version of setgid works.
+** Compile it, make it set-group-ID guest, and run it as yourself (NOT as
+** root and not as member of the group guest).
+**
+** Compilation is trivial -- just "cc t_setgid.c". Make it set-group-ID,
+** guest and then execute it as a non-root user.
+*/
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifndef lint
+static char id[] = "@(#)$Id: t_setgid.c,v 1.6 2001/09/23 03:35:41 ca Exp $";
+#endif /* ! lint */
+
+static void
+printgids(str, r, e)
+ char *str;
+ gid_t r, e;
+{
+ printf("%s (should be %d/%d): r/egid=%d/%d\n", str, (int) r, (int) e,
+ (int) getgid(), (int) getegid());
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int fail = 0;
+ int res;
+ gid_t realgid = getgid();
+ gid_t effgid = getegid();
+
+ printgids("initial gids", realgid, effgid);
+
+ if (effgid == realgid)
+ {
+ printf("SETUP ERROR: re-run set-group-ID guest\n");
+ exit(1);
+ }
+
+#if SM_CONF_SETREGID
+ res = setregid(effgid, effgid);
+#else /* SM_CONF_SETREGID */
+ res = setgid(effgid);
+#endif /* SM_CONF_SETREGID */
+
+ printf("setgid(%d)=%d %s\n", (int) effgid, res,
+ res < 0 ? "failure" : "ok");
+#if SM_CONF_SETREGID
+ printgids("after setregid()", effgid, effgid);
+#else /* SM_CONF_SETREGID */
+ printgids("after setgid()", effgid, effgid);
+#endif /* SM_CONF_SETREGID */
+
+ if (getegid() != effgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong effective gid\n");
+ }
+
+ if (getgid() != effgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real gid\n");
+ }
+
+ /* do activity here */
+ if (setgid(0) == 0)
+ {
+ fail++;
+ printf("MAYDAY! setgid(0) succeeded (should have failed)\n");
+ }
+ else
+ {
+ printf("setgid(0) failed (this is correct)\n");
+ }
+ printgids("after setgid(0)", effgid, effgid);
+
+ if (getegid() != effgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong effective gid\n");
+ }
+ if (getgid() != effgid)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real gid\n");
+ }
+ printf("\n");
+
+ if (fail > 0)
+ {
+ printf("\nThis system cannot use %s to set the real gid to the effective gid\nand clear the saved gid.\n",
+#if SM_CONF_SETREGID
+ "setregid"
+#else /* SM_CONF_SETREGID */
+ "setgid"
+#endif /* SM_CONF_SETREGID */
+ );
+ exit(1);
+ }
+
+ printf("\nIt is possible to use setgid on this system\n");
+ exit(0);
+}
diff --git a/contrib/sendmail/test/t_setreuid.c b/contrib/sendmail/test/t_setreuid.c
index 1b6eff6..b307b08 100644
--- a/contrib/sendmail/test/t_setreuid.c
+++ b/contrib/sendmail/test/t_setreuid.c
@@ -1,10 +1,20 @@
/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
** This program checks to see if your version of setreuid works.
-** Compile it, make it setuid root, and run it as yourself (NOT as
+** Compile it, make it set-user-ID root, and run it as yourself (NOT as
** root). If it won't compile or outputs any MAYDAY messages, don't
** define HASSETREUID in conf.h.
**
-** Compilation is trivial -- just "cc t_setreuid.c". Make it setuid,
+** Compilation is trivial -- just "cc t_setreuid.c". Make it set-user-ID,
** root and then execute it as a non-root user.
*/
@@ -13,7 +23,7 @@
#include <stdio.h>
#ifndef lint
-static char id[] = "@(#)$Id: t_setreuid.c,v 8.4 1999/08/28 00:25:28 gshapiro Exp $";
+static char id[] = "@(#)$Id: t_setreuid.c,v 8.9 2001/10/12 03:04:46 gshapiro Exp $";
#endif /* ! lint */
#ifdef __hpux
@@ -23,10 +33,10 @@ static char id[] = "@(#)$Id: t_setreuid.c,v 8.4 1999/08/28 00:25:28 gshapiro Exp
static void
printuids(str, r, e)
char *str;
- int r, e;
+ uid_t r, e;
{
- printf("%s (should be %d/%d): r/euid=%d/%d\n", str, r, e,
- getuid(), geteuid());
+ printf("%s (should be %d/%d): r/euid=%d/%d\n", str, (int) r, (int) e,
+ (int) getuid(), (int) geteuid());
}
int
@@ -41,7 +51,7 @@ main(argc, argv)
if (geteuid() != 0)
{
- printf("SETUP ERROR: re-run setuid root\n");
+ printf("SETUP ERROR: re-run set-user-ID root\n");
exit(1);
}
@@ -58,6 +68,12 @@ main(argc, argv)
}
printuids("after setreuid(0, 1)", 0, 1);
+ if (getuid() != 0)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real uid\n");
+ }
+
if (geteuid() != 1)
{
fail++;
@@ -75,7 +91,7 @@ main(argc, argv)
if (setreuid(realuid, 0) < 0)
{
fail++;
- printf("setreuid(%d, 0) failure\n", realuid);
+ printf("setreuid(%d, 0) failure\n", (int) realuid);
}
printuids("after setreuid(realuid, 0)", realuid, 0);
@@ -104,6 +120,12 @@ main(argc, argv)
printf("MAYDAY! Wrong effective uid\n");
}
+ if (getuid() != 0)
+ {
+ fail++;
+ printf("MAYDAY! Wrong real uid\n");
+ }
+
/* do activity here */
if (setreuid(-1, 0) < 0)
@@ -115,7 +137,7 @@ main(argc, argv)
if (setreuid(realuid, 0) < 0)
{
fail++;
- printf("setreuid(%d, 0) failure\n", realuid);
+ printf("setreuid(%d, 0) failure\n", (int) realuid);
}
printuids("after setreuid(realuid, 0)", realuid, 0);
diff --git a/contrib/sendmail/test/t_setuid.c b/contrib/sendmail/test/t_setuid.c
index 7487579..6533339 100644
--- a/contrib/sendmail/test/t_setuid.c
+++ b/contrib/sendmail/test/t_setuid.c
@@ -1,12 +1,22 @@
/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+/*
** This program checks to see if your version of setuid works.
-** Compile it, make it setuid root, and run it as yourself (NOT as
+** Compile it, make it set-user-ID root, and run it as yourself (NOT as
** root).
**
** NOTE: This should work everywhere, but Linux has the ability
** to use the undocumented setcap() call to make this break.
**
-** Compilation is trivial -- just "cc t_setuid.c". Make it setuid,
+** Compilation is trivial -- just "cc t_setuid.c". Make it set-user-ID,
** root and then execute it as a non-root user.
*/
@@ -15,16 +25,16 @@
#include <stdio.h>
#ifndef lint
-static char id[] = "@(#)$Id: t_setuid.c,v 8.2.2.1 2000/05/31 00:29:47 gshapiro Exp $";
+static char id[] = "@(#)$Id: t_setuid.c,v 8.7 2001/09/23 03:35:41 ca Exp $";
#endif /* ! lint */
static void
printuids(str, r, e)
char *str;
- int r, e;
+ uid_t r, e;
{
- printf("%s (should be %d/%d): r/euid=%d/%d\n", str, r, e,
- getuid(), geteuid());
+ printf("%s (should be %d/%d): r/euid=%d/%d\n", str, (int) r, (int) e,
+ (int) getuid(), (int) geteuid());
}
int
@@ -39,7 +49,7 @@ main(argc, argv)
if (geteuid() != 0)
{
- printf("SETUP ERROR: re-run setuid root\n");
+ printf("SETUP ERROR: re-run set-user-ID root\n");
exit(1);
}
diff --git a/contrib/sendmail/test/t_snprintf.c b/contrib/sendmail/test/t_snprintf.c
index 3117af5..8a0378f 100644
--- a/contrib/sendmail/test/t_snprintf.c
+++ b/contrib/sendmail/test/t_snprintf.c
@@ -1,6 +1,20 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
#include <stdio.h>
#include <sysexits.h>
+#ifndef lint
+static char id[] = "@(#)$Id: t_snprintf.c,v 8.4 2001/09/23 03:35:41 ca Exp $";
+#endif /* ! lint */
+
#define TEST_STRING "1234567890"
int
diff --git a/contrib/sendmail/vacation/Makefile.m4 b/contrib/sendmail/vacation/Makefile.m4
index 71430eb..6de9d4e 100644
--- a/contrib/sendmail/vacation/Makefile.m4
+++ b/contrib/sendmail/vacation/Makefile.m4
@@ -1,5 +1,6 @@
include(confBUILDTOOLSDIR`/M4/switch.m4')
+define(`confREQUIRE_LIBSM', `true')
# sendmail dir
SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
PREPENDDEF(`confENVDEF', `confMAPDEF')
@@ -7,6 +8,7 @@ PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
bldPRODUCT_START(`executable', `vacation')
define(`bldSOURCES', `vacation.c ')
+bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
bldPUSH_SMLIB(`smdb')
APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
diff --git a/contrib/sendmail/vacation/vacation.1 b/contrib/sendmail/vacation/vacation.1
index e8ead6b..666070e 100644
--- a/contrib/sendmail/vacation/vacation.1
+++ b/contrib/sendmail/vacation/vacation.1
@@ -9,29 +9,34 @@
.\" the sendmail distribution.
.\"
.\"
-.\" $Id: vacation.1,v 8.11.4.8 2001/07/20 04:19:38 gshapiro Exp $
+.\" $Id: vacation.1,v 8.26 2001/11/21 04:21:35 gshapiro Exp $
.\"
-.TH VACATION 1 "$Date: 2001/07/20 04:19:38 $"
+.TH VACATION 1 "$Date: 2001/11/21 04:21:35 $"
.SH NAME
vacation
\- return ``I am not here'' indication
.SH SYNOPSIS
.B vacation
-.RB [ \-i ]
-.RB [ \-I ]
-.RB [ \-r
-.IR interval ]
-.RB [ \-x ]
.RB [ \-a
.IR alias ]
+.RB [ \-C
+.IR cffile ]
+.RB [ \-d ]
.RB [ \-f
.IR database ]
+.RB [ \-i ]
+.RB [ \-I ]
+.RB [ \-l ]
.RB [ \-m
.IR message ]
+.RB [ \-r
+.IR interval ]
.RB [ \-s
.IR address ]
.RB [ \-t
.IR time ]
+.RB [ \-U ]
+.RB [ \-x ]
.RB [ \-z ]
.I login
.SH DESCRIPTION
@@ -59,11 +64,30 @@ Handle messages for
in the same manner as those received for the user's
login name.
.TP
+.BI \-C " cfpath"
+Specify pathname of the sendmail configuration file.
+This option is ignored if
+.B \-U
+is specified.
+This option defaults to the standard sendmail configuration file,
+located at /etc/mail/sendmail.cf on most systems.
+.TP
+.B \-d
+Send error/debug messages to stdout instead of syslog.
+Otherwise, fatal errors, such as calling
+.B vacation
+with incorrect arguments, or with non-existent
+.IR login s,
+are logged in the system log file, using
+syslog(8).
+.TP
.BI \-f " filename"
Use
.I filename
as name of the database instead of
-.IR ~/.vacation.db .
+.IR ~/.vacation.db
+or
+.IR ~/.vacation.{dir,pag} .
Unless the
.I filename
starts with / it is relative to ~.
@@ -88,6 +112,10 @@ Unless the
.I filename
starts with / it is relative to ~.
.TP
+.B \-l
+List the content of the vacation database file including the address
+and the associated time of the last auto-response to that address.
+.TP
.BI \-r " interval"
Set the reply interval to
.I interval
@@ -108,6 +136,13 @@ line as the recipient for the vacation message.
Ignored, available only for compatibility with Sun's
vacation program.
.TP
+.B \-U
+Do not attempt to lookup
+.I login
+in the password file.
+The -f and -m options must be used to specify the database and message file
+since there is no home directory for the default settings for these options.
+.TP
.B \-x
reads an exclusion list from stdin (one address per line).
Mails coming from an address
@@ -153,8 +188,12 @@ or
line is included in the mail headers.
The people who have sent you messages are maintained as a
db(3)
+or
+dbm(3)
database in the file
.I .vacation.db
+or
+.I .vacation.{dir,pag}
in your home directory.
.PP
.B Vacation
@@ -184,17 +223,13 @@ Sendmail(8)
includes this
``From''
line automatically.
-.PP
-Fatal errors, such as calling
-.B vacation
-with incorrect arguments, or with non-existent
-.IR login s,
-are logged in the system log file, using
-syslog(8).
.SH FILES
.TP 1.8i
~/.vacation.db
-default database file
+default database file for db(3)
+.TP 1.8i
+~/.vacation.{dir,pag}
+default database file for dbm(3)
.TP
~/.vacation.msg
default message to send
diff --git a/contrib/sendmail/vacation/vacation.c b/contrib/sendmail/vacation/vacation.c
index 42ae04f..ec69541 100644
--- a/contrib/sendmail/vacation/vacation.c
+++ b/contrib/sendmail/vacation/vacation.c
@@ -11,18 +11,16 @@
*
*/
-#ifndef lint
-static char copyright[] =
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
"@(#) Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1983, 1987, 1993\n\
The Regents of the University of California. All rights reserved.\n\
- Copyright (c) 1983 Eric P. Allman. All rights reserved.\n";
-#endif /* ! lint */
+ Copyright (c) 1983 Eric P. Allman. All rights reserved.\n")
-#ifndef lint
-static char id[] = "@(#)$Id: vacation.c,v 8.68.4.21 2001/05/07 22:06:41 gshapiro Exp $";
-#endif /* ! lint */
+SM_IDSTR(id, "@(#)$Id: vacation.c,v 8.131 2001/12/12 00:02:42 gshapiro Exp $")
#include <ctype.h>
@@ -33,27 +31,17 @@ static char id[] = "@(#)$Id: vacation.c,v 8.68.4.21 2001/05/07 22:06:41 gshapiro
#ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
#endif /* EX_OK */
-#include <sysexits.h>
+#include <sm/sysexits.h>
+#include <sm/cf.h>
+#include <sm/mbdb.h>
#include "sendmail/sendmail.h"
+#include <sendmail/pathnames.h>
#include "libsmdb/smdb.h"
-#if defined(__hpux) && !defined(HPUX11)
-# undef syslog /* Undo hard_syslog conf.h change */
-#endif /* defined(__hpux) && !defined(HPUX11) */
-
-#ifndef _PATH_SENDMAIL
-# define _PATH_SENDMAIL "/usr/lib/sendmail"
-#endif /* ! _PATH_SENDMAIL */
-
#define ONLY_ONCE ((time_t) 0) /* send at most one reply */
#define INTERVAL_UNDEF ((time_t) (-1)) /* no value given */
-#ifndef TRUE
-# define TRUE 1
-# define FALSE 0
-#endif /* ! TRUE */
-
uid_t RealUid;
gid_t RealGid;
char *RealUserName;
@@ -61,7 +49,7 @@ uid_t RunAsUid;
uid_t RunAsGid;
char *RunAsUserName;
int Verbose = 2;
-bool DontInitGroups = FALSE;
+bool DontInitGroups = false;
uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
@@ -79,15 +67,6 @@ BITMAP256 DontBlameSendmail;
#define SECSPERDAY (60 * 60 * 24)
#define DAYSPERWEEK 7
-#ifndef __P
-# ifdef __STDC__
-# define __P(protos) protos
-# else /* __STDC__ */
-# define __P(protos) ()
-# define const
-# endif /* __STDC__ */
-#endif /* ! __P */
-
typedef struct alias
{
char *name;
@@ -100,33 +79,48 @@ SMDB_DATABASE *Db;
char From[MAXLINE];
-#if _FFR_DEBUG
-void (*msglog)(int, const char *, ...) = &syslog;
-static void debuglog __P((int, const char *, ...));
-#else /* _FFR_DEBUG */
-# define msglog syslog
-#endif /* _FFR_DEBUG */
-
+#if defined(__hpux) || defined(__osf__)
+# ifndef SM_CONF_SYSLOG_INT
+# define SM_CONF_SYSLOG_INT 1
+# endif /* SM_CONF_SYSLOG_INT */
+#endif /* defined(__hpux) || defined(__osf__) */
+
+#if SM_CONF_SYSLOG_INT
+# define SYSLOG_RET_T int
+# define SYSLOG_RET return 0
+#else /* SM_CONF_SYSLOG_INT */
+# define SYSLOG_RET_T void
+# define SYSLOG_RET
+#endif /* SM_CONF_SYSLOG_INT */
+
+typedef SYSLOG_RET_T SYSLOG_T __P((int, const char *, ...));
+SYSLOG_T *msglog = syslog;
+static SYSLOG_RET_T debuglog __P((int, const char *, ...));
static void eatmsg __P((void));
+static void listdb __P((void));
/* exit after reading input */
-#define EXITIT(excode) { \
- eatmsg(); \
- return excode; \
- }
+#define EXITIT(excode) \
+{ \
+ eatmsg(); \
+ return excode; \
+}
+
+#define EXITM(excode) \
+{ \
+ if (!iflag && !lflag) \
+ eatmsg(); \
+ exit(excode); \
+}
int
main(argc, argv)
int argc;
char **argv;
{
- bool iflag, emptysender, exclude;
-#if _FFR_BLACKBOX
- bool runasuser = FALSE;
-#endif /* _FFR_BLACKBOX */
-#if _FFR_LISTDB
- bool lflag = FALSE;
-#endif /* _FFR_LISTDB */
+ bool iflag, exclude;
+ bool runasuser = false;
+ bool lflag = false;
int mfail = 0, ufail = 0;
int ch;
int result;
@@ -136,7 +130,9 @@ main(argc, argv)
ALIAS *cur;
char *dbfilename = NULL;
char *msgfilename = NULL;
+ char *cfpath = NULL;
char *name;
+ char *returnaddr = NULL;
SMDB_USER_INFO user_info;
static char rnamebuf[MAXNAME];
extern int optind, opterr;
@@ -146,21 +142,8 @@ main(argc, argv)
extern int readheaders __P((void));
extern bool recent __P((void));
extern void setreply __P((char *, time_t));
- extern void sendmessage __P((char *, char *, bool));
- extern void xclude __P((FILE *));
-#if _FFR_LISTDB
-#define EXITM(excode) { \
- if (!iflag && !lflag) \
- eatmsg(); \
- exit(excode); \
- }
-#else /* _FFR_LISTDB */
-#define EXITM(excode) { \
- if (!iflag) \
- eatmsg(); \
- exit(excode); \
- }
-#endif /* _FFR_LISTDB */
+ extern void sendmessage __P((char *, char *, char *));
+ extern void xclude __P((SM_FILE_T *));
/* Vars needed to link with smutil */
clrbitmap(DontBlameSendmail);
@@ -171,11 +154,11 @@ main(argc, argv)
{
if (strlen(pw->pw_name) > MAXNAME - 1)
pw->pw_name[MAXNAME] = '\0';
- snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
+ sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
}
else
- snprintf(rnamebuf, sizeof rnamebuf,
- "Unknown UID %d", (int) RealUid);
+ sm_snprintf(rnamebuf, sizeof rnamebuf,
+ "Unknown UID %d", (int) RealUid);
RunAsUserName = RealUserName = rnamebuf;
# ifdef LOG_MAIL
@@ -185,13 +168,17 @@ main(argc, argv)
# endif /* LOG_MAIL */
opterr = 0;
- iflag = FALSE;
- emptysender = FALSE;
- exclude = FALSE;
+ iflag = false;
+ exclude = false;
interval = INTERVAL_UNDEF;
*From = '\0';
-#define OPTIONS "a:df:Iilm:r:s:t:Uxz"
+
+#if _FFR_RETURN_ADDR
+# define OPTIONS "a:C:df:Iilm:R:r:s:t:Uxz"
+#else /* _FFR_RETURN_ADDR */
+# define OPTIONS "a:C:df:Iilm:r:s:t:Uxz"
+#endif /* _FFR_RETURN_ADDR */
while (mfail == 0 && ufail == 0 &&
(ch = getopt(argc, argv, OPTIONS)) != -1)
@@ -199,7 +186,7 @@ main(argc, argv)
switch((char)ch)
{
case 'a': /* alias */
- cur = (ALIAS *)malloc((u_int)sizeof(ALIAS));
+ cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS));
if (cur == NULL)
{
mfail++;
@@ -210,11 +197,13 @@ main(argc, argv)
Names = cur;
break;
-#if _FFR_DEBUG
+ case 'C':
+ cfpath = optarg;
+ break;
+
case 'd': /* debug mode */
- msglog = &debuglog;
+ msglog = debuglog;
break;
-#endif /* _FFR_DEBUG */
case 'f': /* alternate database */
dbfilename = optarg;
@@ -222,19 +211,23 @@ main(argc, argv)
case 'I': /* backward compatible */
case 'i': /* init the database */
- iflag = TRUE;
+ iflag = true;
break;
-#if _FFR_LISTDB
case 'l':
- lflag = TRUE; /* list the database */
+ lflag = true; /* list the database */
break;
-#endif /* _FFR_LISTDB */
case 'm': /* alternate message file */
msgfilename = optarg;
break;
+#if _FFR_RETURN_ADDR
+ case 'R':
+ returnaddr = optarg;
+ break;
+#endif /* _FFR_RETURN_ADDR */
+
case 'r':
if (isascii(*optarg) && isdigit(*optarg))
{
@@ -247,24 +240,22 @@ main(argc, argv)
break;
case 's': /* alternate sender name */
- (void) strlcpy(From, optarg, sizeof From);
+ (void) sm_strlcpy(From, optarg, sizeof From);
break;
case 't': /* SunOS: -t1d (default expire) */
break;
-#if _FFR_BLACKBOX
case 'U': /* run as single user mode */
- runasuser = TRUE;
+ runasuser = true;
break;
-#endif /* _FFR_BLACKBOX */
case 'x':
- exclude = TRUE;
+ exclude = true;
break;
case 'z':
- emptysender = TRUE;
+ returnaddr = "<>";
break;
case '?':
@@ -287,11 +278,7 @@ main(argc, argv)
if (argc != 1)
{
- if (!iflag &&
-#if _FFR_LISTDB
- !lflag &&
-#endif /* _FFR_LISTDB */
- !exclude)
+ if (!iflag && !lflag && !exclude)
usage();
if ((pw = getpwuid(getuid())) == NULL)
{
@@ -302,16 +289,16 @@ main(argc, argv)
name = pw->pw_name;
user_info.smdbu_id = pw->pw_uid;
user_info.smdbu_group_id = pw->pw_gid;
- (void) strlcpy(user_info.smdbu_name, pw->pw_name,
- SMDB_MAX_USER_NAME_LEN);
+ (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name,
+ SMDB_MAX_USER_NAME_LEN);
if (chdir(pw->pw_dir) != 0)
{
- msglog(LOG_NOTICE, "vacation: no such directory %s.\n",
+ msglog(LOG_NOTICE,
+ "vacation: no such directory %s.\n",
pw->pw_dir);
EXITM(EX_NOINPUT);
}
}
-#if _FFR_BLACKBOX
else if (runasuser)
{
name = *argv;
@@ -323,27 +310,51 @@ main(argc, argv)
}
user_info.smdbu_id = pw->pw_uid;
user_info.smdbu_group_id = pw->pw_gid;
- (void) strlcpy(user_info.smdbu_name, pw->pw_name,
+ (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name,
SMDB_MAX_USER_NAME_LEN);
}
-#endif /* _FFR_BLACKBOX */
- else if ((pw = getpwnam(*argv)) == NULL)
- {
- msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
- EXITM(EX_NOUSER);
- }
else
{
- name = pw->pw_name;
- if (chdir(pw->pw_dir) != 0)
+ int err;
+ SM_CF_OPT_T mbdbname;
+ SM_MBDB_T user;
+
+ cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
+ mbdbname.opt_name = "MailboxDatabase";
+ mbdbname.opt_val = "pw";
+ (void) sm_cf_getopt(cfpath, 1, &mbdbname);
+ err = sm_mbdb_initialize(mbdbname.opt_val);
+ if (err != EX_OK)
{
- msglog(LOG_NOTICE, "vacation: no such directory %s.\n",
- pw->pw_dir);
+ msglog(LOG_ERR,
+ "vacation: can't open mailbox database: %s.\n",
+ sm_strexit(err));
+ EXITM(err);
+ }
+ err = sm_mbdb_lookup(*argv, &user);
+ if (err == EX_NOUSER)
+ {
+ msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
+ EXITM(EX_NOUSER);
+ }
+ if (err != EX_OK)
+ {
+ msglog(LOG_ERR,
+ "vacation: can't read mailbox database: %s.\n",
+ sm_strexit(err));
+ EXITM(err);
+ }
+ name = user.mbdb_name;
+ if (chdir(user.mbdb_homedir) != 0)
+ {
+ msglog(LOG_NOTICE,
+ "vacation: no such directory %s.\n",
+ user.mbdb_homedir);
EXITM(EX_NOINPUT);
}
- user_info.smdbu_id = pw->pw_uid;
- user_info.smdbu_group_id = pw->pw_gid;
- (void) strlcpy(user_info.smdbu_name, pw->pw_name,
+ user_info.smdbu_id = user.mbdb_uid;
+ user_info.smdbu_group_id = user.mbdb_gid;
+ (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name,
SMDB_MAX_USER_NAME_LEN);
}
@@ -353,14 +364,12 @@ main(argc, argv)
msgfilename = VMSG;
sff = SFF_CREAT;
-#if _FFR_BLACKBOX
if (getegid() != getgid())
{
- /* Allow a set-group-id vacation binary */
+ /* Allow a set-group-ID vacation binary */
RunAsGid = user_info.smdbu_group_id = getegid();
- sff |= SFF_NOPATHCHECK|SFF_OPENASROOT;
+ sff |= SFF_OPENASROOT;
}
-#endif /* _FFR_BLACKBOX */
result = smdb_open_database(&Db, dbfilename,
O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),
@@ -369,20 +378,16 @@ main(argc, argv)
if (result != SMDBE_OK)
{
msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename,
- errstring(result));
+ sm_errstring(result));
EXITM(EX_DATAERR);
}
-#if _FFR_LISTDB
if (lflag)
{
- static void listdb __P((void));
-
listdb();
(void) Db->smdb_close(Db);
exit(EX_OK);
}
-#endif /* _FFR_LISTDB */
if (interval != INTERVAL_UNDEF)
setinterval(interval);
@@ -395,12 +400,12 @@ main(argc, argv)
if (exclude)
{
- xclude(stdin);
+ xclude(smioin);
(void) Db->smdb_close(Db);
EXITM(EX_OK);
}
- if ((cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))) == NULL)
+ if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL)
{
msglog(LOG_NOTICE,
"vacation: can't allocate memory for username.\n");
@@ -419,7 +424,7 @@ main(argc, argv)
(void) time(&now);
setreply(From, now);
(void) Db->smdb_close(Db);
- sendmessage(name, msgfilename, emptysender);
+ sendmessage(name, msgfilename, returnaddr);
}
else
(void) Db->smdb_close(Db);
@@ -474,16 +479,17 @@ readheaders()
extern bool junkmail __P((char *));
extern bool nsearch __P((char *, char *));
- cont = tome = FALSE;
- while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
+ cont = tome = false;
+ while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) &&
+ *buf != '\n')
{
switch(*buf)
{
case 'F': /* "From " */
- cont = FALSE;
+ cont = false;
if (strncmp(buf, "From ", 5) == 0)
{
- bool quoted = FALSE;
+ bool quoted = false;
p = buf + 5;
while (*p != '\0')
@@ -517,8 +523,8 @@ readheaders()
/* ok since both strings have MAXLINE length */
if (*From == '\0')
- (void) strlcpy(From, buf + 5,
- sizeof From);
+ (void) sm_strlcpy(From, buf + 5,
+ sizeof From);
if ((p = strchr(buf + 5, '\n')) != NULL)
*p = '\0';
if (junkmail(buf + 5))
@@ -528,7 +534,7 @@ readheaders()
case 'P': /* "Precedence:" */
case 'p':
- cont = FALSE;
+ cont = false;
if (strlen(buf) <= 10 ||
strncasecmp(buf, "Precedence", 10) != 0 ||
(buf[10] != ':' && buf[10] != ' ' &&
@@ -549,20 +555,20 @@ readheaders()
case 'c':
if (strncasecmp(buf, "Cc:", 3) != 0)
break;
- cont = TRUE;
+ cont = true;
goto findme;
case 'T': /* "To:" */
case 't':
if (strncasecmp(buf, "To:", 3) != 0)
break;
- cont = TRUE;
+ cont = true;
goto findme;
default:
if (!isascii(*buf) || !isspace(*buf) || !cont || tome)
{
- cont = FALSE;
+ cont = false;
break;
}
findme:
@@ -619,9 +625,9 @@ nsearch(name, str)
strncasecmp(name, s, len) == 0 &&
(s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) &&
(!isascii(*(s + len)) || !isalnum(*(s + len))))
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -689,7 +695,7 @@ junkmail(from)
** From site!site!SENDER%site.domain%site.domain@site.domain
*/
- quot = FALSE;
+ quot = false;
e = from;
len = 0;
while (*e != '\0' && (quot || !isdelim(*e)))
@@ -728,10 +734,10 @@ junkmail(from)
sender[MAX_USER_LEN - 1] = '\0';
if (len <= 0)
- return FALSE;
+ return false;
#if 0
if (quot)
- return FALSE; /* syntax error... */
+ return false; /* syntax error... */
#endif /* 0 */
/* test prefixes */
@@ -739,7 +745,7 @@ junkmail(from)
{
if (len >= cur->len &&
strncasecmp(cur->name, sender, cur->len) == 0)
- return TRUE;
+ return true;
}
/*
@@ -752,14 +758,14 @@ junkmail(from)
*/
if (len > MAX_USER_LEN)
- return FALSE;
+ return false;
/* test full local parts */
for (cur = ignore; cur->name != NULL; ++cur)
{
if (len == cur->len &&
strncasecmp(cur->name, sender, cur->len) == 0)
- return TRUE;
+ return true;
}
/* test postfixes */
@@ -768,9 +774,9 @@ junkmail(from)
if (len >= cur->len &&
strncasecmp(cur->name, e - cur->len - 1,
cur->len) == 0)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
#define VIT "__VACATION__INTERVAL__TIMER__"
@@ -783,7 +789,7 @@ junkmail(from)
** none.
**
** Returns:
-** TRUE iff user has gotten a vacation message recently.
+** true iff user has gotten a vacation message recently.
**
*/
@@ -792,7 +798,7 @@ recent()
{
SMDB_DBENT key, data;
time_t then, next;
- bool trydomain = FALSE;
+ bool trydomain = false;
int st;
char *domain;
@@ -823,7 +829,7 @@ recent()
memmove(&then, data.data, sizeof(then));
if (next == ONLY_ONCE || then == ONLY_ONCE ||
then + next > time(NULL))
- return TRUE;
+ return true;
}
if ((trydomain = !trydomain) &&
(domain = strchr(From, '@')) != NULL)
@@ -832,7 +838,7 @@ recent()
key.size = strlen(domain);
}
} while (trydomain);
- return FALSE;
+ return false;
}
/*
@@ -913,13 +919,13 @@ setreply(from, when)
void
xclude(f)
- FILE *f;
+ SM_FILE_T *f;
{
char buf[MAXLINE], *p;
if (f == NULL)
return;
- while (fgets(buf, sizeof buf, f))
+ while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf))
{
if ((p = strchr(buf, '\n')) != NULL)
*p = '\0';
@@ -934,7 +940,7 @@ xclude(f)
** Parameters:
** myname -- user name.
** msgfn -- name of file with vacation message.
-** emptysender -- use <> as sender address?
+** sender -- use as sender address
**
** Returns:
** nothing.
@@ -944,18 +950,18 @@ xclude(f)
*/
void
-sendmessage(myname, msgfn, emptysender)
+sendmessage(myname, msgfn, sender)
char *myname;
char *msgfn;
- bool emptysender;
+ char *sender;
{
- FILE *mfp, *sfp;
+ SM_FILE_T *mfp, *sfp;
int i;
int pvect[2];
char *pv[8];
char buf[MAXLINE];
- mfp = fopen(msgfn, "r");
+ mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL);
if (mfp == NULL)
{
if (msgfn[0] == '/')
@@ -967,14 +973,14 @@ sendmessage(myname, msgfn, emptysender)
}
if (pipe(pvect) < 0)
{
- msglog(LOG_ERR, "vacation: pipe: %s", errstring(errno));
+ msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno));
exit(EX_OSERR);
}
pv[0] = "sendmail";
pv[1] = "-oi";
pv[2] = "-f";
- if (emptysender)
- pv[3] = "<>";
+ if (sender != NULL)
+ pv[3] = sender;
else
pv[3] = myname;
pv[4] = "--";
@@ -983,7 +989,7 @@ sendmessage(myname, msgfn, emptysender)
i = fork();
if (i < 0)
{
- msglog(LOG_ERR, "vacation: fork: %s", errstring(errno));
+ msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno));
exit(EX_OSERR);
}
if (i == 0)
@@ -991,26 +997,29 @@ sendmessage(myname, msgfn, emptysender)
(void) dup2(pvect[0], 0);
(void) close(pvect[0]);
(void) close(pvect[1]);
- (void) fclose(mfp);
+ (void) sm_io_close(mfp, SM_TIME_DEFAULT);
(void) execv(_PATH_SENDMAIL, pv);
msglog(LOG_ERR, "vacation: can't exec %s: %s",
- _PATH_SENDMAIL, errstring(errno));
+ _PATH_SENDMAIL, sm_errstring(errno));
exit(EX_UNAVAILABLE);
}
/* check return status of the following calls? XXX */
(void) close(pvect[0]);
- if ((sfp = fdopen(pvect[1], "w")) != NULL)
+ if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
+ (void *) &(pvect[1]),
+ SM_IO_WRONLY, NULL)) != NULL)
{
- (void) fprintf(sfp, "To: %s\n", From);
- (void) fprintf(sfp, "Auto-Submitted: auto-generated\n");
- while (fgets(buf, sizeof buf, mfp))
- (void) fputs(buf, sfp);
- (void) fclose(mfp);
- (void) fclose(sfp);
+ (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From);
+ (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT,
+ "Auto-Submitted: auto-replied\n");
+ while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf))
+ (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf);
+ (void) sm_io_close(mfp, SM_TIME_DEFAULT);
+ (void) sm_io_close(sfp, SM_TIME_DEFAULT);
}
else
{
- (void) fclose(mfp);
+ (void) sm_io_close(mfp, SM_TIME_DEFAULT);
msglog(LOG_ERR, "vacation: can't open pipe to sendmail");
exit(EX_UNAVAILABLE);
}
@@ -1019,29 +1028,20 @@ sendmessage(myname, msgfn, emptysender)
void
usage()
{
+ char *retusage;
+
+#if _FFR_RETURN_ADDR
+ retusage = "[-R returnaddr] ";
+#else /* _FFR_RETURN_ADDR */
+ retusage = "";
+#endif /* _FFR_RETURN_ADDR */
+
msglog(LOG_NOTICE,
- "uid %u: usage: vacation [-a alias]%s [-f db] [-i]%s [-m msg] [-r interval] [-s sender] [-t time]%s [-x] [-z] login\n",
- getuid(),
-#if _FFR_DEBUG
- " [-d]",
-#else /* _FFR_DEBUG */
- "",
-#endif /* _FFR_DEBUG */
-#if _FFR_LISTDB
- " [-l]",
-#else /* _FFR_LISTDB */
- "",
-#endif /* _FFR_LISTDB */
-#if _FFR_BLACKBOX
- " [-U]"
-#else /* _FFR_BLACKBOX */
- ""
-#endif /* _FFR_BLACKBOX */
- );
+ "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] [-l] [-m msg] %s[-r interval] [-s sender] [-t time] [-U] [-x] [-z] login\n",
+ getuid(), retusage);
exit(EX_USAGE);
}
-#if _FFR_LISTDB
/*
** LISTDB -- list the contents of the vacation database
**
@@ -1066,8 +1066,9 @@ listdb()
result = Db->smdb_cursor(Db, &cursor, 0);
if (result != SMDBE_OK)
{
- fprintf(stderr, "vacation: set cursor: %s\n",
- errstring(result));
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "vacation: set cursor: %s\n",
+ sm_errstring(result));
return;
}
@@ -1075,7 +1076,7 @@ listdb()
SMDB_CURSOR_GET_NEXT)) == SMDBE_OK)
{
/* skip magic VIT entry */
- if ((int)db_key.size -1 == strlen(VIT) &&
+ if ((int)db_key.size - 1 == strlen(VIT) &&
strncmp((char *)db_key.data, VIT,
(int)db_key.size - 1) == 0)
continue;
@@ -1083,8 +1084,9 @@ listdb()
/* skip bogus values */
if (db_value.size != sizeof t)
{
- fprintf(stderr, "vacation: %.*s invalid time stamp\n",
- (int) db_key.size, (char *) db_key.data);
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "vacation: %.*s invalid time stamp\n",
+ (int) db_key.size, (char *) db_key.data);
continue;
}
@@ -1093,8 +1095,9 @@ listdb()
if (db_key.size > 40)
db_key.size = 40;
- printf("%-40.*s %-10s",
- (int) db_key.size, (char *) db_key.data, ctime(&t));
+ sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s",
+ (int) db_key.size, (char *) db_key.data,
+ ctime(&t));
memset(&db_key, '\0', sizeof db_key);
memset(&db_value, '\0', sizeof db_value);
@@ -1102,8 +1105,9 @@ listdb()
if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
{
- fprintf(stderr, "vacation: get value at cursor: %s\n",
- errstring(result));
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "vacation: get value at cursor: %s\n",
+ sm_errstring(result));
if (cursor != NULL)
{
(void) cursor->smdbc_close(cursor);
@@ -1114,9 +1118,7 @@ listdb()
(void) cursor->smdbc_close(cursor);
cursor = NULL;
}
-#endif /* _FFR_LISTDB */
-#if _FFR_DEBUG
/*
** DEBUGLOG -- write message to standard error
**
@@ -1132,7 +1134,7 @@ listdb()
*/
/*VARARGS2*/
-static void
+static SYSLOG_RET_T
#ifdef __STDC__
debuglog(int i, const char *fmt, ...)
#else /* __STDC__ */
@@ -1143,67 +1145,10 @@ debuglog(i, fmt, va_alist)
#endif /* __STDC__ */
{
- VA_LOCAL_DECL
-
- VA_START(fmt);
- vfprintf(stderr, fmt, ap);
- VA_END;
-}
-#endif /* _FFR_DEBUG */
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-message(const char *msg, ...)
-#else /* __STDC__ */
-message(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-syserr(const char *msg, ...)
-#else /* __STDC__ */
-syserr(msg, va_alist)
- const char *msg;
- va_dcl
-#endif /* __STDC__ */
-{
- const char *m;
- VA_LOCAL_DECL
-
- m = msg;
- if (isascii(m[0]) && isdigit(m[0]) &&
- isascii(m[1]) && isdigit(m[1]) &&
- isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
- m += 4;
- VA_START(msg);
- (void) vfprintf(stderr, m, ap);
- VA_END;
- (void) fprintf(stderr, "\n");
-}
+ SM_VA_LOCAL_DECL
-void
-dumpfd(fd, printclosed, logit)
- int fd;
- bool printclosed;
- bool logit;
-{
- return;
+ SM_VA_START(ap, fmt);
+ sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap);
+ SM_VA_END(ap);
+ SYSLOG_RET;
}
OpenPOWER on IntegriCloud