190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 1998-2002, 2004 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1992 Eric P. Allman. All rights reserved. 590792Sgshapiro * Copyright (c) 1992, 1993 690792Sgshapiro * The Regents of the University of California. All rights reserved. 790792Sgshapiro * 890792Sgshapiro * By using this file, you agree to the terms and conditions set 990792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1090792Sgshapiro * the sendmail distribution. 1190792Sgshapiro * 1290792Sgshapiro */ 1390792Sgshapiro 1490792Sgshapiro#include <sm/gen.h> 1590792Sgshapiro#ifndef lint 1690792SgshapiroSM_UNUSED(static char copyright[]) = 17261363Sgshapiro"@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\ 1890792Sgshapiro All rights reserved.\n\ 1990792Sgshapiro Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ 2090792Sgshapiro Copyright (c) 1992, 1993\n\ 2190792Sgshapiro The Regents of the University of California. All rights reserved.\n"; 2290792Sgshapiro#endif /* ! lint */ 2390792Sgshapiro 2490792Sgshapiro#ifndef lint 25266692SgshapiroSM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.26 2013-11-22 20:51:26 ca Exp $"; 2690792Sgshapiro#endif /* ! lint */ 2790792Sgshapiro 2890792Sgshapiro 2990792Sgshapiro#include <sys/types.h> 3090792Sgshapiro#ifndef ISC_UNIX 3190792Sgshapiro# include <sys/file.h> 3290792Sgshapiro#endif /* ! ISC_UNIX */ 3390792Sgshapiro#include <ctype.h> 3490792Sgshapiro#include <stdlib.h> 3590792Sgshapiro#include <unistd.h> 3690792Sgshapiro#ifdef EX_OK 3790792Sgshapiro# undef EX_OK /* unistd.h may have another use for this */ 3890792Sgshapiro#endif /* EX_OK */ 3990792Sgshapiro#include <sysexits.h> 4090792Sgshapiro#include <assert.h> 4190792Sgshapiro#include <sendmail/sendmail.h> 4290792Sgshapiro#include <sendmail/pathnames.h> 4390792Sgshapiro#include <libsmdb/smdb.h> 4490792Sgshapiro 4590792Sgshapirouid_t RealUid; 4690792Sgshapirogid_t RealGid; 4790792Sgshapirochar *RealUserName; 4890792Sgshapirouid_t RunAsUid; 49173340Sgshapirogid_t RunAsGid; 5090792Sgshapirochar *RunAsUserName; 5190792Sgshapiroint Verbose = 2; 5290792Sgshapirobool DontInitGroups = false; 5390792Sgshapirouid_t TrustedUid = 0; 5490792SgshapiroBITMAP256 DontBlameSendmail; 5590792Sgshapiro 5690792Sgshapiro#define BUFSIZE 1024 5790792Sgshapiro#define ISSEP(c) (isascii(c) && isspace(c)) 5890792Sgshapiro 5990792Sgshapiro 60141858Sgshapirostatic void usage __P((char *)); 61141858Sgshapiro 6290792Sgshapirostatic void 6390792Sgshapirousage(progname) 6490792Sgshapiro char *progname; 6590792Sgshapiro{ 6690792Sgshapiro fprintf(stderr, 6790792Sgshapiro "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n", 6890792Sgshapiro progname); 6990792Sgshapiro exit(EX_USAGE); 7090792Sgshapiro} 7190792Sgshapiro 7290792Sgshapiroint 7390792Sgshapiromain(argc, argv) 7490792Sgshapiro int argc; 7590792Sgshapiro char **argv; 7690792Sgshapiro{ 7790792Sgshapiro char *progname; 7890792Sgshapiro char *cfile; 7990792Sgshapiro bool query = false; 8090792Sgshapiro bool update = false; 8190792Sgshapiro bool remove = false; 8290792Sgshapiro bool inclnull = false; 8390792Sgshapiro bool foldcase = true; 8490792Sgshapiro unsigned int nops = 0; 8590792Sgshapiro int exitstat; 8690792Sgshapiro int opt; 8790792Sgshapiro char *typename = NULL; 8890792Sgshapiro char *mapname = NULL; 8990792Sgshapiro char *keyname = NULL; 9090792Sgshapiro char *value = NULL; 9190792Sgshapiro int mode; 9290792Sgshapiro int smode; 9390792Sgshapiro int putflags = 0; 9490792Sgshapiro long sff = SFF_ROOTOK|SFF_REGONLY; 9590792Sgshapiro struct passwd *pw; 9690792Sgshapiro SMDB_DATABASE *database; 9790792Sgshapiro SMDB_DBENT db_key, db_val; 9890792Sgshapiro SMDB_DBPARAMS params; 9990792Sgshapiro SMDB_USER_INFO user_info; 10090792Sgshapiro#if HASFCHOWN 10190792Sgshapiro FILE *cfp; 10290792Sgshapiro char buf[MAXLINE]; 10390792Sgshapiro#endif /* HASFCHOWN */ 10490792Sgshapiro static char rnamebuf[MAXNAME]; /* holds RealUserName */ 10590792Sgshapiro extern char *optarg; 10690792Sgshapiro extern int optind; 10790792Sgshapiro 10890792Sgshapiro memset(¶ms, '\0', sizeof params); 10990792Sgshapiro params.smdbp_cache_size = 1024 * 1024; 11090792Sgshapiro 11190792Sgshapiro progname = strrchr(argv[0], '/'); 11290792Sgshapiro if (progname != NULL) 11390792Sgshapiro progname++; 11490792Sgshapiro else 11590792Sgshapiro progname = argv[0]; 11690792Sgshapiro cfile = _PATH_SENDMAILCF; 11790792Sgshapiro 11890792Sgshapiro clrbitmap(DontBlameSendmail); 11990792Sgshapiro RunAsUid = RealUid = getuid(); 12090792Sgshapiro RunAsGid = RealGid = getgid(); 12190792Sgshapiro pw = getpwuid(RealUid); 12290792Sgshapiro if (pw != NULL) 12390792Sgshapiro (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 12490792Sgshapiro else 12590792Sgshapiro (void) sm_snprintf(rnamebuf, sizeof rnamebuf, 12690792Sgshapiro "Unknown UID %d", (int) RealUid); 12790792Sgshapiro RunAsUserName = RealUserName = rnamebuf; 12890792Sgshapiro user_info.smdbu_id = RunAsUid; 12990792Sgshapiro user_info.smdbu_group_id = RunAsGid; 13090792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, 13190792Sgshapiro SMDB_MAX_USER_NAME_LEN); 13290792Sgshapiro 133285303Sgshapiro#define OPTIONS "C:fquxN" 13490792Sgshapiro while ((opt = getopt(argc, argv, OPTIONS)) != -1) 13590792Sgshapiro { 13690792Sgshapiro switch (opt) 13790792Sgshapiro { 13890792Sgshapiro case 'C': 13990792Sgshapiro cfile = optarg; 14090792Sgshapiro break; 14190792Sgshapiro 14290792Sgshapiro case 'f': 14390792Sgshapiro foldcase = false; 14490792Sgshapiro break; 14590792Sgshapiro 14690792Sgshapiro case 'q': 14790792Sgshapiro query = true; 14890792Sgshapiro nops++; 14990792Sgshapiro break; 15090792Sgshapiro 15190792Sgshapiro case 'u': 15290792Sgshapiro update = true; 15390792Sgshapiro nops++; 15490792Sgshapiro break; 15590792Sgshapiro 15690792Sgshapiro case 'x': 15790792Sgshapiro remove = true; 15890792Sgshapiro nops++; 15990792Sgshapiro break; 16090792Sgshapiro 16190792Sgshapiro case 'N': 16290792Sgshapiro inclnull = true; 16390792Sgshapiro break; 16490792Sgshapiro 16590792Sgshapiro default: 16690792Sgshapiro usage(progname); 16790792Sgshapiro assert(0); /* NOTREACHED */ 16890792Sgshapiro } 16990792Sgshapiro } 17090792Sgshapiro 17190792Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 17290792Sgshapiro sff |= SFF_NOSLINK; 17390792Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 17490792Sgshapiro sff |= SFF_NOHLINK; 17590792Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 17690792Sgshapiro sff |= SFF_NOWLINK; 17790792Sgshapiro 17890792Sgshapiro argc -= optind; 17990792Sgshapiro argv += optind; 18090792Sgshapiro if ((nops != 1) || 18190792Sgshapiro (query && argc != 3) || 18290792Sgshapiro (remove && argc != 3) || 18390792Sgshapiro (update && argc <= 3)) 18490792Sgshapiro { 18590792Sgshapiro usage(progname); 18690792Sgshapiro assert(0); /* NOTREACHED */ 18790792Sgshapiro } 18890792Sgshapiro 18990792Sgshapiro typename = argv[0]; 19090792Sgshapiro mapname = argv[1]; 19190792Sgshapiro keyname = argv[2]; 19290792Sgshapiro if (update) 19390792Sgshapiro value = argv[3]; 19490792Sgshapiro 19590792Sgshapiro if (foldcase) 19690792Sgshapiro { 19790792Sgshapiro char *p; 19890792Sgshapiro 19990792Sgshapiro for (p = keyname; *p != '\0'; p++) 20090792Sgshapiro { 20190792Sgshapiro if (isascii(*p) && isupper(*p)) 20290792Sgshapiro *p = tolower(*p); 20390792Sgshapiro } 20490792Sgshapiro } 20590792Sgshapiro 20690792Sgshapiro 20790792Sgshapiro#if HASFCHOWN 20890792Sgshapiro /* Find TrustedUser value in sendmail.cf */ 20990792Sgshapiro if ((cfp = fopen(cfile, "r")) == NULL) 21090792Sgshapiro { 21190792Sgshapiro fprintf(stderr, "%s: %s: %s\n", progname, 21290792Sgshapiro cfile, sm_errstring(errno)); 21390792Sgshapiro exit(EX_NOINPUT); 21490792Sgshapiro } 21590792Sgshapiro while (fgets(buf, sizeof(buf), cfp) != NULL) 21690792Sgshapiro { 21790792Sgshapiro register char *b; 21890792Sgshapiro 21990792Sgshapiro if ((b = strchr(buf, '\n')) != NULL) 22090792Sgshapiro *b = '\0'; 22190792Sgshapiro 22290792Sgshapiro b = buf; 22390792Sgshapiro switch (*b++) 22490792Sgshapiro { 22590792Sgshapiro case 'O': /* option */ 22690792Sgshapiro if (strncasecmp(b, " TrustedUser", 12) == 0 && 22790792Sgshapiro !(isascii(b[12]) && isalnum(b[12]))) 22890792Sgshapiro { 22990792Sgshapiro b = strchr(b, '='); 23090792Sgshapiro if (b == NULL) 23190792Sgshapiro continue; 23290792Sgshapiro while (isascii(*++b) && isspace(*b)) 23390792Sgshapiro continue; 23490792Sgshapiro if (isascii(*b) && isdigit(*b)) 23590792Sgshapiro TrustedUid = atoi(b); 23690792Sgshapiro else 23790792Sgshapiro { 23890792Sgshapiro TrustedUid = 0; 23990792Sgshapiro pw = getpwnam(b); 24090792Sgshapiro if (pw == NULL) 24190792Sgshapiro fprintf(stderr, 24290792Sgshapiro "TrustedUser: unknown user %s\n", b); 24390792Sgshapiro else 24490792Sgshapiro TrustedUid = pw->pw_uid; 24590792Sgshapiro } 24690792Sgshapiro 24790792Sgshapiro# ifdef UID_MAX 24890792Sgshapiro if (TrustedUid > UID_MAX) 24990792Sgshapiro { 25090792Sgshapiro fprintf(stderr, 25190792Sgshapiro "TrustedUser: uid value (%ld) > UID_MAX (%ld)", 25290792Sgshapiro (long) TrustedUid, 25390792Sgshapiro (long) UID_MAX); 25490792Sgshapiro TrustedUid = 0; 25590792Sgshapiro } 25690792Sgshapiro# endif /* UID_MAX */ 25790792Sgshapiro break; 25890792Sgshapiro } 25990792Sgshapiro 26090792Sgshapiro 26190792Sgshapiro default: 26290792Sgshapiro continue; 26390792Sgshapiro } 26490792Sgshapiro } 26590792Sgshapiro (void) fclose(cfp); 26690792Sgshapiro#endif /* HASFCHOWN */ 26790792Sgshapiro 26890792Sgshapiro if (query) 26990792Sgshapiro { 27090792Sgshapiro mode = O_RDONLY; 27190792Sgshapiro smode = S_IRUSR; 27290792Sgshapiro } 27390792Sgshapiro else 27490792Sgshapiro { 27590792Sgshapiro mode = O_RDWR | O_CREAT; 27690792Sgshapiro sff |= SFF_CREAT|SFF_NOTEXCL; 27790792Sgshapiro smode = S_IWUSR; 27890792Sgshapiro } 27990792Sgshapiro 28090792Sgshapiro params.smdbp_num_elements = 4096; 28190792Sgshapiro 28290792Sgshapiro errno = smdb_open_database(&database, mapname, mode, smode, sff, 28390792Sgshapiro typename, &user_info, ¶ms); 28490792Sgshapiro if (errno != SMDBE_OK) 28590792Sgshapiro { 28690792Sgshapiro char *hint; 28790792Sgshapiro 28890792Sgshapiro if (errno == SMDBE_UNSUPPORTED_DB_TYPE && 28990792Sgshapiro (hint = smdb_db_definition(typename)) != NULL) 29090792Sgshapiro fprintf(stderr, 29190792Sgshapiro "%s: Need to recompile with -D%s for %s support\n", 29290792Sgshapiro progname, hint, typename); 29390792Sgshapiro else 29490792Sgshapiro fprintf(stderr, 29590792Sgshapiro "%s: error opening type %s map %s: %s\n", 29690792Sgshapiro progname, typename, mapname, 29790792Sgshapiro sm_errstring(errno)); 29890792Sgshapiro exit(EX_CANTCREAT); 29990792Sgshapiro } 30090792Sgshapiro 30190792Sgshapiro (void) database->smdb_sync(database, 0); 30290792Sgshapiro 30390792Sgshapiro if (geteuid() == 0 && TrustedUid != 0) 30490792Sgshapiro { 30590792Sgshapiro errno = database->smdb_set_owner(database, TrustedUid, -1); 30690792Sgshapiro if (errno != SMDBE_OK) 30790792Sgshapiro { 30890792Sgshapiro fprintf(stderr, 30990792Sgshapiro "WARNING: ownership change on %s failed %s", 31090792Sgshapiro mapname, sm_errstring(errno)); 31190792Sgshapiro } 31290792Sgshapiro } 31390792Sgshapiro 31490792Sgshapiro exitstat = EX_OK; 31590792Sgshapiro if (query) 31690792Sgshapiro { 31790792Sgshapiro memset(&db_key, '\0', sizeof db_key); 31890792Sgshapiro memset(&db_val, '\0', sizeof db_val); 31990792Sgshapiro 32090792Sgshapiro db_key.data = keyname; 32190792Sgshapiro db_key.size = strlen(keyname); 32290792Sgshapiro if (inclnull) 32390792Sgshapiro db_key.size++; 32490792Sgshapiro 32590792Sgshapiro errno = database->smdb_get(database, &db_key, &db_val, 0); 32690792Sgshapiro if (errno != SMDBE_OK) 32790792Sgshapiro { 32890792Sgshapiro /* XXX - Need to distinguish between not found */ 32990792Sgshapiro fprintf(stderr, 33090792Sgshapiro "%s: couldn't find key %s in map %s\n", 33190792Sgshapiro progname, keyname, mapname); 33290792Sgshapiro exitstat = EX_UNAVAILABLE; 33390792Sgshapiro } 33490792Sgshapiro else 33590792Sgshapiro { 33690792Sgshapiro printf("%.*s\n", (int) db_val.size, 33790792Sgshapiro (char *) db_val.data); 33890792Sgshapiro } 33990792Sgshapiro } 34090792Sgshapiro else if (update) 34190792Sgshapiro { 34290792Sgshapiro memset(&db_key, '\0', sizeof db_key); 34390792Sgshapiro memset(&db_val, '\0', sizeof db_val); 34490792Sgshapiro 34590792Sgshapiro db_key.data = keyname; 34690792Sgshapiro db_key.size = strlen(keyname); 34790792Sgshapiro if (inclnull) 34890792Sgshapiro db_key.size++; 34990792Sgshapiro db_val.data = value; 35090792Sgshapiro db_val.size = strlen(value); 35190792Sgshapiro if (inclnull) 35290792Sgshapiro db_val.size++; 35390792Sgshapiro 35490792Sgshapiro errno = database->smdb_put(database, &db_key, &db_val, 35590792Sgshapiro putflags); 35690792Sgshapiro if (errno != SMDBE_OK) 35790792Sgshapiro { 35890792Sgshapiro fprintf(stderr, 35990792Sgshapiro "%s: error updating (%s, %s) in map %s: %s\n", 36090792Sgshapiro progname, keyname, value, mapname, 36190792Sgshapiro sm_errstring(errno)); 36290792Sgshapiro exitstat = EX_IOERR; 36390792Sgshapiro } 36490792Sgshapiro } 36590792Sgshapiro else if (remove) 36690792Sgshapiro { 36790792Sgshapiro memset(&db_key, '\0', sizeof db_key); 36890792Sgshapiro memset(&db_val, '\0', sizeof db_val); 36990792Sgshapiro 37090792Sgshapiro db_key.data = keyname; 37190792Sgshapiro db_key.size = strlen(keyname); 37290792Sgshapiro if (inclnull) 37390792Sgshapiro db_key.size++; 37490792Sgshapiro 37590792Sgshapiro errno = database->smdb_del(database, &db_key, 0); 37690792Sgshapiro 37790792Sgshapiro switch (errno) 37890792Sgshapiro { 37990792Sgshapiro case SMDBE_NOT_FOUND: 38090792Sgshapiro fprintf(stderr, 38190792Sgshapiro "%s: key %s doesn't exist in map %s\n", 38290792Sgshapiro progname, keyname, mapname); 38390792Sgshapiro /* Don't set exitstat */ 38490792Sgshapiro break; 38590792Sgshapiro case SMDBE_OK: 38690792Sgshapiro /* All's well */ 38790792Sgshapiro break; 38890792Sgshapiro default: 38990792Sgshapiro fprintf(stderr, 39090792Sgshapiro "%s: couldn't remove key %s in map %s (error)\n", 39190792Sgshapiro progname, keyname, mapname); 39290792Sgshapiro exitstat = EX_IOERR; 39390792Sgshapiro break; 39490792Sgshapiro } 39590792Sgshapiro } 39690792Sgshapiro else 39790792Sgshapiro { 39890792Sgshapiro assert(0); /* NOT REACHED */ 39990792Sgshapiro } 40090792Sgshapiro 40190792Sgshapiro /* 40290792Sgshapiro ** Now close the database. 40390792Sgshapiro */ 40490792Sgshapiro 40590792Sgshapiro errno = database->smdb_close(database); 40690792Sgshapiro if (errno != SMDBE_OK) 40790792Sgshapiro { 40890792Sgshapiro fprintf(stderr, "%s: close(%s): %s\n", 40990792Sgshapiro progname, mapname, sm_errstring(errno)); 41090792Sgshapiro exitstat = EX_IOERR; 41190792Sgshapiro } 41290792Sgshapiro smdb_free_database(database); 41390792Sgshapiro 41490792Sgshapiro exit(exitstat); 41590792Sgshapiro /* NOTREACHED */ 41690792Sgshapiro return exitstat; 41790792Sgshapiro} 418