1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 #ifdef USERDB 11 static char sccsid [] = "@(#)udb.c 5.13 (Berkeley) 12/12/91 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 5.13 (Berkeley) 12/12/91 (without USERDB)"; 14 #endif 15 #endif 16 17 #include "sendmail.h" 18 19 #ifdef USERDB 20 21 #include <sys/file.h> 22 #include <sys/time.h> 23 #include <fcntl.h> 24 #include <netdb.h> 25 #include <db.h> 26 27 /* 28 ** UDBEXPAND.C -- interface between sendmail and Berkeley User Data Base. 29 ** 30 ** This depends on the 4.4BSD db package. 31 */ 32 33 34 struct udbent 35 { 36 char *udb_spec; /* string version of spec */ 37 int udb_type; /* type of entry */ 38 union 39 { 40 /* type UE_REMOTE -- do remote call for lookup */ 41 struct 42 { 43 struct sockaddr_in _udb_addr; /* address */ 44 int _udb_timeout; /* timeout */ 45 } udb_remote; 46 #define udb_addr udb_u.udb_remote._udb_addr 47 #define udb_timeout udb_u.udb_remote._udb_timeout 48 49 /* type UE_FORWARD -- forward message to remote */ 50 struct 51 { 52 char *_udb_fwdhost; /* name of forward host */ 53 } udb_forward; 54 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 55 56 /* type UE_LOOKUP -- lookup in local database */ 57 struct 58 { 59 char *_udb_dbname; /* pathname of database */ 60 DB *_udb_dbp; /* open database ptr */ 61 } udb_lookup; 62 #define udb_dbname udb_u.udb_lookup._udb_dbname 63 #define udb_dbp udb_u.udb_lookup._udb_dbp 64 } udb_u; 65 }; 66 67 #define UDB_EOLIST 0 /* end of list */ 68 #define UDB_SKIP 1 /* skip this entry */ 69 #define UDB_REMOTE 2 /* look up in remote database */ 70 #define UDB_LOOKUP 3 /* look up in local database */ 71 #define UDB_FORWARD 4 /* forward to remote host */ 72 73 #define MAXUDBENT 10 /* maximum number of UDB entries */ 74 75 76 struct option 77 { 78 char *name; 79 char *val; 80 }; 81 /* 82 ** UDBEXPAND -- look up user in database and expand 83 ** 84 ** Parameters: 85 ** a -- address to expand. 86 ** sendq -- pointer to head of sendq to put the expansions in. 87 ** 88 ** Returns: 89 ** none. 90 ** 91 ** Side Effects: 92 ** Modifies sendq. 93 */ 94 95 int UdbPort = 1616; 96 int UdbTimeout = 10; 97 98 struct udbent UdbEnts[MAXUDBENT + 1]; 99 int UdbSock = -1; 100 101 void 102 udbexpand(a, sendq) 103 register ADDRESS *a; 104 ADDRESS **sendq; 105 { 106 int i; 107 register char *p; 108 DBT key; 109 DBT info; 110 static bool firstcall = TRUE; 111 bool breakout; 112 register struct udbent *up; 113 int keylen; 114 char keybuf[128]; 115 char buf[8192]; 116 117 if (tTd(28, 1)) 118 printf("expand(%s)\n", a->q_paddr); 119 120 /* make certain we are supposed to send to this address */ 121 if (bitset(QDONTSEND, a->q_flags)) 122 return; 123 CurEnv->e_to = a->q_paddr; 124 125 /* on first call, locate the database */ 126 if (firstcall) 127 { 128 extern void _udbx_init(); 129 130 _udbx_init(); 131 firstcall = FALSE; 132 } 133 134 /* short circuit the process if no chance of a match */ 135 if (UdbSpec == NULL || UdbSpec[0] == '\0') 136 return; 137 138 /* if name is too long, assume it won't match */ 139 if (strlen(a->q_user) > sizeof keybuf - 12) 140 return; 141 142 /* if name begins with a colon, it indicates our metadata */ 143 if (a->q_user[0] == ':') 144 return; 145 146 /* build actual database key */ 147 (void) strcpy(keybuf, a->q_user); 148 (void) strcat(keybuf, ":maildrop"); 149 keylen = strlen(keybuf); 150 151 breakout = FALSE; 152 for (up = UdbEnts; !breakout; up++) 153 { 154 char *user; 155 struct timeval timeout; 156 fd_set fdset; 157 158 /* 159 ** Select action based on entry type. 160 ** 161 ** On dropping out of this switch, "class" should 162 ** explain the type of the data, and "user" should 163 ** contain the user information. 164 */ 165 166 switch (up->udb_type) 167 { 168 case UDB_LOOKUP: 169 key.data = keybuf; 170 key.size = keylen; 171 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 172 if (i != 0 || info.size <= 0) 173 { 174 if (i < 0) 175 syserr("udbexpand: db-get stat %s"); 176 if (tTd(28, 2)) 177 printf("expand: no match on %s\n", keybuf); 178 continue; 179 } 180 181 while (i == 0 && key.size == keylen && 182 bcmp(key.data, keybuf, keylen) == 0) 183 { 184 breakout = TRUE; 185 if (info.size < sizeof buf) 186 user = buf; 187 else 188 user = xalloc(info.size + 1); 189 bcopy(info.data, user, info.size); 190 user[info.size] = '\0'; 191 192 message(Arpa_Info, "expanded to %s", user); 193 AliasLevel++; 194 sendtolist(user, a, sendq); 195 AliasLevel--; 196 197 if (user != buf) 198 free(user); 199 200 /* get the next record */ 201 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 202 } 203 break; 204 205 case UDB_REMOTE: 206 /* not yet implemented */ 207 continue; 208 209 case UDB_FORWARD: 210 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 211 if (i < sizeof buf) 212 user = buf; 213 else 214 user = xalloc(i + 1); 215 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 216 message(Arpa_Info, "expanded to %s", user); 217 AliasLevel++; 218 sendtolist(user, a, sendq); 219 AliasLevel--; 220 if (user != buf) 221 free(user); 222 breakout = TRUE; 223 break; 224 225 case UDB_EOLIST: 226 breakout = TRUE; 227 continue; 228 229 default: 230 /* unknown entry type */ 231 continue; 232 } 233 } 234 } 235 236 #define MAXUDBOPTS 27 237 238 void 239 _udbx_init() 240 { 241 register char *p; 242 int i; 243 register struct udbent *up; 244 char buf[8192]; 245 246 # ifdef UDB_DEFAULT_SPEC 247 if (UdbSpec == NULL) 248 UdbSpec = UDB_DEFAULT_SPEC; 249 # endif 250 251 p = UdbSpec; 252 up = UdbEnts; 253 while (p != NULL) 254 { 255 char *spec; 256 auto int rcode; 257 int nopts; 258 int nmx; 259 register struct hostent *h; 260 char *mxhosts[MAXMXHOSTS + 1]; 261 struct option opts[MAXUDBOPTS + 1]; 262 263 while (*p == ' ' || *p == '\t' || *p == ',') 264 p++; 265 if (*p == '\0') 266 break; 267 spec = p; 268 p = index(p, ','); 269 if (p != NULL) 270 *p++ = '\0'; 271 272 /* extract options */ 273 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 274 275 /* 276 ** Decode database specification. 277 ** 278 ** In the sendmail tradition, the leading character 279 ** defines the semantics of the rest of the entry. 280 ** 281 ** +hostname -- send a datagram to the udb server 282 ** on host "hostname" asking for the 283 ** home mail server for this user. 284 ** *hostname -- similar to +hostname, except that the 285 ** hostname is searched as an MX record; 286 ** resulting hosts are searched as for 287 ** +mxhostname. If no MX host is found, 288 ** this is the same as +hostname. 289 ** @hostname -- forward email to the indicated host. 290 ** This should be the last in the list, 291 ** since it always matches the input. 292 ** /dbname -- search the named database on the local 293 ** host using the Berkeley db package. 294 */ 295 296 switch (*spec) 297 { 298 case '+': /* search remote database */ 299 case '*': /* search remote database (expand MX) */ 300 if (*spec == '*') 301 { 302 nmx = getmxrr(spec + 1, mxhosts, "", &rcode); 303 if (tTd(28, 16)) 304 { 305 int i; 306 307 printf("getmxrr(%s): %d", spec + 1, nmx); 308 for (i = 0; i <= nmx; i++) 309 printf(" %s", mxhosts[i]); 310 printf("\n"); 311 } 312 } 313 else 314 { 315 nmx = 1; 316 mxhosts[0] = spec + 1; 317 } 318 319 for (i = 0; i < nmx; i++) 320 { 321 h = gethostbyname(mxhosts[i]); 322 if (h == NULL) 323 continue; 324 up->udb_type = UDB_REMOTE; 325 up->udb_addr.sin_family = h->h_addrtype; 326 bcopy(h->h_addr_list[0], 327 (char *) &up->udb_addr.sin_addr, 328 h->h_length); 329 up->udb_addr.sin_port = UdbPort; 330 up->udb_timeout = UdbTimeout; 331 up++; 332 } 333 334 /* set up a datagram socket */ 335 if (UdbSock < 0) 336 { 337 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 338 (void) fcntl(UdbSock, F_SETFD, 1); 339 } 340 break; 341 342 case '@': /* forward to remote host */ 343 up->udb_type = UDB_FORWARD; 344 up->udb_fwdhost = spec + 1; 345 up++; 346 break; 347 348 case '/': /* look up remote name */ 349 up->udb_dbname = spec; 350 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 351 if (up->udb_dbp == NULL) 352 break; 353 up->udb_type = UDB_LOOKUP; 354 up++; 355 break; 356 } 357 } 358 up->udb_type = UDB_EOLIST; 359 360 if (tTd(28, 4)) 361 { 362 for (up = UdbEnts; ; up++) 363 { 364 switch (up->udb_type) 365 { 366 case UDB_EOLIST: 367 return; 368 369 case UDB_REMOTE: 370 printf("REMOTE: addr %s, timeo %d\n", 371 inet_ntoa(up->udb_addr.sin_addr), 372 up->udb_timeout); 373 break; 374 375 case UDB_LOOKUP: 376 printf("LOOKUP: file %s\n", 377 up->udb_dbname); 378 break; 379 380 case UDB_FORWARD: 381 printf("FORWARD: host %s\n", 382 up->udb_fwdhost); 383 break; 384 385 default: 386 printf("UNKNOWN\n"); 387 break; 388 } 389 } 390 } 391 } 392 393 int 394 _udb_parsespec(udbspec, opt, maxopts) 395 char *udbspec; 396 struct option opt[]; 397 int maxopts; 398 { 399 register char *spec; 400 register char *spec_end; 401 register int optnum; 402 403 spec_end = index(udbspec, ':'); 404 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 405 { 406 register char *p; 407 408 while (isspace(*spec)) 409 spec++; 410 spec_end = index(spec, ':'); 411 if (spec_end != NULL) 412 *spec_end++ = '\0'; 413 414 opt[optnum].name = spec; 415 opt[optnum].val = NULL; 416 p = index(spec, '='); 417 if (p != NULL) 418 opt[optnum].val = ++p; 419 } 420 return optnum; 421 } 422 423 #else /* not USERDB */ 424 425 void 426 udbexpand(a, sendq) 427 ADDRESS *a; 428 ADDRESS **sendq; 429 { 430 return; 431 } 432 433 #endif /* USERDB */ 434