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