1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * mkmap - program to convert the mail.aliases map into an 30 * inverse map of <user@host> back to <preferred-alias> 31 */ 32 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <ndbm.h> 38 #include <stdio.h> 39 #include <ctype.h> 40 #include <netdb.h> 41 #include <sys/systeminfo.h> 42 43 #include "ypdefs.h" 44 USE_YP_PREFIX 45 USE_YP_MASTER_NAME 46 USE_YP_LAST_MODIFIED 47 48 #define MKAL_INCLUDE ":include:" 49 50 void CopyName(char *dst, char *src, int len); 51 int HostCheck(char *h, char *a); 52 void DoName(char *cp); 53 void UpperCase(char *cp); 54 void AddYPEntries(void); 55 56 int Verbose = 0; /* to get the gory details */ 57 int UucpOK = 0; /* pass all UUCP names right through */ 58 int DomainOK = 0; /* pass all Domain names (with dots) */ 59 int ErrorCheck = 0; /* check carefully for errors */ 60 int NoOutput = 0; /* no output, just do the check */ 61 int Simple = 0; /* Do not do the user name preference step */ 62 int NameMode = 0; /* Try to capitalize as names */ 63 64 DBM *Indbm = NULL, *Scandbm = NULL, *Outdbm = NULL; 65 66 int 67 IsMailingList(char *s) 68 { 69 /* 70 * returns true if the given string is a mailing list 71 */ 72 char *p; 73 74 if (strchr(s, ',')) 75 return (1); 76 if (strchr(s, '|')) 77 return (1); 78 p = strchr(s, ':'); 79 if (p && strncmp(p, MKAL_INCLUDE, sizeof (MKAL_INCLUDE))) 80 return (1); 81 return (0); 82 } 83 84 int 85 IsQualified(char *s, char *p, char *h) 86 { 87 /* 88 * returns true if the given string is qualified with a host name 89 */ 90 register char *middle; 91 92 middle = strchr(s, '@'); 93 if (middle) { 94 for (middle = s; *middle != '@'; *p++ = *middle++) 95 continue; 96 *p = '\0'; 97 CopyName(h, middle+1, strlen(middle + 1)); 98 return (1); 99 } 100 middle = strrchr(s, '!'); 101 if (middle) { 102 strcpy(p, middle+1); 103 *middle = '\0'; 104 CopyName(h, s, strlen(s)); 105 *middle = '!'; 106 return (1); 107 } 108 return (0); 109 } 110 111 int 112 IsMaint(char *s) 113 { 114 /* 115 * returns true if the given string is one of the maintenence 116 * strings used in sendmail or NIS. 117 */ 118 if (*s == '@') 119 return (1); 120 if (strncmp(s, yp_prefix, yp_prefix_sz) == 0) 121 return (1); 122 return (0); 123 } 124 125 void 126 CopyName(char *dst, char *src, int len) 127 { 128 /* 129 * copy a string, but ignore white space 130 */ 131 while (*src && len--) { 132 if (isspace(*src)) 133 src++; 134 else 135 *dst++ = *src++; 136 } 137 *dst = '\0'; 138 } 139 140 int 141 Compare(char *s1, char *s2) 142 { 143 /* 144 * compare strings, but ignore white space 145 */ 146 while (*s1 != '\0' && isspace(*s1)) 147 s1++; 148 while (*s2 != '\0' && isspace(*s2)) 149 s2++; 150 return (strcmp(s1, s2)); 151 } 152 153 void 154 ProcessMap(void) 155 { 156 datum key, value, part, partvalue; 157 char address[PBLKSIZ]; /* qualified version */ 158 char user[PBLKSIZ]; /* unqualified version */ 159 char userpart[PBLKSIZ]; /* unqualified part of qualified addr. */ 160 char hostpart[PBLKSIZ]; /* rest of qualified addr. */ 161 162 for (key = dbm_firstkey(Scandbm); key.dptr != NULL; 163 key = dbm_nextkey(Scandbm)) { 164 value = dbm_fetch(Indbm, key); 165 CopyName(address, value.dptr, value.dsize); 166 CopyName(user, key.dptr, key.dsize); 167 if (address == NULL) continue; 168 if (IsMailingList(address)) continue; 169 if (!IsQualified(address, userpart, hostpart)) continue; 170 if (IsMaint(user)) continue; 171 if (ErrorCheck && HostCheck(hostpart, address)) { 172 printf("Invalid host %s in %s:%s\n", 173 hostpart, user, address); 174 continue; 175 } 176 part.dptr = userpart; 177 part.dsize = strlen(userpart) + 1; 178 if (Simple) 179 partvalue.dptr = NULL; 180 else 181 partvalue = dbm_fetch(Indbm, part); 182 value.dptr = address; 183 value.dsize = strlen(address) + 1; 184 if (partvalue.dptr != NULL && 185 Compare(partvalue.dptr, user) == 0) { 186 187 if (NameMode) 188 DoName(userpart); 189 if (!NoOutput) 190 dbm_store(Outdbm, value, part, DBM_REPLACE); 191 if (Verbose) printf("%s --> %s --> %s\n", 192 userpart, user, address); 193 } else { 194 if (NameMode) 195 DoName(user); 196 key.dptr = user; 197 key.dsize = strlen(user) + 1; 198 if (!NoOutput) 199 dbm_store(Outdbm, value, key, DBM_REPLACE); 200 if (Verbose) 201 printf("%s --> %s\n", user, address); 202 } 203 } 204 } 205 206 207 /* 208 * Returns true if this is an invalid host 209 */ 210 int 211 HostCheck(char *h, char *a) 212 { 213 struct hostent *hp; 214 215 if (DomainOK && strchr(a, '.')) 216 return (0); 217 218 if (UucpOK && strchr(a, '!')) 219 return (0); 220 221 hp = gethostbyname(h); 222 return (hp == NULL); 223 } 224 225 /* 226 * Apply some Heurisitcs to upper case-ify the name 227 * If it has a dot in it. 228 */ 229 void 230 DoName(char *cp) 231 { 232 if (strchr(cp, '.') == NULL) 233 return; 234 235 while (*cp) { 236 UpperCase(cp); 237 while (*cp && *cp != '-' && *cp != '.') 238 cp++; 239 if (*cp) 240 cp++; /* skip past punctuation */ 241 } 242 } 243 244 /* 245 * upper cases one name - stops at a . 246 */ 247 void 248 UpperCase(char *cp) 249 { 250 int ch = cp[0]; 251 252 if (isupper(ch)) 253 ch = tolower(ch); 254 255 if (ch == 'f' && cp[1] == 'f') 256 return; /* handle ff */ 257 258 if (ch == 'm' && cp[1] == 'c' && islower(cp[2])) 259 cp[2] = toupper(cp[2]); 260 if (islower(ch)) 261 cp[0] = toupper(ch); 262 } 263 264 void 265 AddYPEntries(void) 266 { 267 datum key, value; 268 char last_modified[PBLKSIZ]; 269 char host_name[PBLKSIZ]; 270 time_t now; 271 272 /* 273 * Add the special NIS entries. 274 */ 275 key.dptr = yp_last_modified; 276 key.dsize = yp_last_modified_sz; 277 time(&now); 278 sprintf(last_modified, "%10.10d", now); 279 value.dptr = last_modified; 280 value.dsize = strlen(value.dptr); 281 dbm_store(Outdbm, key, value, DBM_REPLACE); 282 283 key.dptr = yp_master_name; 284 key.dsize = yp_master_name_sz; 285 sysinfo(SI_HOSTNAME, host_name, sizeof (host_name)); 286 value.dptr = host_name; 287 value.dsize = strlen(value.dptr); 288 dbm_store(Outdbm, key, value, DBM_REPLACE); 289 } 290 291 int 292 main(int argc, char *argv[]) 293 { 294 while (argc > 1 && argv[1][0] == '-') { 295 switch (argv[1][1]) { 296 case 'v': 297 Verbose = 1; 298 break; 299 300 case 'u': 301 UucpOK = 1; 302 break; 303 304 case 'd': 305 DomainOK = 1; 306 break; 307 308 case 'e': 309 ErrorCheck = 1; 310 break; 311 312 case 's': 313 Simple = 1; 314 break; 315 316 case 'n': 317 NameMode = 1; 318 break; 319 320 default: 321 printf("Unknown option %c\n", argv[1][1]); 322 break; 323 } 324 argc--; argv++; 325 } 326 if (argc < 2) { 327 printf("Usage: mkalias [-e] [-v] [-u] [-d] [-s] [-n] <input> <output>\n"); 328 exit(1); 329 } 330 Indbm = dbm_open(argv[1], O_RDONLY, 0); 331 if (Indbm == NULL) { 332 printf("Unable to open input database %s\n", argv[1]); 333 exit(1); 334 } 335 Scandbm = dbm_open(argv[1], O_RDONLY, 0); 336 if (Scandbm == NULL) { 337 printf("Unable to open input database %s\n", argv[1]); 338 exit(1); 339 } 340 if (argv[2] == NULL) 341 NoOutput = 1; 342 else { 343 Outdbm = dbm_open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0644); 344 if (Outdbm == NULL) { 345 printf("Unable to open output database %s\n", argv[2]); 346 exit(1); 347 } 348 } 349 ProcessMap(); 350 dbm_close(Indbm); 351 dbm_close(Scandbm); 352 if (!NoOutput) { 353 AddYPEntries(); 354 dbm_close(Outdbm); 355 } 356 return (0); 357 } 358