1 /*
2 * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #include <sm/gen.h>
15
16 SM_IDSTR(copyright,
17 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
18 All rights reserved.\n\
19 Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\
20 Copyright (c) 1988, 1993\n\
21 The Regents of the University of California. All rights reserved.\n")
22
23 SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $")
24
25 #include <sys/types.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #ifdef EX_OK
30 # undef EX_OK /* unistd.h may have another use for this */
31 #endif /* EX_OK */
32 #include <sysexits.h>
33
34
35 #ifndef NOT_SENDMAIL
36 # define NOT_SENDMAIL
37 #endif /* ! NOT_SENDMAIL */
38 #include <sendmail/sendmail.h>
39 #include <sendmail/pathnames.h>
40 #include <libsmdb/smdb.h>
41
42 static void praliases __P((char *, int, char **));
43
44 uid_t RealUid;
45 gid_t RealGid;
46 char *RealUserName;
47 uid_t RunAsUid;
48 gid_t RunAsGid;
49 char *RunAsUserName;
50 int Verbose = 2;
51 bool DontInitGroups = false;
52 uid_t TrustedUid = 0;
53 BITMAP256 DontBlameSendmail;
54
55 # define DELIMITERS " ,/"
56 # define PATH_SEPARATOR ':'
57
58 int
main(argc,argv)59 main(argc, argv)
60 int argc;
61 char **argv;
62 {
63 char *cfile;
64 char *filename = NULL;
65 SM_FILE_T *cfp;
66 int ch;
67 char afilebuf[MAXLINE];
68 char buf[MAXLINE];
69 struct passwd *pw;
70 static char rnamebuf[MAXNAME];
71 extern char *optarg;
72 extern int optind;
73
74 clrbitmap(DontBlameSendmail);
75 RunAsUid = RealUid = getuid();
76 RunAsGid = RealGid = getgid();
77 pw = getpwuid(RealUid);
78 if (pw != NULL)
79 {
80 if (strlen(pw->pw_name) > MAXNAME - 1)
81 pw->pw_name[MAXNAME] = 0;
82 sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
83 }
84 else
85 (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
86 "Unknown UID %d", (int) RealUid);
87 RunAsUserName = RealUserName = rnamebuf;
88
89 cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
90 while ((ch = getopt(argc, argv, "C:f:")) != -1)
91 {
92 switch ((char)ch) {
93 case 'C':
94 cfile = optarg;
95 break;
96 case 'f':
97 filename = optarg;
98 break;
99 case '?':
100 default:
101 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
102 "usage: praliases [-C cffile] [-f aliasfile]"
103 " [key ...]\n");
104 exit(EX_USAGE);
105 }
106 }
107 argc -= optind;
108 argv += optind;
109
110 if (filename != NULL)
111 {
112 praliases(filename, argc, argv);
113 exit(EX_OK);
114 }
115
116 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
117 NULL)) == NULL)
118 {
119 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
120 "praliases: %s: %s\n", cfile,
121 sm_errstring(errno));
122 exit(EX_NOINPUT);
123 }
124
125 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
126 {
127 register char *b, *p;
128
129 b = strchr(buf, '\n');
130 if (b != NULL)
131 *b = '\0';
132
133 b = buf;
134 switch (*b++)
135 {
136 case 'O': /* option -- see if alias file */
137 if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
138 !(isascii(b[10]) && isalnum(b[10])))
139 {
140 /* new form -- find value */
141 b = strchr(b, '=');
142 if (b == NULL)
143 continue;
144 while (isascii(*++b) && isspace(*b))
145 continue;
146 }
147 else if (*b++ != 'A')
148 {
149 /* something else boring */
150 continue;
151 }
152
153 /* this is the A or AliasFile option -- save it */
154 if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
155 sizeof afilebuf)
156 {
157 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
158 "praliases: AliasFile filename too long: %.30s\n",
159 b);
160 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
161 exit(EX_CONFIG);
162 }
163 b = afilebuf;
164
165 for (p = b; p != NULL; )
166 {
167 while (isascii(*p) && isspace(*p))
168 p++;
169 if (*p == '\0')
170 break;
171 b = p;
172
173 p = strpbrk(p, DELIMITERS);
174
175 /* find end of spec */
176 if (p != NULL)
177 {
178 bool quoted = false;
179
180 for (; *p != '\0'; p++)
181 {
182 /*
183 ** Don't break into a quoted
184 ** string.
185 */
186
187 if (*p == '"')
188 quoted = !quoted;
189 else if (*p == ',' && !quoted)
190 break;
191 }
192
193 /* No more alias specs follow */
194 if (*p == '\0')
195 {
196 /* chop trailing whitespace */
197 while (isascii(*p) &&
198 isspace(*p) &&
199 p > b)
200 p--;
201 *p = '\0';
202 p = NULL;
203 }
204 }
205
206 if (p != NULL)
207 {
208 char *e = p - 1;
209
210 /* chop trailing whitespace */
211 while (isascii(*e) &&
212 isspace(*e) &&
213 e > b)
214 e--;
215 *++e = '\0';
216 *p++ = '\0';
217 }
218 praliases(b, argc, argv);
219 }
220 /* FALLTHROUGH */
221
222 default:
223 continue;
224 }
225 }
226 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
227 exit(EX_OK);
228 /* NOTREACHED */
229 return EX_OK;
230 }
231
232 static void
praliases(filename,argc,argv)233 praliases(filename, argc, argv)
234 char *filename;
235 int argc;
236 char **argv;
237 {
238 int result;
239 char *colon;
240 char *db_name;
241 char *db_type;
242 SMDB_DATABASE *database = NULL;
243 SMDB_CURSOR *cursor = NULL;
244 SMDB_DBENT db_key, db_value;
245 SMDB_DBPARAMS params;
246 SMDB_USER_INFO user_info;
247
248 colon = strchr(filename, PATH_SEPARATOR);
249 if (colon == NULL)
250 {
251 db_name = filename;
252 db_type = SMDB_TYPE_DEFAULT;
253 }
254 else
255 {
256 *colon = '\0';
257 db_name = colon + 1;
258 db_type = filename;
259 }
260
261 /* clean off arguments */
262 for (;;)
263 {
264 while (isascii(*db_name) && isspace(*db_name))
265 db_name++;
266
267 if (*db_name != '-')
268 break;
269 while (*db_name != '\0' &&
270 !(isascii(*db_name) && isspace(*db_name)))
271 db_name++;
272 }
273
274 /* Skip non-file based DB types */
275 if (db_type != NULL && *db_type != '\0')
276 {
277 if (db_type != SMDB_TYPE_DEFAULT &&
278 strcmp(db_type, "hash") != 0 &&
279 strcmp(db_type, "btree") != 0 &&
280 strcmp(db_type, "dbm") != 0)
281 {
282 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
283 "praliases: Skipping non-file based alias type %s\n",
284 db_type);
285 return;
286 }
287 }
288
289 if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
290 {
291 if (colon != NULL)
292 *colon = ':';
293 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
294 "praliases: illegal alias specification: %s\n", filename);
295 goto fatal;
296 }
297
298 memset(¶ms, '\0', sizeof params);
299 params.smdbp_cache_size = 1024 * 1024;
300
301 user_info.smdbu_id = RunAsUid;
302 user_info.smdbu_group_id = RunAsGid;
303 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
304 SMDB_MAX_USER_NAME_LEN);
305
306 result = smdb_open_database(&database, db_name, O_RDONLY, 0,
307 SFF_ROOTOK, db_type, &user_info, ¶ms);
308 if (result != SMDBE_OK)
309 {
310 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
311 "praliases: %s: open: %s\n",
312 db_name, sm_errstring(result));
313 goto fatal;
314 }
315
316 if (argc == 0)
317 {
318 memset(&db_key, '\0', sizeof db_key);
319 memset(&db_value, '\0', sizeof db_value);
320
321 result = database->smdb_cursor(database, &cursor, 0);
322 if (result != SMDBE_OK)
323 {
324 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
325 "praliases: %s: set cursor: %s\n", db_name,
326 sm_errstring(result));
327 goto fatal;
328 }
329
330 while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
331 SMDB_CURSOR_GET_NEXT)) ==
332 SMDBE_OK)
333 {
334 #if 0
335 /* skip magic @:@ entry */
336 if (db_key.size == 2 &&
337 db_key.data[0] == '@' &&
338 db_key.data[1] == '\0' &&
339 db_value.size == 2 &&
340 db_value.data[0] == '@' &&
341 db_value.data[1] == '\0')
342 continue;
343 #endif /* 0 */
344
345 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
346 "%.*s:%.*s\n",
347 (int) db_key.size,
348 (char *) db_key.data,
349 (int) db_value.size,
350 (char *) db_value.data);
351 }
352
353 if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
354 {
355 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
356 "praliases: %s: get value at cursor: %s\n",
357 db_name, sm_errstring(result));
358 goto fatal;
359 }
360 }
361 else for (; *argv != NULL; ++argv)
362 {
363 int get_res;
364
365 memset(&db_key, '\0', sizeof db_key);
366 memset(&db_value, '\0', sizeof db_value);
367 db_key.data = *argv;
368 db_key.size = strlen(*argv);
369 get_res = database->smdb_get(database, &db_key, &db_value, 0);
370 if (get_res == SMDBE_NOT_FOUND)
371 {
372 db_key.size++;
373 get_res = database->smdb_get(database, &db_key,
374 &db_value, 0);
375 }
376 if (get_res == SMDBE_OK)
377 {
378 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
379 "%.*s:%.*s\n",
380 (int) db_key.size,
381 (char *) db_key.data,
382 (int) db_value.size,
383 (char *) db_value.data);
384 }
385 else
386 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
387 "%s: No such key\n",
388 (char *)db_key.data);
389 }
390
391 fatal:
392 if (cursor != NULL)
393 (void) cursor->smdbc_close(cursor);
394 if (database != NULL)
395 (void) database->smdb_close(database);
396 if (colon != NULL)
397 *colon = ':';
398 return;
399 }
400