[19203] | 1 | /* |
---|
| 2 | * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers. |
---|
| 3 | * All rights reserved. |
---|
| 4 | * |
---|
| 5 | * By using this file, you agree to the terms and conditions set |
---|
| 6 | * forth in the LICENSE file which can be found at the top level of |
---|
| 7 | * the sendmail distribution. |
---|
| 8 | * |
---|
| 9 | */ |
---|
| 10 | |
---|
| 11 | #include <sm/gen.h> |
---|
| 12 | SM_RCSID("@(#)$Id: mpeix.c,v 1.1.1.1 2003-04-08 15:07:35 zacheiss Exp $") |
---|
| 13 | |
---|
| 14 | #ifdef MPE |
---|
| 15 | /* |
---|
| 16 | ** MPE lacks many common functions required across all sendmail programs |
---|
| 17 | ** so we define implementations for these functions here. |
---|
| 18 | */ |
---|
| 19 | |
---|
| 20 | # include <errno.h> |
---|
| 21 | # include <fcntl.h> |
---|
| 22 | # include <limits.h> |
---|
| 23 | # include <mpe.h> |
---|
| 24 | # include <netinet/in.h> |
---|
| 25 | # include <pwd.h> |
---|
| 26 | # include <sys/socket.h> |
---|
| 27 | # include <sys/stat.h> |
---|
| 28 | # include <unistd.h> |
---|
| 29 | # include <sm/conf.h> |
---|
| 30 | |
---|
| 31 | /* |
---|
| 32 | ** CHROOT -- dummy chroot() function |
---|
| 33 | ** |
---|
| 34 | ** The MPE documentation for sendmail says that chroot-based |
---|
| 35 | ** functionality is not implemented because MPE lacks chroot. But |
---|
| 36 | ** rather than mucking around with all the sendmail calls to chroot, |
---|
| 37 | ** we define this dummy function to return an ENOSYS failure just in |
---|
| 38 | ** case a sendmail user attempts to enable chroot-based functionality. |
---|
| 39 | ** |
---|
| 40 | ** Parameters: |
---|
| 41 | ** path -- pathname of new root (ignored). |
---|
| 42 | ** |
---|
| 43 | ** Returns: |
---|
| 44 | ** -1 and errno == ENOSYS (function not implemented) |
---|
| 45 | */ |
---|
| 46 | |
---|
| 47 | int |
---|
| 48 | chroot(path) |
---|
| 49 | char *path; |
---|
| 50 | { |
---|
| 51 | errno = ENOSYS; |
---|
| 52 | return -1; |
---|
| 53 | } |
---|
| 54 | |
---|
| 55 | /* |
---|
| 56 | ** ENDPWENT -- dummy endpwent() function |
---|
| 57 | ** |
---|
| 58 | ** Parameters: |
---|
| 59 | ** none |
---|
| 60 | ** |
---|
| 61 | ** Returns: |
---|
| 62 | ** none |
---|
| 63 | */ |
---|
| 64 | |
---|
| 65 | void |
---|
| 66 | endpwent() |
---|
| 67 | { |
---|
| 68 | return; |
---|
| 69 | } |
---|
| 70 | |
---|
| 71 | /* |
---|
| 72 | ** In addition to missing functions, certain existing MPE functions have |
---|
| 73 | ** slightly different semantics (or bugs) compared to normal Unix OSes. |
---|
| 74 | ** |
---|
| 75 | ** Here we define wrappers for these functions to make them behave in the |
---|
| 76 | ** manner expected by sendmail. |
---|
| 77 | */ |
---|
| 78 | |
---|
| 79 | /* |
---|
| 80 | ** SENDMAIL_MPE_BIND -- shadow function for the standard socket bind() |
---|
| 81 | ** |
---|
| 82 | ** MPE requires GETPRIVMODE() for AF_INET sockets less than port 1024. |
---|
| 83 | ** |
---|
| 84 | ** Parameters: |
---|
| 85 | ** sd -- socket descriptor. |
---|
| 86 | ** addr -- socket address. |
---|
| 87 | ** addrlen -- length of socket address. |
---|
| 88 | ** |
---|
| 89 | ** Results: |
---|
| 90 | ** 0 -- success |
---|
| 91 | ** != 0 -- failure |
---|
| 92 | */ |
---|
| 93 | |
---|
| 94 | #undef bind |
---|
| 95 | int |
---|
| 96 | sendmail_mpe_bind(sd, addr, addrlen) |
---|
| 97 | int sd; |
---|
| 98 | void *addr; |
---|
| 99 | int addrlen; |
---|
| 100 | { |
---|
| 101 | bool priv = false; |
---|
| 102 | int result; |
---|
| 103 | extern void GETPRIVMODE __P((void)); |
---|
| 104 | extern void GETUSERMODE __P((void)); |
---|
| 105 | |
---|
| 106 | if (addrlen == sizeof(struct sockaddr_in) && |
---|
| 107 | ((struct sockaddr_in *)addr)->sin_family == AF_INET) |
---|
| 108 | { |
---|
| 109 | /* AF_INET */ |
---|
| 110 | if (((struct sockaddr_in *)addr)->sin_port > 0 && |
---|
| 111 | ((struct sockaddr_in *)addr)->sin_port < 1024) |
---|
| 112 | { |
---|
| 113 | priv = true; |
---|
| 114 | GETPRIVMODE(); |
---|
| 115 | } |
---|
| 116 | ((struct sockaddr_in *)addr)->sin_addr.s_addr = 0; |
---|
| 117 | result = bind(sd, addr, addrlen); |
---|
| 118 | if (priv) |
---|
| 119 | GETUSERMODE(); |
---|
| 120 | return result; |
---|
| 121 | } |
---|
| 122 | |
---|
| 123 | /* AF_UNIX */ |
---|
| 124 | return bind(sd, addr, addrlen); |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | /* |
---|
| 128 | ** SENDMAIL_MPE__EXIT -- wait for children to terminate, then _exit() |
---|
| 129 | ** |
---|
| 130 | ** Child processes cannot survive the death of their parent on MPE, so |
---|
| 131 | ** we must call wait() before _exit() in order to prevent this |
---|
| 132 | ** infanticide. |
---|
| 133 | ** |
---|
| 134 | ** Parameters: |
---|
| 135 | ** status -- _exit status value. |
---|
| 136 | ** |
---|
| 137 | ** Returns: |
---|
| 138 | ** none. |
---|
| 139 | */ |
---|
| 140 | |
---|
| 141 | #undef _exit |
---|
| 142 | void |
---|
| 143 | sendmail_mpe__exit(status) |
---|
| 144 | int status; |
---|
| 145 | { |
---|
| 146 | int result; |
---|
| 147 | |
---|
| 148 | /* Wait for all children to terminate. */ |
---|
| 149 | do |
---|
| 150 | { |
---|
| 151 | result = wait(NULL); |
---|
| 152 | } while (result > 0 || errno == EINTR); |
---|
| 153 | _exit(status); |
---|
| 154 | } |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | ** SENDMAIL_MPE_EXIT -- wait for children to terminate, then exit() |
---|
| 158 | ** |
---|
| 159 | ** Child processes cannot survive the death of their parent on MPE, so |
---|
| 160 | ** we must call wait() before exit() in order to prevent this |
---|
| 161 | ** infanticide. |
---|
| 162 | ** |
---|
| 163 | ** Parameters: |
---|
| 164 | ** status -- exit status value. |
---|
| 165 | ** |
---|
| 166 | ** Returns: |
---|
| 167 | ** none. |
---|
| 168 | */ |
---|
| 169 | |
---|
| 170 | #undef exit |
---|
| 171 | void |
---|
| 172 | sendmail_mpe_exit(status) |
---|
| 173 | int status; |
---|
| 174 | { |
---|
| 175 | int result; |
---|
| 176 | |
---|
| 177 | /* Wait for all children to terminate. */ |
---|
| 178 | do |
---|
| 179 | { |
---|
| 180 | result = wait(NULL); |
---|
| 181 | } while (result > 0 || errno == EINTR); |
---|
| 182 | exit(status); |
---|
| 183 | } |
---|
| 184 | |
---|
| 185 | /* |
---|
| 186 | ** SENDMAIL_MPE_FCNTL -- shadow function for fcntl() |
---|
| 187 | ** |
---|
| 188 | ** MPE requires sfcntl() for sockets, and fcntl() for everything |
---|
| 189 | ** else. This shadow routine determines the descriptor type and |
---|
| 190 | ** makes the appropriate call. |
---|
| 191 | ** |
---|
| 192 | ** Parameters: |
---|
| 193 | ** same as fcntl(). |
---|
| 194 | ** |
---|
| 195 | ** Returns: |
---|
| 196 | ** same as fcntl(). |
---|
| 197 | */ |
---|
| 198 | |
---|
| 199 | #undef fcntl |
---|
| 200 | int |
---|
| 201 | sendmail_mpe_fcntl(int fildes, int cmd, ...) |
---|
| 202 | { |
---|
| 203 | int len, result; |
---|
| 204 | struct sockaddr sa; |
---|
| 205 | |
---|
| 206 | void *arg; |
---|
| 207 | va_list ap; |
---|
| 208 | |
---|
| 209 | va_start(ap, cmd); |
---|
| 210 | arg = va_arg(ap, void *); |
---|
| 211 | va_end(ap); |
---|
| 212 | |
---|
| 213 | len = sizeof sa; |
---|
| 214 | if (getsockname(fildes, &sa, &len) == -1) |
---|
| 215 | { |
---|
| 216 | if (errno == EAFNOSUPPORT) |
---|
| 217 | { |
---|
| 218 | /* AF_UNIX socket */ |
---|
| 219 | return sfcntl(fildes, cmd, arg); |
---|
| 220 | } |
---|
| 221 | else if (errno == ENOTSOCK) |
---|
| 222 | { |
---|
| 223 | /* file or pipe */ |
---|
| 224 | return fcntl(fildes, cmd, arg); |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | /* unknown getsockname() failure */ |
---|
| 228 | return (-1); |
---|
| 229 | } |
---|
| 230 | else |
---|
| 231 | { |
---|
| 232 | /* AF_INET socket */ |
---|
| 233 | if ((result = sfcntl(fildes, cmd, arg)) != -1 && |
---|
| 234 | cmd == F_GETFL) |
---|
| 235 | result |= O_RDWR; /* fill in some missing flags */ |
---|
| 236 | return result; |
---|
| 237 | } |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | /* |
---|
| 241 | ** SENDMAIL_MPE_GETPWNAM - shadow function for getpwnam() |
---|
| 242 | ** |
---|
| 243 | ** Several issues apply here: |
---|
| 244 | ** |
---|
| 245 | ** - MPE user names MUST have one '.' separator character |
---|
| 246 | ** - MPE user names MUST be in upper case |
---|
| 247 | ** - MPE does not initialize all fields in the passwd struct |
---|
| 248 | ** |
---|
| 249 | ** Parameters: |
---|
| 250 | ** name -- username string. |
---|
| 251 | ** |
---|
| 252 | ** Returns: |
---|
| 253 | ** pointer to struct passwd if found else NULL |
---|
| 254 | */ |
---|
| 255 | |
---|
| 256 | static char *sendmail_mpe_nullstr = ""; |
---|
| 257 | |
---|
| 258 | #undef getpwnam |
---|
| 259 | extern struct passwd *getpwnam(const char *); |
---|
| 260 | |
---|
| 261 | struct passwd * |
---|
| 262 | sendmail_mpe_getpwnam(name) |
---|
| 263 | const char *name; |
---|
| 264 | { |
---|
| 265 | int dots = 0; |
---|
| 266 | int err; |
---|
| 267 | int i = strlen(name); |
---|
| 268 | char *upper; |
---|
| 269 | struct passwd *result = NULL; |
---|
| 270 | |
---|
| 271 | if (i <= 0) |
---|
| 272 | { |
---|
| 273 | errno = EINVAL; |
---|
| 274 | return result; |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | if ((upper = (char *)malloc(i + 1)) != NULL) |
---|
| 278 | { |
---|
| 279 | /* upshift the username parameter and count the dots */ |
---|
| 280 | while (i >= 0) |
---|
| 281 | { |
---|
| 282 | if (name[i] == '.') |
---|
| 283 | { |
---|
| 284 | dots++; |
---|
| 285 | upper[i] = '.'; |
---|
| 286 | } |
---|
| 287 | else |
---|
| 288 | upper[i] = toupper(name[i]); |
---|
| 289 | i--; |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | if (dots != 1) |
---|
| 293 | { |
---|
| 294 | /* prevent bug when dots == 0 */ |
---|
| 295 | err = EINVAL; |
---|
| 296 | } |
---|
| 297 | else if ((result = getpwnam(upper)) != NULL) |
---|
| 298 | { |
---|
| 299 | /* init the uninitialized fields */ |
---|
| 300 | result->pw_gecos = sendmail_mpe_nullstr; |
---|
| 301 | result->pw_passwd = sendmail_mpe_nullstr; |
---|
| 302 | result->pw_age = sendmail_mpe_nullstr; |
---|
| 303 | result->pw_comment = sendmail_mpe_nullstr; |
---|
| 304 | result->pw_audid = 0; |
---|
| 305 | result->pw_audflg = 0; |
---|
| 306 | } |
---|
| 307 | err = errno; |
---|
| 308 | free(upper); |
---|
| 309 | } |
---|
| 310 | errno = err; |
---|
| 311 | return result; |
---|
| 312 | } |
---|
| 313 | |
---|
| 314 | /* |
---|
| 315 | ** SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid() |
---|
| 316 | ** |
---|
| 317 | ** Initializes the uninitalized fields in the passwd struct. |
---|
| 318 | ** |
---|
| 319 | ** Parameters: |
---|
| 320 | ** uid -- uid to obtain passwd data for |
---|
| 321 | ** |
---|
| 322 | ** Returns: |
---|
| 323 | ** pointer to struct passwd or NULL if not found |
---|
| 324 | */ |
---|
| 325 | |
---|
| 326 | #undef getpwuid |
---|
| 327 | extern struct passwd *getpwuid __P((uid_t)); |
---|
| 328 | |
---|
| 329 | struct passwd * |
---|
| 330 | sendmail_mpe_getpwuid(uid) |
---|
| 331 | uid_t uid; |
---|
| 332 | { |
---|
| 333 | struct passwd *result; |
---|
| 334 | |
---|
| 335 | if ((result = getpwuid(uid)) != NULL) |
---|
| 336 | { |
---|
| 337 | /* initialize the uninitialized fields */ |
---|
| 338 | result->pw_gecos = sendmail_mpe_nullstr; |
---|
| 339 | result->pw_passwd = sendmail_mpe_nullstr; |
---|
| 340 | result->pw_age = sendmail_mpe_nullstr; |
---|
| 341 | result->pw_comment = sendmail_mpe_nullstr; |
---|
| 342 | result->pw_audid = 0; |
---|
| 343 | result->pw_audflg = 0; |
---|
| 344 | } |
---|
| 345 | return result; |
---|
| 346 | } |
---|
| 347 | |
---|
| 348 | /* |
---|
| 349 | ** OK boys and girls, time for some serious voodoo! |
---|
| 350 | ** |
---|
| 351 | ** MPE does not have a complete implementation of POSIX users and groups: |
---|
| 352 | ** |
---|
| 353 | ** - there is no uid 0 superuser |
---|
| 354 | ** - setuid/setgid file permission bits exist but have no-op functionality |
---|
| 355 | ** - setgid() exists, but only supports new gid == current gid (boring!) |
---|
| 356 | ** - setuid() forces a gid change to the new uid's primary (and only) gid |
---|
| 357 | ** |
---|
| 358 | ** ...all of which thoroughly annoys sendmail. |
---|
| 359 | ** |
---|
| 360 | ** So what to do? We can't go on an #ifdef MPE rampage throughout |
---|
| 361 | ** sendmail, because there are only about a zillion references to uid 0 |
---|
| 362 | ** and so success (and security) would probably be rather dubious by the |
---|
| 363 | ** time we finished. |
---|
| 364 | ** |
---|
| 365 | ** Instead we take the approach of defining wrapper functions for the |
---|
| 366 | ** gid/uid management functions getegid(), geteuid(), setgid(), and |
---|
| 367 | ** setuid() in order to implement the following model: |
---|
| 368 | ** |
---|
| 369 | ** - the sendmail program thinks it is a setuid-root (uid 0) program |
---|
| 370 | ** - uid 0 is recognized as being valid, but does not grant extra powers |
---|
| 371 | ** - MPE priv mode allows sendmail to call setuid(), not uid 0 |
---|
| 372 | ** - file access is still controlled by the real non-zero uid |
---|
| 373 | ** - the other programs (vacation, etc) have standard MPE POSIX behavior |
---|
| 374 | ** |
---|
| 375 | ** This emulation model is activated by use of the program file setgid and |
---|
| 376 | ** setuid mode bits which exist but are unused by MPE. If the setgid mode |
---|
| 377 | ** bit is on, then gid emulation will be enabled. If the setuid mode bit is |
---|
| 378 | ** on, then uid emulation will be enabled. So for the mail daemon, we need |
---|
| 379 | ** to do chmod u+s,g+s /SENDMAIL/CURRENT/SENDMAIL. |
---|
| 380 | ** |
---|
| 381 | ** The following flags determine the current emulation state: |
---|
| 382 | ** |
---|
| 383 | ** true == emulation enabled |
---|
| 384 | ** false == emulation disabled, use unmodified MPE semantics |
---|
| 385 | */ |
---|
| 386 | |
---|
| 387 | static bool sendmail_mpe_flaginit = false; |
---|
| 388 | static bool sendmail_mpe_gidflag = false; |
---|
| 389 | static bool sendmail_mpe_uidflag = false; |
---|
| 390 | |
---|
| 391 | /* |
---|
| 392 | ** SENDMAIL_MPE_GETMODE -- return the mode bits for the current process |
---|
| 393 | ** |
---|
| 394 | ** Parameters: |
---|
| 395 | ** none. |
---|
| 396 | ** |
---|
| 397 | ** Returns: |
---|
| 398 | ** file mode bits for the current process program file. |
---|
| 399 | */ |
---|
| 400 | |
---|
| 401 | mode_t |
---|
| 402 | sendmail_mpe_getmode() |
---|
| 403 | { |
---|
| 404 | int status = 666; |
---|
| 405 | int myprogram_length; |
---|
| 406 | int myprogram_syntax = 2; |
---|
| 407 | char formaldesig[28]; |
---|
| 408 | char myprogram[PATH_MAX + 2]; |
---|
| 409 | char path[PATH_MAX + 1]; |
---|
| 410 | struct stat st; |
---|
| 411 | extern HPMYPROGRAM __P((int parms, char *formaldesig, int *status, |
---|
| 412 | int *length, char *myprogram, |
---|
| 413 | int *myprogram_length, int *myprogram_syntax)); |
---|
| 414 | |
---|
| 415 | myprogram_length = sizeof(myprogram); |
---|
| 416 | HPMYPROGRAM(6, formaldesig, &status, NULL, myprogram, |
---|
| 417 | &myprogram_length, &myprogram_syntax); |
---|
| 418 | |
---|
| 419 | /* should not occur, do not attempt emulation */ |
---|
| 420 | if (status != 0) |
---|
| 421 | return 0; |
---|
| 422 | |
---|
| 423 | memcpy(&path, &myprogram[1], myprogram_length - 2); |
---|
| 424 | path[myprogram_length - 2] = '\0'; |
---|
| 425 | |
---|
| 426 | /* should not occur, do not attempt emulation */ |
---|
| 427 | if (stat(path, &st) < 0) |
---|
| 428 | return 0; |
---|
| 429 | |
---|
| 430 | return st.st_mode; |
---|
| 431 | } |
---|
| 432 | |
---|
| 433 | /* |
---|
| 434 | ** SENDMAIL_MPE_EMULGID -- should we perform gid emulation? |
---|
| 435 | ** |
---|
| 436 | ** If !sendmail_mpe_flaginit then obtain the mode bits to determine |
---|
| 437 | ** if the setgid bit is on, we want gid emulation and so set |
---|
| 438 | ** sendmail_mpe_gidflag to true. Otherwise we do not want gid emulation |
---|
| 439 | ** and so set sendmail_mpe_gidflag to false. |
---|
| 440 | ** |
---|
| 441 | ** Parameters: |
---|
| 442 | ** none. |
---|
| 443 | ** |
---|
| 444 | ** Returns: |
---|
| 445 | ** true -- perform gid emulation |
---|
| 446 | ** false -- do not perform gid emulation |
---|
| 447 | */ |
---|
| 448 | |
---|
| 449 | bool |
---|
| 450 | sendmail_mpe_emulgid() |
---|
| 451 | { |
---|
| 452 | if (!sendmail_mpe_flaginit) |
---|
| 453 | { |
---|
| 454 | mode_t mode; |
---|
| 455 | |
---|
| 456 | mode = sendmail_mpe_getmode(); |
---|
| 457 | sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID); |
---|
| 458 | sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID); |
---|
| 459 | sendmail_mpe_flaginit = true; |
---|
| 460 | } |
---|
| 461 | return sendmail_mpe_gidflag; |
---|
| 462 | } |
---|
| 463 | |
---|
| 464 | /* |
---|
| 465 | ** SENDMAIL_MPE_EMULUID -- should we perform uid emulation? |
---|
| 466 | ** |
---|
| 467 | ** If sendmail_mpe_uidflag == -1 then obtain the mode bits to determine |
---|
| 468 | ** if the setuid bit is on, we want uid emulation and so set |
---|
| 469 | ** sendmail_mpe_uidflag to true. Otherwise we do not want uid emulation |
---|
| 470 | ** and so set sendmail_mpe_uidflag to false. |
---|
| 471 | ** |
---|
| 472 | ** Parameters: |
---|
| 473 | ** none. |
---|
| 474 | ** |
---|
| 475 | ** Returns: |
---|
| 476 | ** true -- perform uid emulation |
---|
| 477 | ** false -- do not perform uid emulation |
---|
| 478 | */ |
---|
| 479 | |
---|
| 480 | bool |
---|
| 481 | sendmail_mpe_emuluid() |
---|
| 482 | { |
---|
| 483 | if (!sendmail_mpe_flaginit) |
---|
| 484 | { |
---|
| 485 | mode_t mode; |
---|
| 486 | |
---|
| 487 | mode = sendmail_mpe_getmode(); |
---|
| 488 | sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID); |
---|
| 489 | sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID); |
---|
| 490 | sendmail_mpe_flaginit = true; |
---|
| 491 | } |
---|
| 492 | return sendmail_mpe_uidflag; |
---|
| 493 | } |
---|
| 494 | |
---|
| 495 | /* |
---|
| 496 | ** SENDMAIL_MPE_GETEGID -- shadow function for getegid() |
---|
| 497 | ** |
---|
| 498 | ** If emulation mode is in effect and the saved egid has been |
---|
| 499 | ** initialized, return the saved egid; otherwise return the value of the |
---|
| 500 | ** real getegid() function. |
---|
| 501 | ** |
---|
| 502 | ** Parameters: |
---|
| 503 | ** none. |
---|
| 504 | ** |
---|
| 505 | ** Returns: |
---|
| 506 | ** emulated egid if present, else true egid. |
---|
| 507 | */ |
---|
| 508 | |
---|
| 509 | static uid_t sendmail_mpe_egid = -1; |
---|
| 510 | |
---|
| 511 | #undef getegid |
---|
| 512 | gid_t |
---|
| 513 | sendmail_mpe_getegid() |
---|
| 514 | { |
---|
| 515 | if (sendmail_mpe_emulgid() && sendmail_mpe_egid != -1) |
---|
| 516 | return sendmail_mpe_egid; |
---|
| 517 | return getegid(); |
---|
| 518 | } |
---|
| 519 | |
---|
| 520 | /* |
---|
| 521 | ** SENDMAIL_MPE_GETEUID -- shadow function for geteuid() |
---|
| 522 | ** |
---|
| 523 | ** If emulation mode is in effect, return the saved euid; otherwise |
---|
| 524 | ** return the value of the real geteuid() function. |
---|
| 525 | ** |
---|
| 526 | ** Note that the initial value of the saved euid is zero, to simulate |
---|
| 527 | ** a setuid-root program. |
---|
| 528 | ** |
---|
| 529 | ** Parameters: |
---|
| 530 | ** none |
---|
| 531 | ** |
---|
| 532 | ** Returns: |
---|
| 533 | ** emulated euid if in emulation mode, else true euid. |
---|
| 534 | */ |
---|
| 535 | |
---|
| 536 | static uid_t sendmail_mpe_euid = 0; |
---|
| 537 | |
---|
| 538 | #undef geteuid |
---|
| 539 | uid_t |
---|
| 540 | sendmail_mpe_geteuid() |
---|
| 541 | { |
---|
| 542 | if (sendmail_mpe_emuluid()) |
---|
| 543 | return sendmail_mpe_euid; |
---|
| 544 | return geteuid(); |
---|
| 545 | } |
---|
| 546 | |
---|
| 547 | /* |
---|
| 548 | ** SENDMAIL_MPE_SETGID -- shadow function for setgid() |
---|
| 549 | ** |
---|
| 550 | ** Simulate a call to setgid() without actually calling the real |
---|
| 551 | ** function. Implement the expected uid 0 semantics. |
---|
| 552 | ** |
---|
| 553 | ** Note that sendmail will also be calling setuid() which will force an |
---|
| 554 | ** implicit real setgid() to the proper primary gid. So it doesn't matter |
---|
| 555 | ** that we don't actually alter the real gid in this shadow function. |
---|
| 556 | ** |
---|
| 557 | ** Parameters: |
---|
| 558 | ** gid -- desired gid. |
---|
| 559 | ** |
---|
| 560 | ** Returns: |
---|
| 561 | ** 0 -- emulated success |
---|
| 562 | ** -1 -- emulated failure |
---|
| 563 | */ |
---|
| 564 | |
---|
| 565 | #undef setgid |
---|
| 566 | int |
---|
| 567 | sendmail_mpe_setgid(gid) |
---|
| 568 | gid_t gid; |
---|
| 569 | { |
---|
| 570 | if (sendmail_mpe_emulgid()) |
---|
| 571 | { |
---|
| 572 | if (gid == getgid() || sendmail_mpe_euid == 0) |
---|
| 573 | { |
---|
| 574 | sendmail_mpe_egid = gid; |
---|
| 575 | return 0; |
---|
| 576 | } |
---|
| 577 | errno = EINVAL; |
---|
| 578 | return -1; |
---|
| 579 | } |
---|
| 580 | return setgid(gid); |
---|
| 581 | } |
---|
| 582 | |
---|
| 583 | /* |
---|
| 584 | ** SENDMAIL_MPE_SETUID -- shadow function for setuid() |
---|
| 585 | ** |
---|
| 586 | ** setuid() is broken as of MPE 7.0 in that it changes the current |
---|
| 587 | ** working directory to be the home directory of the new uid. Thus |
---|
| 588 | ** we must obtain the cwd and restore it after the setuid(). |
---|
| 589 | ** |
---|
| 590 | ** Note that expected uid 0 semantics have been added, as well as |
---|
| 591 | ** remembering the new uid for later use by the other shadow functions. |
---|
| 592 | ** |
---|
| 593 | ** Parameters: |
---|
| 594 | ** uid -- desired uid. |
---|
| 595 | ** |
---|
| 596 | ** Returns: |
---|
| 597 | ** 0 -- success |
---|
| 598 | ** -1 -- failure |
---|
| 599 | ** |
---|
| 600 | ** Globals: |
---|
| 601 | ** sendmail_mpe_euid |
---|
| 602 | */ |
---|
| 603 | |
---|
| 604 | #undef setuid |
---|
| 605 | int |
---|
| 606 | sendmail_mpe_setuid(uid) |
---|
| 607 | uid_t uid; |
---|
| 608 | { |
---|
| 609 | char *cwd; |
---|
| 610 | char cwd_buf[PATH_MAX + 1]; |
---|
| 611 | int result; |
---|
| 612 | extern void GETPRIVMODE __P((void)); |
---|
| 613 | extern void GETUSERMODE __P((void)); |
---|
| 614 | |
---|
| 615 | if (sendmail_mpe_emuluid()) |
---|
| 616 | { |
---|
| 617 | if (uid == 0) |
---|
| 618 | { |
---|
| 619 | if (sendmail_mpe_euid != 0) |
---|
| 620 | { |
---|
| 621 | errno = EINVAL; |
---|
| 622 | return -1; |
---|
| 623 | } |
---|
| 624 | sendmail_mpe_euid = 0; |
---|
| 625 | return 0; |
---|
| 626 | } |
---|
| 627 | |
---|
| 628 | /* Preserve the current working directory */ |
---|
| 629 | if ((cwd = getcwd(cwd_buf, PATH_MAX + 1)) == NULL) |
---|
| 630 | return -1; |
---|
| 631 | |
---|
| 632 | GETPRIVMODE(); |
---|
| 633 | result = setuid(uid); |
---|
| 634 | GETUSERMODE(); |
---|
| 635 | |
---|
| 636 | /* Restore the current working directory */ |
---|
| 637 | chdir(cwd_buf); |
---|
| 638 | |
---|
| 639 | if (result == 0) |
---|
| 640 | sendmail_mpe_euid = uid; |
---|
| 641 | |
---|
| 642 | return result; |
---|
| 643 | } |
---|
| 644 | return setuid(uid); |
---|
| 645 | } |
---|
| 646 | #endif /* MPE */ |
---|