1 /* 2 * Copyright (c) 1998-2002, 2004 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1992 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1992, 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 #ifndef lint 16 SM_UNUSED(static char copyright[]) = 17 "@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\ 18 All rights reserved.\n\ 19 Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ 20 Copyright (c) 1992, 1993\n\ 21 The Regents of the University of California. All rights reserved.\n"; 22 #endif /* ! lint */ 23 24 #ifndef lint 25 SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.26 2013-11-22 20:51:26 ca Exp $"; 26 #endif 27 28 29 #include <sys/types.h> 30 #ifndef ISC_UNIX 31 # include <sys/file.h> 32 #endif 33 #include <ctype.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #ifdef EX_OK 37 # undef EX_OK /* unistd.h may have another use for this */ 38 #endif 39 #include <sysexits.h> 40 #include <assert.h> 41 #include <sm/sendmail.h> 42 #include <sendmail/sendmail.h> 43 #include <sendmail/pathnames.h> 44 #include <libsmdb/smdb.h> 45 46 uid_t RealUid; 47 gid_t RealGid; 48 char *RealUserName; 49 uid_t RunAsUid; 50 gid_t RunAsGid; 51 char *RunAsUserName; 52 int Verbose = 2; 53 bool DontInitGroups = false; 54 uid_t TrustedUid = 0; 55 BITMAP256 DontBlameSendmail; 56 57 #define BUFSIZE 1024 58 #define ISSEP(c) (isascii(c) && isspace(c)) 59 60 61 static void usage __P((char *)); 62 63 static void 64 usage(progname) 65 char *progname; 66 { 67 fprintf(stderr, 68 "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n", 69 progname); 70 exit(EX_USAGE); 71 } 72 73 int 74 main(argc, argv) 75 int argc; 76 char **argv; 77 { 78 char *progname; 79 char *cfile; 80 bool query = false; 81 bool update = false; 82 bool remove = false; 83 bool inclnull = false; 84 bool foldcase = true; 85 unsigned int nops = 0; 86 int exitstat; 87 int opt; 88 char *typename = NULL; 89 char *mapname = NULL; 90 char *keyname = NULL; 91 char *value = NULL; 92 int mode; 93 int smode; 94 int putflags = 0; 95 long sff = SFF_ROOTOK|SFF_REGONLY; 96 struct passwd *pw; 97 SMDB_DATABASE *database; 98 SMDB_DBENT db_key, db_val; 99 SMDB_DBPARAMS params; 100 SMDB_USER_INFO user_info; 101 #if HASFCHOWN 102 FILE *cfp; 103 char buf[MAXLINE]; 104 #endif 105 static char rnamebuf[MAXNAME]; /* holds RealUserName */ 106 extern char *optarg; 107 extern int optind; 108 109 memset(¶ms, '\0', sizeof params); 110 params.smdbp_cache_size = 1024 * 1024; 111 112 progname = strrchr(argv[0], '/'); 113 if (progname != NULL) 114 progname++; 115 else 116 progname = argv[0]; 117 cfile = _PATH_SENDMAILCF; 118 119 clrbitmap(DontBlameSendmail); 120 RunAsUid = RealUid = getuid(); 121 RunAsGid = RealGid = getgid(); 122 pw = getpwuid(RealUid); 123 if (pw != NULL) 124 (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 125 else 126 (void) sm_snprintf(rnamebuf, sizeof rnamebuf, 127 "Unknown UID %d", (int) RealUid); 128 RunAsUserName = RealUserName = rnamebuf; 129 user_info.smdbu_id = RunAsUid; 130 user_info.smdbu_group_id = RunAsGid; 131 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, 132 SMDB_MAX_USER_NAME_LEN); 133 134 #define OPTIONS "C:fquxN" 135 while ((opt = getopt(argc, argv, OPTIONS)) != -1) 136 { 137 switch (opt) 138 { 139 case 'C': 140 cfile = optarg; 141 break; 142 143 case 'f': 144 foldcase = false; 145 break; 146 147 case 'q': 148 query = true; 149 nops++; 150 break; 151 152 case 'u': 153 update = true; 154 nops++; 155 break; 156 157 case 'x': 158 remove = true; 159 nops++; 160 break; 161 162 case 'N': 163 inclnull = true; 164 break; 165 166 default: 167 usage(progname); 168 assert(0); /* NOTREACHED */ 169 } 170 } 171 172 if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 173 sff |= SFF_NOSLINK; 174 if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 175 sff |= SFF_NOHLINK; 176 if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 177 sff |= SFF_NOWLINK; 178 179 argc -= optind; 180 argv += optind; 181 if ((nops != 1) || 182 (query && argc != 3) || 183 (remove && argc != 3) || 184 (update && argc <= 3)) 185 { 186 usage(progname); 187 assert(0); /* NOTREACHED */ 188 } 189 190 typename = argv[0]; 191 mapname = argv[1]; 192 keyname = argv[2]; 193 if (update) 194 value = argv[3]; 195 196 if (foldcase) 197 { 198 char *lower; 199 200 lower = makelower(keyname); 201 202 /* if it is different then it is a static variable */ 203 if (keyname != lower) 204 keyname = lower; 205 } 206 207 208 #if HASFCHOWN 209 /* Find TrustedUser value in sendmail.cf */ 210 if ((cfp = fopen(cfile, "r")) == NULL) 211 { 212 fprintf(stderr, "%s: %s: %s\n", progname, 213 cfile, sm_errstring(errno)); 214 exit(EX_NOINPUT); 215 } 216 while (fgets(buf, sizeof(buf), cfp) != NULL) 217 { 218 register char *b; 219 220 if ((b = strchr(buf, '\n')) != NULL) 221 *b = '\0'; 222 223 b = buf; 224 switch (*b++) 225 { 226 case 'O': /* option */ 227 if (strncasecmp(b, " TrustedUser", 12) == 0 && 228 !(isascii(b[12]) && isalnum(b[12]))) 229 { 230 b = strchr(b, '='); 231 if (b == NULL) 232 continue; 233 while (isascii(*++b) && isspace(*b)) 234 continue; 235 if (isascii(*b) && isdigit(*b)) 236 TrustedUid = atoi(b); 237 else 238 { 239 TrustedUid = 0; 240 pw = getpwnam(b); 241 if (pw == NULL) 242 fprintf(stderr, 243 "TrustedUser: unknown user %s\n", b); 244 else 245 TrustedUid = pw->pw_uid; 246 } 247 248 # ifdef UID_MAX 249 if (TrustedUid > UID_MAX) 250 { 251 fprintf(stderr, 252 "TrustedUser: uid value (%ld) > UID_MAX (%ld)", 253 (long) TrustedUid, 254 (long) UID_MAX); 255 TrustedUid = 0; 256 } 257 # endif /* UID_MAX */ 258 break; 259 } 260 261 262 default: 263 continue; 264 } 265 } 266 (void) fclose(cfp); 267 #endif /* HASFCHOWN */ 268 269 if (query) 270 { 271 mode = O_RDONLY; 272 smode = S_IRUSR; 273 } 274 else 275 { 276 mode = O_RDWR | O_CREAT; 277 sff |= SFF_CREAT|SFF_NOTEXCL; 278 smode = S_IWUSR; 279 } 280 281 params.smdbp_num_elements = 4096; 282 283 errno = smdb_open_database(&database, mapname, mode, smode, sff, 284 typename, &user_info, ¶ms); 285 if (errno != SMDBE_OK) 286 { 287 char *hint; 288 289 if (errno == SMDBE_UNSUPPORTED_DB_TYPE && 290 (hint = smdb_db_definition(typename)) != NULL) 291 fprintf(stderr, 292 "%s: Need to recompile with -D%s for %s support\n", 293 progname, hint, typename); 294 else 295 fprintf(stderr, 296 "%s: error opening type %s map %s: %s\n", 297 progname, typename, mapname, 298 sm_errstring(errno)); 299 exit(EX_CANTCREAT); 300 } 301 302 (void) database->smdb_sync(database, 0); 303 304 if (geteuid() == 0 && TrustedUid != 0) 305 { 306 errno = database->smdb_set_owner(database, TrustedUid, -1); 307 if (errno != SMDBE_OK) 308 { 309 fprintf(stderr, 310 "WARNING: ownership change on %s failed %s", 311 mapname, sm_errstring(errno)); 312 } 313 } 314 315 exitstat = EX_OK; 316 if (query) 317 { 318 memset(&db_key, '\0', sizeof db_key); 319 memset(&db_val, '\0', sizeof db_val); 320 321 db_key.data = keyname; 322 db_key.size = strlen(keyname); 323 if (inclnull) 324 db_key.size++; 325 326 errno = database->smdb_get(database, &db_key, &db_val, 0); 327 if (errno != SMDBE_OK) 328 { 329 /* XXX - Need to distinguish between not found */ 330 fprintf(stderr, 331 "%s: couldn't find key %s in map %s\n", 332 progname, keyname, mapname); 333 exitstat = EX_UNAVAILABLE; 334 } 335 else 336 { 337 printf("%.*s\n", (int) db_val.size, 338 (char *) db_val.data); 339 } 340 } 341 else if (update) 342 { 343 memset(&db_key, '\0', sizeof db_key); 344 memset(&db_val, '\0', sizeof db_val); 345 346 db_key.data = keyname; 347 db_key.size = strlen(keyname); 348 if (inclnull) 349 db_key.size++; 350 db_val.data = value; 351 db_val.size = strlen(value); 352 if (inclnull) 353 db_val.size++; 354 355 errno = database->smdb_put(database, &db_key, &db_val, 356 putflags); 357 if (errno != SMDBE_OK) 358 { 359 fprintf(stderr, 360 "%s: error updating (%s, %s) in map %s: %s\n", 361 progname, keyname, value, mapname, 362 sm_errstring(errno)); 363 exitstat = EX_IOERR; 364 } 365 } 366 else if (remove) 367 { 368 memset(&db_key, '\0', sizeof db_key); 369 memset(&db_val, '\0', sizeof db_val); 370 371 db_key.data = keyname; 372 db_key.size = strlen(keyname); 373 if (inclnull) 374 db_key.size++; 375 376 errno = database->smdb_del(database, &db_key, 0); 377 378 switch (errno) 379 { 380 case SMDBE_NOT_FOUND: 381 fprintf(stderr, 382 "%s: key %s doesn't exist in map %s\n", 383 progname, keyname, mapname); 384 /* Don't set exitstat */ 385 break; 386 case SMDBE_OK: 387 /* All's well */ 388 break; 389 default: 390 fprintf(stderr, 391 "%s: couldn't remove key %s in map %s (error)\n", 392 progname, keyname, mapname); 393 exitstat = EX_IOERR; 394 break; 395 } 396 } 397 else 398 { 399 assert(0); /* NOT REACHED */ 400 } 401 402 /* 403 ** Now close the database. 404 */ 405 406 errno = database->smdb_close(database); 407 if (errno != SMDBE_OK) 408 { 409 fprintf(stderr, "%s: close(%s): %s\n", 410 progname, mapname, sm_errstring(errno)); 411 exitstat = EX_IOERR; 412 } 413 smdb_free_database(database); 414 415 exit(exitstat); 416 /* NOTREACHED */ 417 return exitstat; 418 } 419