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
IsMailingList(char * s)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
IsQualified(char * s,char * p,char * h)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
IsMaint(char * s)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
CopyName(char * dst,char * src,int len)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
Compare(char * s1,char * s2)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
ProcessMap(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
HostCheck(char * h,char * a)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
DoName(char * cp)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
UpperCase(char * cp)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
AddYPEntries(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
main(int argc,char * argv[])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