Merge from vendor branch BZIP:
[dragonfly.git] / contrib / sendmail-8.13.4 / praliases / praliases.c
1 /*
2  * Copyright (c) 1998-2001 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.93 2001/09/11 04:05:07 gshapiro 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 uid_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
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]\n");
103                         exit(EX_USAGE);
104                 }
105         }
106         argc -= optind;
107         argv += optind;
108
109         if (filename != NULL)
110         {
111                 praliases(filename, argc, argv);
112                 exit(EX_OK);
113         }
114
115         if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
116                               NULL)) == NULL)
117         {
118                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
119                                      "praliases: %s: %s\n", cfile,
120                                      sm_errstring(errno));
121                 exit(EX_NOINPUT);
122         }
123
124         while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
125         {
126                 register char *b, *p;
127
128                 b = strchr(buf, '\n');
129                 if (b != NULL)
130                         *b = '\0';
131
132                 b = buf;
133                 switch (*b++)
134                 {
135                   case 'O':             /* option -- see if alias file */
136                         if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
137                             !(isascii(b[10]) && isalnum(b[10])))
138                         {
139                                 /* new form -- find value */
140                                 b = strchr(b, '=');
141                                 if (b == NULL)
142                                         continue;
143                                 while (isascii(*++b) && isspace(*b))
144                                         continue;
145                         }
146                         else if (*b++ != 'A')
147                         {
148                                 /* something else boring */
149                                 continue;
150                         }
151
152                         /* this is the A or AliasFile option -- save it */
153                         if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
154                             sizeof afilebuf)
155                         {
156                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
157                                     "praliases: AliasFile filename too long: %.30s\n",
158                                         b);
159                                 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
160                                 exit(EX_CONFIG);
161                         }
162                         b = afilebuf;
163
164                         for (p = b; p != NULL; )
165                         {
166                                 while (isascii(*p) && isspace(*p))
167                                         p++;
168                                 if (*p == '\0')
169                                         break;
170                                 b = p;
171
172                                 p = strpbrk(p, DELIMITERS);
173
174                                 /* find end of spec */
175                                 if (p != NULL)
176                                 {
177                                         bool quoted = false;
178
179                                         for (; *p != '\0'; p++)
180                                         {
181                                                 /*
182                                                 **  Don't break into a quoted
183                                                 **  string.
184                                                 */
185
186                                                 if (*p == '"')
187                                                         quoted = !quoted;
188                                                 else if (*p == ',' && !quoted)
189                                                         break;
190                                         }
191
192                                         /* No more alias specs follow */
193                                         if (*p == '\0')
194                                         {
195                                                 /* chop trailing whitespace */
196                                                 while (isascii(*p) &&
197                                                        isspace(*p) &&
198                                                        p > b)
199                                                         p--;
200                                                 *p = '\0';
201                                                 p = NULL;
202                                         }
203                                 }
204
205                                 if (p != NULL)
206                                 {
207                                         char *e = p - 1;
208
209                                         /* chop trailing whitespace */
210                                         while (isascii(*e) &&
211                                                isspace(*e) &&
212                                                e > b)
213                                                 e--;
214                                         *++e = '\0';
215                                         *p++ = '\0';
216                                 }
217                                 praliases(b, argc, argv);
218                         }
219
220                   default:
221                         continue;
222                 }
223         }
224         (void) sm_io_close(cfp, SM_TIME_DEFAULT);
225         exit(EX_OK);
226         /* NOTREACHED */
227         return EX_OK;
228 }
229
230 static void
231 praliases(filename, argc, argv)
232         char *filename;
233         int argc;
234         char **argv;
235 {
236         int result;
237         char *colon;
238         char *db_name;
239         char *db_type;
240         SMDB_DATABASE *database = NULL;
241         SMDB_CURSOR *cursor = NULL;
242         SMDB_DBENT db_key, db_value;
243         SMDB_DBPARAMS params;
244         SMDB_USER_INFO user_info;
245
246         colon = strchr(filename, PATH_SEPARATOR);
247         if (colon == NULL)
248         {
249                 db_name = filename;
250                 db_type = SMDB_TYPE_DEFAULT;
251         }
252         else
253         {
254                 *colon = '\0';
255                 db_name = colon + 1;
256                 db_type = filename;
257         }
258
259         /* clean off arguments */
260         for (;;)
261         {
262                 while (isascii(*db_name) && isspace(*db_name))
263                         db_name++;
264
265                 if (*db_name != '-')
266                         break;
267                 while (*db_name != '\0' &&
268                        !(isascii(*db_name) && isspace(*db_name)))
269                         db_name++;
270         }
271
272         /* Skip non-file based DB types */
273         if (db_type != NULL && *db_type != '\0')
274         {
275                 if (db_type != SMDB_TYPE_DEFAULT &&
276                     strcmp(db_type, "hash") != 0 &&
277                     strcmp(db_type, "btree") != 0 &&
278                     strcmp(db_type, "dbm") != 0)
279                 {
280                         sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
281                                       "praliases: Skipping non-file based alias type %s\n",
282                                 db_type);
283                         return;
284                 }
285         }
286
287         if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
288         {
289                 if (colon != NULL)
290                         *colon = ':';
291                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
292                     "praliases: illegal alias specification: %s\n", filename);
293                 goto fatal;
294         }
295
296         memset(&params, '\0', sizeof params);
297         params.smdbp_cache_size = 1024 * 1024;
298
299         user_info.smdbu_id = RunAsUid;
300         user_info.smdbu_group_id = RunAsGid;
301         (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
302                           SMDB_MAX_USER_NAME_LEN);
303
304         result = smdb_open_database(&database, db_name, O_RDONLY, 0,
305                                     SFF_ROOTOK, db_type, &user_info, &params);
306         if (result != SMDBE_OK)
307         {
308                 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
309                               "praliases: %s: open: %s\n",
310                               db_name, sm_errstring(result));
311                 goto fatal;
312         }
313
314         if (argc == 0)
315         {
316                 memset(&db_key, '\0', sizeof db_key);
317                 memset(&db_value, '\0', sizeof db_value);
318
319                 result = database->smdb_cursor(database, &cursor, 0);
320                 if (result != SMDBE_OK)
321                 {
322                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
323                             "praliases: %s: set cursor: %s\n", db_name,
324                             sm_errstring(result));
325                         goto fatal;
326                 }
327
328                 while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
329                                                    SMDB_CURSOR_GET_NEXT)) ==
330                                                    SMDBE_OK)
331                 {
332 #if 0
333                         /* skip magic @:@ entry */
334                         if (db_key.size == 2 &&
335                             db_key.data[0] == '@' &&
336                             db_key.data[1] == '\0' &&
337                             db_value.size == 2 &&
338                             db_value.data[0] == '@' &&
339                             db_value.data[1] == '\0')
340                                 continue;
341 #endif /* 0 */
342
343                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
344                                              "%.*s:%.*s\n",
345                                              (int) db_key.size,
346                                              (char *) db_key.data,
347                                              (int) db_value.size,
348                                              (char *) db_value.data);
349                 }
350
351                 if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
352                 {
353                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
354                                 "praliases: %s: get value at cursor: %s\n",
355                                 db_name, sm_errstring(result));
356                         goto fatal;
357                 }
358         }
359         else for (; *argv != NULL; ++argv)
360         {
361                 int get_res;
362
363                 memset(&db_key, '\0', sizeof db_key);
364                 memset(&db_value, '\0', sizeof db_value);
365                 db_key.data = *argv;
366                 db_key.size = strlen(*argv);
367                 get_res = database->smdb_get(database, &db_key, &db_value, 0);
368                 if (get_res == SMDBE_NOT_FOUND)
369                 {
370                         db_key.size++;
371                         get_res = database->smdb_get(database, &db_key,
372                                                      &db_value, 0);
373                 }
374                 if (get_res == SMDBE_OK)
375                 {
376                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
377                                              "%.*s:%.*s\n",
378                                              (int) db_key.size,
379                                              (char *) db_key.data,
380                                              (int) db_value.size,
381                                              (char *) db_value.data);
382                 }
383                 else
384                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
385                                              "%s: No such key\n",
386                                              (char *)db_key.data);
387         }
388
389  fatal:
390         if (cursor != NULL)
391                 (void) cursor->smdbc_close(cursor);
392         if (database != NULL)
393                 (void) database->smdb_close(database);
394         if (colon != NULL)
395                 *colon = ':';
396         return;
397 }