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