190792Sgshapiro/* 2141858Sgshapiro * Copyright (c) 1998-2002, 2004 Sendmail, 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[]) = 1790792Sgshapiro"@(#) Copyright (c) 1998-2001 Sendmail, 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 25173340SgshapiroSM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.25 2007/05/11 18:50:35 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 verbose = false; 8090792Sgshapiro bool query = false; 8190792Sgshapiro bool update = false; 8290792Sgshapiro bool remove = false; 8390792Sgshapiro bool inclnull = false; 8490792Sgshapiro bool foldcase = true; 8590792Sgshapiro unsigned int nops = 0; 8690792Sgshapiro int exitstat; 8790792Sgshapiro int opt; 8890792Sgshapiro char *typename = NULL; 8990792Sgshapiro char *mapname = NULL; 9090792Sgshapiro char *keyname = NULL; 9190792Sgshapiro char *value = NULL; 9290792Sgshapiro int mode; 9390792Sgshapiro int smode; 9490792Sgshapiro int putflags = 0; 9590792Sgshapiro long sff = SFF_ROOTOK|SFF_REGONLY; 9690792Sgshapiro struct passwd *pw; 9790792Sgshapiro SMDB_DATABASE *database; 9890792Sgshapiro SMDB_DBENT db_key, db_val; 9990792Sgshapiro SMDB_DBPARAMS params; 10090792Sgshapiro SMDB_USER_INFO user_info; 10190792Sgshapiro#if HASFCHOWN 10290792Sgshapiro FILE *cfp; 10390792Sgshapiro char buf[MAXLINE]; 10490792Sgshapiro#endif /* HASFCHOWN */ 10590792Sgshapiro static char rnamebuf[MAXNAME]; /* holds RealUserName */ 10690792Sgshapiro extern char *optarg; 10790792Sgshapiro extern int optind; 10890792Sgshapiro 10990792Sgshapiro memset(¶ms, '\0', sizeof params); 11090792Sgshapiro params.smdbp_cache_size = 1024 * 1024; 11190792Sgshapiro 11290792Sgshapiro progname = strrchr(argv[0], '/'); 11390792Sgshapiro if (progname != NULL) 11490792Sgshapiro progname++; 11590792Sgshapiro else 11690792Sgshapiro progname = argv[0]; 11790792Sgshapiro cfile = _PATH_SENDMAILCF; 11890792Sgshapiro 11990792Sgshapiro clrbitmap(DontBlameSendmail); 12090792Sgshapiro RunAsUid = RealUid = getuid(); 12190792Sgshapiro RunAsGid = RealGid = getgid(); 12290792Sgshapiro pw = getpwuid(RealUid); 12390792Sgshapiro if (pw != NULL) 12490792Sgshapiro (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 12590792Sgshapiro else 12690792Sgshapiro (void) sm_snprintf(rnamebuf, sizeof rnamebuf, 12790792Sgshapiro "Unknown UID %d", (int) RealUid); 12890792Sgshapiro RunAsUserName = RealUserName = rnamebuf; 12990792Sgshapiro user_info.smdbu_id = RunAsUid; 13090792Sgshapiro user_info.smdbu_group_id = RunAsGid; 13190792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, 13290792Sgshapiro SMDB_MAX_USER_NAME_LEN); 13390792Sgshapiro 13490792Sgshapiro#define OPTIONS "C:fquxvN" 13590792Sgshapiro while ((opt = getopt(argc, argv, OPTIONS)) != -1) 13690792Sgshapiro { 13790792Sgshapiro switch (opt) 13890792Sgshapiro { 13990792Sgshapiro case 'C': 14090792Sgshapiro cfile = optarg; 14190792Sgshapiro break; 14290792Sgshapiro 14390792Sgshapiro case 'f': 14490792Sgshapiro foldcase = false; 14590792Sgshapiro break; 14690792Sgshapiro 14790792Sgshapiro case 'q': 14890792Sgshapiro query = true; 14990792Sgshapiro nops++; 15090792Sgshapiro break; 15190792Sgshapiro 15290792Sgshapiro case 'u': 15390792Sgshapiro update = true; 15490792Sgshapiro nops++; 15590792Sgshapiro break; 15690792Sgshapiro 15790792Sgshapiro case 'x': 15890792Sgshapiro remove = true; 15990792Sgshapiro nops++; 16090792Sgshapiro break; 16190792Sgshapiro 16290792Sgshapiro case 'v': 16390792Sgshapiro verbose = true; 16490792Sgshapiro break; 16590792Sgshapiro 16690792Sgshapiro case 'N': 16790792Sgshapiro inclnull = true; 16890792Sgshapiro break; 16990792Sgshapiro 17090792Sgshapiro default: 17190792Sgshapiro usage(progname); 17290792Sgshapiro assert(0); /* NOTREACHED */ 17390792Sgshapiro } 17490792Sgshapiro } 17590792Sgshapiro 17690792Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 17790792Sgshapiro sff |= SFF_NOSLINK; 17890792Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 17990792Sgshapiro sff |= SFF_NOHLINK; 18090792Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 18190792Sgshapiro sff |= SFF_NOWLINK; 18290792Sgshapiro 18390792Sgshapiro argc -= optind; 18490792Sgshapiro argv += optind; 18590792Sgshapiro if ((nops != 1) || 18690792Sgshapiro (query && argc != 3) || 18790792Sgshapiro (remove && argc != 3) || 18890792Sgshapiro (update && argc <= 3)) 18990792Sgshapiro { 19090792Sgshapiro usage(progname); 19190792Sgshapiro assert(0); /* NOTREACHED */ 19290792Sgshapiro } 19390792Sgshapiro 19490792Sgshapiro typename = argv[0]; 19590792Sgshapiro mapname = argv[1]; 19690792Sgshapiro keyname = argv[2]; 19790792Sgshapiro if (update) 19890792Sgshapiro value = argv[3]; 19990792Sgshapiro 20090792Sgshapiro if (foldcase) 20190792Sgshapiro { 20290792Sgshapiro char *p; 20390792Sgshapiro 20490792Sgshapiro for (p = keyname; *p != '\0'; p++) 20590792Sgshapiro { 20690792Sgshapiro if (isascii(*p) && isupper(*p)) 20790792Sgshapiro *p = tolower(*p); 20890792Sgshapiro } 20990792Sgshapiro } 21090792Sgshapiro 21190792Sgshapiro 21290792Sgshapiro#if HASFCHOWN 21390792Sgshapiro /* Find TrustedUser value in sendmail.cf */ 21490792Sgshapiro if ((cfp = fopen(cfile, "r")) == NULL) 21590792Sgshapiro { 21690792Sgshapiro fprintf(stderr, "%s: %s: %s\n", progname, 21790792Sgshapiro cfile, sm_errstring(errno)); 21890792Sgshapiro exit(EX_NOINPUT); 21990792Sgshapiro } 22090792Sgshapiro while (fgets(buf, sizeof(buf), cfp) != NULL) 22190792Sgshapiro { 22290792Sgshapiro register char *b; 22390792Sgshapiro 22490792Sgshapiro if ((b = strchr(buf, '\n')) != NULL) 22590792Sgshapiro *b = '\0'; 22690792Sgshapiro 22790792Sgshapiro b = buf; 22890792Sgshapiro switch (*b++) 22990792Sgshapiro { 23090792Sgshapiro case 'O': /* option */ 23190792Sgshapiro if (strncasecmp(b, " TrustedUser", 12) == 0 && 23290792Sgshapiro !(isascii(b[12]) && isalnum(b[12]))) 23390792Sgshapiro { 23490792Sgshapiro b = strchr(b, '='); 23590792Sgshapiro if (b == NULL) 23690792Sgshapiro continue; 23790792Sgshapiro while (isascii(*++b) && isspace(*b)) 23890792Sgshapiro continue; 23990792Sgshapiro if (isascii(*b) && isdigit(*b)) 24090792Sgshapiro TrustedUid = atoi(b); 24190792Sgshapiro else 24290792Sgshapiro { 24390792Sgshapiro TrustedUid = 0; 24490792Sgshapiro pw = getpwnam(b); 24590792Sgshapiro if (pw == NULL) 24690792Sgshapiro fprintf(stderr, 24790792Sgshapiro "TrustedUser: unknown user %s\n", b); 24890792Sgshapiro else 24990792Sgshapiro TrustedUid = pw->pw_uid; 25090792Sgshapiro } 25190792Sgshapiro 25290792Sgshapiro# ifdef UID_MAX 25390792Sgshapiro if (TrustedUid > UID_MAX) 25490792Sgshapiro { 25590792Sgshapiro fprintf(stderr, 25690792Sgshapiro "TrustedUser: uid value (%ld) > UID_MAX (%ld)", 25790792Sgshapiro (long) TrustedUid, 25890792Sgshapiro (long) UID_MAX); 25990792Sgshapiro TrustedUid = 0; 26090792Sgshapiro } 26190792Sgshapiro# endif /* UID_MAX */ 26290792Sgshapiro break; 26390792Sgshapiro } 26490792Sgshapiro 26590792Sgshapiro 26690792Sgshapiro default: 26790792Sgshapiro continue; 26890792Sgshapiro } 26990792Sgshapiro } 27090792Sgshapiro (void) fclose(cfp); 27190792Sgshapiro#endif /* HASFCHOWN */ 27290792Sgshapiro 27390792Sgshapiro if (query) 27490792Sgshapiro { 27590792Sgshapiro mode = O_RDONLY; 27690792Sgshapiro smode = S_IRUSR; 27790792Sgshapiro } 27890792Sgshapiro else 27990792Sgshapiro { 28090792Sgshapiro mode = O_RDWR | O_CREAT; 28190792Sgshapiro sff |= SFF_CREAT|SFF_NOTEXCL; 28290792Sgshapiro smode = S_IWUSR; 28390792Sgshapiro } 28490792Sgshapiro 28590792Sgshapiro params.smdbp_num_elements = 4096; 28690792Sgshapiro 28790792Sgshapiro errno = smdb_open_database(&database, mapname, mode, smode, sff, 28890792Sgshapiro typename, &user_info, ¶ms); 28990792Sgshapiro if (errno != SMDBE_OK) 29090792Sgshapiro { 29190792Sgshapiro char *hint; 29290792Sgshapiro 29390792Sgshapiro if (errno == SMDBE_UNSUPPORTED_DB_TYPE && 29490792Sgshapiro (hint = smdb_db_definition(typename)) != NULL) 29590792Sgshapiro fprintf(stderr, 29690792Sgshapiro "%s: Need to recompile with -D%s for %s support\n", 29790792Sgshapiro progname, hint, typename); 29890792Sgshapiro else 29990792Sgshapiro fprintf(stderr, 30090792Sgshapiro "%s: error opening type %s map %s: %s\n", 30190792Sgshapiro progname, typename, mapname, 30290792Sgshapiro sm_errstring(errno)); 30390792Sgshapiro exit(EX_CANTCREAT); 30490792Sgshapiro } 30590792Sgshapiro 30690792Sgshapiro (void) database->smdb_sync(database, 0); 30790792Sgshapiro 30890792Sgshapiro if (geteuid() == 0 && TrustedUid != 0) 30990792Sgshapiro { 31090792Sgshapiro errno = database->smdb_set_owner(database, TrustedUid, -1); 31190792Sgshapiro if (errno != SMDBE_OK) 31290792Sgshapiro { 31390792Sgshapiro fprintf(stderr, 31490792Sgshapiro "WARNING: ownership change on %s failed %s", 31590792Sgshapiro mapname, sm_errstring(errno)); 31690792Sgshapiro } 31790792Sgshapiro } 31890792Sgshapiro 31990792Sgshapiro exitstat = EX_OK; 32090792Sgshapiro if (query) 32190792Sgshapiro { 32290792Sgshapiro memset(&db_key, '\0', sizeof db_key); 32390792Sgshapiro memset(&db_val, '\0', sizeof db_val); 32490792Sgshapiro 32590792Sgshapiro db_key.data = keyname; 32690792Sgshapiro db_key.size = strlen(keyname); 32790792Sgshapiro if (inclnull) 32890792Sgshapiro db_key.size++; 32990792Sgshapiro 33090792Sgshapiro errno = database->smdb_get(database, &db_key, &db_val, 0); 33190792Sgshapiro if (errno != SMDBE_OK) 33290792Sgshapiro { 33390792Sgshapiro /* XXX - Need to distinguish between not found */ 33490792Sgshapiro fprintf(stderr, 33590792Sgshapiro "%s: couldn't find key %s in map %s\n", 33690792Sgshapiro progname, keyname, mapname); 33790792Sgshapiro exitstat = EX_UNAVAILABLE; 33890792Sgshapiro } 33990792Sgshapiro else 34090792Sgshapiro { 34190792Sgshapiro printf("%.*s\n", (int) db_val.size, 34290792Sgshapiro (char *) db_val.data); 34390792Sgshapiro } 34490792Sgshapiro } 34590792Sgshapiro else if (update) 34690792Sgshapiro { 34790792Sgshapiro memset(&db_key, '\0', sizeof db_key); 34890792Sgshapiro memset(&db_val, '\0', sizeof db_val); 34990792Sgshapiro 35090792Sgshapiro db_key.data = keyname; 35190792Sgshapiro db_key.size = strlen(keyname); 35290792Sgshapiro if (inclnull) 35390792Sgshapiro db_key.size++; 35490792Sgshapiro db_val.data = value; 35590792Sgshapiro db_val.size = strlen(value); 35690792Sgshapiro if (inclnull) 35790792Sgshapiro db_val.size++; 35890792Sgshapiro 35990792Sgshapiro errno = database->smdb_put(database, &db_key, &db_val, 36090792Sgshapiro putflags); 36190792Sgshapiro if (errno != SMDBE_OK) 36290792Sgshapiro { 36390792Sgshapiro fprintf(stderr, 36490792Sgshapiro "%s: error updating (%s, %s) in map %s: %s\n", 36590792Sgshapiro progname, keyname, value, mapname, 36690792Sgshapiro sm_errstring(errno)); 36790792Sgshapiro exitstat = EX_IOERR; 36890792Sgshapiro } 36990792Sgshapiro } 37090792Sgshapiro else if (remove) 37190792Sgshapiro { 37290792Sgshapiro memset(&db_key, '\0', sizeof db_key); 37390792Sgshapiro memset(&db_val, '\0', sizeof db_val); 37490792Sgshapiro 37590792Sgshapiro db_key.data = keyname; 37690792Sgshapiro db_key.size = strlen(keyname); 37790792Sgshapiro if (inclnull) 37890792Sgshapiro db_key.size++; 37990792Sgshapiro 38090792Sgshapiro errno = database->smdb_del(database, &db_key, 0); 38190792Sgshapiro 38290792Sgshapiro switch (errno) 38390792Sgshapiro { 38490792Sgshapiro case SMDBE_NOT_FOUND: 38590792Sgshapiro fprintf(stderr, 38690792Sgshapiro "%s: key %s doesn't exist in map %s\n", 38790792Sgshapiro progname, keyname, mapname); 38890792Sgshapiro /* Don't set exitstat */ 38990792Sgshapiro break; 39090792Sgshapiro case SMDBE_OK: 39190792Sgshapiro /* All's well */ 39290792Sgshapiro break; 39390792Sgshapiro default: 39490792Sgshapiro fprintf(stderr, 39590792Sgshapiro "%s: couldn't remove key %s in map %s (error)\n", 39690792Sgshapiro progname, keyname, mapname); 39790792Sgshapiro exitstat = EX_IOERR; 39890792Sgshapiro break; 39990792Sgshapiro } 40090792Sgshapiro } 40190792Sgshapiro else 40290792Sgshapiro { 40390792Sgshapiro assert(0); /* NOT REACHED */ 40490792Sgshapiro } 40590792Sgshapiro 40690792Sgshapiro /* 40790792Sgshapiro ** Now close the database. 40890792Sgshapiro */ 40990792Sgshapiro 41090792Sgshapiro errno = database->smdb_close(database); 41190792Sgshapiro if (errno != SMDBE_OK) 41290792Sgshapiro { 41390792Sgshapiro fprintf(stderr, "%s: close(%s): %s\n", 41490792Sgshapiro progname, mapname, sm_errstring(errno)); 41590792Sgshapiro exitstat = EX_IOERR; 41690792Sgshapiro } 41790792Sgshapiro smdb_free_database(database); 41890792Sgshapiro 41990792Sgshapiro exit(exitstat); 42090792Sgshapiro /* NOTREACHED */ 42190792Sgshapiro return exitstat; 42290792Sgshapiro} 423