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.3 (Berkeley) 10/11/91 (with USERDB)"; 12 #else 13 static char sccsid [] = "@(#)udb.c 5.3 (Berkeley) 10/11/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 -- look up user in database and expand 29 ** 30 ** Parameters: 31 ** a -- address to expand. 32 ** sendq -- pointer to head of sendq to put the expansions in. 33 ** 34 ** Returns: 35 ** none. 36 ** 37 ** Side Effects: 38 ** Modifies sendq. 39 */ 40 41 struct udbent 42 { 43 char *udb_spec; /* string version of spec */ 44 int udb_type; /* type of entry */ 45 union 46 { 47 /* type UE_REMOTE -- do remote call for lookup */ 48 struct 49 { 50 int _udb_addrlen; /* length of addr */ 51 struct sockaddr_in _udb_addr; /* address */ 52 int _udb_timeout; /* timeout */ 53 } udb_remote; 54 #define udb_addrlen udb_u.udb_remote._udb_addrlen 55 #define udb_addr udb_u.udb_remote._udb_addr 56 #define udb_timeout udb_u.udb_remote._udb_timeout 57 58 /* type UE_FORWARD -- forward message to remote */ 59 struct 60 { 61 char *_udb_fwdhost; /* name of forward host */ 62 } udb_forward; 63 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 64 65 /* type UE_LOOKUP -- lookup in local database */ 66 struct 67 { 68 char *_udb_dbname; /* pathname of database */ 69 DB *_udb_dbp; /* open database ptr */ 70 } udb_lookup; 71 #define udb_dbname udb_u.udb_lookup._udb_dbname 72 #define udb_dbp udb_u.udb_lookup._udb_dbp 73 } udb_u; 74 }; 75 76 #define UDB_EOLIST 0 /* end of list */ 77 #define UDB_SKIP 1 /* skip this entry */ 78 #define UDB_REMOTE 2 /* look up in remote database */ 79 #define UDB_LOOKUP 3 /* look up in local database */ 80 #define UDB_FORWARD 4 /* forward to remote host */ 81 82 #define MAXUDBENT 10 /* maximum number of UDB entries */ 83 84 85 void 86 udbexpand(a, sendq) 87 register ADDRESS *a; 88 ADDRESS **sendq; 89 { 90 int i; 91 register char *p; 92 auto char *class; 93 auto char *list; 94 DBT key; 95 DBT info; 96 register char *bp; 97 static bool firstcall = TRUE; 98 static int udbsock = -1; 99 bool breakout; 100 register struct udbent *up; 101 struct udbent udbents[MAXUDBENT + 1]; 102 char buf[8192]; 103 104 if (tTd(28, 1)) 105 printf("expand(%s)\n", a->q_paddr); 106 107 /* make certain we are supposed to send to this address */ 108 if (bitset(QDONTSEND, a->q_flags) || 109 UdbSpec == NULL || UdbSpec[0] == '\0') 110 return; 111 CurEnv->e_to = a->q_paddr; 112 113 /* on first call, locate the database */ 114 if (firstcall) 115 { 116 firstcall = FALSE; 117 p = UdbSpec; 118 up = udbents; 119 for (;;) 120 { 121 char *spec; 122 auto int rcode; 123 int nmx; 124 char *mxhosts[MAXMXHOSTS + 1]; 125 126 while (*p == ' ' || *p == '\t' || *p == ',') 127 p++; 128 if (*p == '\0') 129 break; 130 spec = p; 131 p = index(p, ','); 132 if (*p != '\0') 133 *p++ = '\0'; 134 switch (*spec) 135 { 136 case '*': /* search remote database */ 137 expand("\001j", buf, &buf[sizeof(buf) - 1], CurEnv); 138 nmx = getmxrr(spec + 1, mxhosts, buf, &rcode); 139 for (i = 0; i < nmx; i++) 140 { 141 register struct hostent *h; 142 143 h = gethostbyname(mxhosts[i]); 144 if (h == NULL) 145 continue; 146 up->udb_type = UDB_REMOTE; 147 up->udb_addr.sin_family = h->h_addrtype; 148 up->udb_addrlen = h->h_length; 149 bcopy(h->h_addr_list[0], 150 (char *) &up->udb_addr.sin_addr, 151 h->h_length); 152 up++; 153 } 154 155 /* set up a datagram socket */ 156 if (udbsock < 0) 157 { 158 udbsock = socket(AF_INET, SOCK_DGRAM, 0); 159 (void) fcntl(udbsock, F_SETFD, 1); 160 } 161 break; 162 163 case '@': /* forward to remote host */ 164 up->udb_type = UDB_FORWARD; 165 up->udb_fwdhost = spec + 1; 166 up++; 167 break; 168 169 case '/': /* look up remote name */ 170 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 171 if (up->udb_dbp == NULL) 172 break; 173 up->udb_type = UDB_LOOKUP; 174 up++; 175 break; 176 } 177 } 178 up->udb_type = UDB_EOLIST; 179 } 180 181 breakout = FALSE; 182 for (up = udbents; !breakout; up++) 183 { 184 char *user; 185 struct timeval timeout; 186 fd_set fdset; 187 188 /* 189 ** Select action based on entry type. 190 ** 191 ** On dropping out of this switch, "class" should 192 ** explain the type of the data, and "user" should 193 ** contain the user information. 194 */ 195 196 switch (up->udb_type) 197 { 198 case UDB_LOOKUP: 199 key.data = a->q_user; 200 key.size = strlen(key.data); 201 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 202 if (i != 0 || info.size <= 0) 203 { 204 if (i < 0) 205 syserr("udbexpand: db-get stat %s"); 206 if (tTd(28, 2)) 207 printf("expand: no match on %s\n", key.data); 208 continue; 209 } 210 211 /* extract the class (first string) and data (second string) */ 212 class = info.data; 213 i = strlen((char *) info.data) + 1; 214 p = (char *) info.data + i; 215 i = info.size - i; 216 217 /* use internal buffer if it will fit; otherwise malloc */ 218 if (i < sizeof buf) 219 user = buf; 220 else 221 user = xalloc(i + 1); 222 bcopy(p, user, i); 223 user[i] = '\0'; 224 break; 225 226 case UDB_REMOTE: 227 if (sendto(udbsock, a->q_user, strlen(a->q_user), 0, 228 (struct sockaddr *) &up->udb_addr, 229 up->udb_addrlen) < 0) 230 { 231 continue; 232 } 233 timeout.tv_sec = up->udb_timeout / 10; 234 timeout.tv_usec = (up->udb_timeout % 10) * 100000; 235 do 236 { 237 FD_ZERO(&fdset); 238 FD_SET(udbsock, &fdset); 239 i = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout); 240 } while (i > 0 && !FD_ISSET(udbsock, &fdset)); 241 if (i <= 0) 242 continue; 243 i = recvfrom(udbsock, buf, sizeof buf - 1, 0, NULL, NULL); 244 if (i < 0) 245 continue; 246 class = buf; 247 user = &buf[strlen(buf)]; 248 buf[i] = '\0'; 249 break; 250 251 case UDB_FORWARD: 252 class = "forward"; 253 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 254 if (i < sizeof buf) 255 user = buf; 256 else 257 user = xalloc(i + 1); 258 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 259 break; 260 261 case UDB_EOLIST: 262 breakout = TRUE; 263 continue; 264 265 default: 266 /* unknown entry type */ 267 continue; 268 } 269 270 if (tTd(28, 1)) 271 printf("Class %s: %s\n", class, user); 272 273 /* do special processing based on class */ 274 if (strcmp(class, "user") == 0 || strcmp(class, "forward") == 0) 275 { 276 message(Arpa_Info, "expanded to (%s) %s", class, user); 277 AliasLevel++; 278 sendtolist(user, a, sendq); 279 AliasLevel--; 280 breakout = TRUE; 281 } 282 283 /* free memory if we allocated it */ 284 if (up->udb_type == UDB_FORWARD || up->udb_type == UDB_LOOKUP) 285 { 286 if (user != buf) 287 free(user); 288 } 289 } 290 } 291 292 #else /* not USERDB */ 293 294 void 295 udbexpand(a, sendq) 296 ADDRESS *a; 297 ADDRESS **sendq; 298 { 299 return; 300 } 301 302 #endif /* USERDB */ 303