xref: /illumos-gate/usr/src/cmd/ypcmd/mkalias.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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