Wed Jul 1 07:26:42 2015 UTC ()
Pull up following revision(s) (requested by dholland in ticket #860):
	usr.bin/calendar/calendar.c: revision 1.51
Correct privilege handling problems in calendar -a (which runs as root
from /etc/daily); do not exec other programs while the real uid is
still 0.
Also, clear the supplementary groups list up front and call initgroups
when becoming another user, to avoid leaking any extra group
privileges that we might have.
And finally, don't silently ignore errors changing uid and gid; those
are serious if they happen.


(bouyer)
diff -r1.50 -r1.50.4.1 src/usr.bin/calendar/calendar.c

cvs diff -r1.50 -r1.50.4.1 src/usr.bin/calendar/calendar.c (expand / switch to unified diff)

--- src/usr.bin/calendar/calendar.c 2013/11/09 15:57:15 1.50
+++ src/usr.bin/calendar/calendar.c 2015/07/01 07:26:42 1.50.4.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: calendar.c,v 1.50 2013/11/09 15:57:15 christos Exp $ */ 1/* $NetBSD: calendar.c,v 1.50.4.1 2015/07/01 07:26:42 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1989, 1993, 1994 4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -29,35 +29,36 @@ @@ -29,35 +29,36 @@
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33#ifndef lint 33#ifndef lint
34__COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 34__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
35 The Regents of the University of California. All rights reserved."); 35 The Regents of the University of California. All rights reserved.");
36#endif /* not lint */ 36#endif /* not lint */
37 37
38#ifndef lint 38#ifndef lint
39#if 0 39#if 0
40static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95"; 40static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95";
41#endif 41#endif
42__RCSID("$NetBSD: calendar.c,v 1.50 2013/11/09 15:57:15 christos Exp $"); 42__RCSID("$NetBSD: calendar.c,v 1.50.4.1 2015/07/01 07:26:42 bouyer Exp $");
43#endif /* not lint */ 43#endif /* not lint */
44 44
45#include <sys/param.h> 45#include <sys/param.h>
46#include <sys/time.h> 46#include <sys/time.h>
47#include <sys/stat.h> 47#include <sys/stat.h>
48#include <sys/uio.h> 48#include <sys/uio.h>
49#include <sys/wait.h> 49#include <sys/wait.h>
50 50
 51#include <assert.h>
51#include <ctype.h> 52#include <ctype.h>
52#include <err.h> 53#include <err.h>
53#include <errno.h> 54#include <errno.h>
54#include <fcntl.h> 55#include <fcntl.h>
55#include <pwd.h> 56#include <pwd.h>
56#include <stdbool.h> 57#include <stdbool.h>
57#include <stdio.h> 58#include <stdio.h>
58#include <stdlib.h> 59#include <stdlib.h>
59#include <string.h> 60#include <string.h>
60#include <time.h> 61#include <time.h>
61#include <tzfile.h> 62#include <tzfile.h>
62#include <unistd.h> 63#include <unistd.h>
63 64
@@ -102,26 +103,27 @@ static struct iovec header[] = { @@ -102,26 +103,27 @@ static struct iovec header[] = {
102 103
103static const char *days[] = { 104static const char *days[] = {
104 "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL, 105 "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
105}; 106};
106 107
107static const char *months[] = { 108static const char *months[] = {
108 "jan", "feb", "mar", "apr", "may", "jun", 109 "jan", "feb", "mar", "apr", "may", "jun",
109 "jul", "aug", "sep", "oct", "nov", "dec", NULL, 110 "jul", "aug", "sep", "oct", "nov", "dec", NULL,
110}; 111};
111 112
112static void atodays(int, char *, unsigned short *); 113static void atodays(int, char *, unsigned short *);
113static void cal(void); 114static void cal(void);
114static void closecal(FILE *); 115static void closecal(FILE *);
 116static void changeuser(void);
115static int getday(char *); 117static int getday(char *);
116static int getfield(char *, char **, int *); 118static int getfield(char *, char **, int *);
117static void getmmdd(struct tm *, char *); 119static void getmmdd(struct tm *, char *);
118static int getmonth(char *); 120static int getmonth(char *);
119static bool isnow(char *); 121static bool isnow(char *);
120static FILE *opencal(FILE **); 122static FILE *opencal(FILE **);
121static void settime(void); 123static void settime(void);
122static void usage(void) __dead; 124static void usage(void) __dead;
123 125
124int 126int
125main(int argc, char **argv) 127main(int argc, char **argv)
126{ 128{
127 int ch; 129 int ch;
@@ -161,32 +163,44 @@ main(int argc, char **argv) @@ -161,32 +163,44 @@ main(int argc, char **argv)
161 } 163 }
162 argc -= optind; 164 argc -= optind;
163 argv += optind; 165 argv += optind;
164 166
165 if (argc) 167 if (argc)
166 usage(); 168 usage();
167 169
168 settime(); 170 settime();
169 if (doall) { 171 if (doall) {
170 /* 172 /*
171 * XXX - This ignores the user's CALENDAR_DIR variable. 173 * XXX - This ignores the user's CALENDAR_DIR variable.
172 * Run under user's login shell? 174 * Run under user's login shell?
173 */ 175 */
 176 if (setgroups(0, NULL) == -1) {
 177 err(EXIT_FAILURE, "setgroups");
 178 }
174 while ((pw = getpwent()) != NULL) { 179 while ((pw = getpwent()) != NULL) {
175 (void)setegid(pw->pw_gid); 180 if (setegid(pw->pw_gid) == -1) {
176 (void)seteuid(pw->pw_uid); 181 warn("%s: setegid", pw->pw_name);
177 if (chdir(pw->pw_dir) != -1) 182 continue;
 183 }
 184 if (seteuid(pw->pw_uid) == -1) {
 185 warn("%s: seteuid", pw->pw_name);
 186 continue;
 187 }
 188 if (chdir(pw->pw_dir) != -1) {
178 cal(); 189 cal();
179 (void)seteuid(0); 190 }
 191 if (seteuid(0) == -1) {
 192 warn("%s: seteuid back to 0", pw->pw_name);
 193 }
180 } 194 }
181 } else if ((caldir = getenv("CALENDAR_DIR")) != NULL) { 195 } else if ((caldir = getenv("CALENDAR_DIR")) != NULL) {
182 if (chdir(caldir) != -1) 196 if (chdir(caldir) != -1)
183 cal(); 197 cal();
184 } else if ((pw = getpwuid(geteuid())) != NULL) { 198 } else if ((pw = getpwuid(geteuid())) != NULL) {
185 if (chdir(pw->pw_dir) != -1) 199 if (chdir(pw->pw_dir) != -1)
186 cal(); 200 cal();
187 } 201 }
188 return 0; 202 return 0;
189} 203}
190 204
191static void 205static void
192cal(void) 206cal(void)
@@ -419,26 +433,30 @@ opencal(FILE **in) @@ -419,26 +433,30 @@ opencal(FILE **in)
419 case 0: 433 case 0:
420 /* child */ 434 /* child */
421 /* set stdin to calendar file */ 435 /* set stdin to calendar file */
422 if (fd != STDIN_FILENO) { 436 if (fd != STDIN_FILENO) {
423 (void)dup2(fd, STDIN_FILENO); 437 (void)dup2(fd, STDIN_FILENO);
424 (void)close(fd); 438 (void)close(fd);
425 } 439 }
426 /* set stdout to pipe input */ 440 /* set stdout to pipe input */
427 if (pdes[1] != STDOUT_FILENO) { 441 if (pdes[1] != STDOUT_FILENO) {
428 (void)dup2(pdes[1], STDOUT_FILENO); 442 (void)dup2(pdes[1], STDOUT_FILENO);
429 (void)close(pdes[1]); 443 (void)close(pdes[1]);
430 } 444 }
431 (void)close(pdes[0]); 445 (void)close(pdes[0]);
 446 if (doall) {
 447 /* become the user properly */
 448 changeuser();
 449 }
432 /* tell CPP to only open regular files */ 450 /* tell CPP to only open regular files */
433 if(!cpp_restricted && setenv("CPP_RESTRICTED", "", 1) == -1) 451 if(!cpp_restricted && setenv("CPP_RESTRICTED", "", 1) == -1)
434 err(EXIT_FAILURE, "Cannot restrict cpp"); 452 err(EXIT_FAILURE, "Cannot restrict cpp");
435 cpp_restricted = true; 453 cpp_restricted = true;
436 454
437 (void)execl(_PATH_CPP, "cpp", "-traditional", "-P", "-I.", 455 (void)execl(_PATH_CPP, "cpp", "-traditional", "-P", "-I.",
438 "-I" _PATH_CALENDARS, NULL); 456 "-I" _PATH_CALENDARS, NULL);
439 err(EXIT_FAILURE, "Cannot exec `%s'", _PATH_CPP); 457 err(EXIT_FAILURE, "Cannot exec `%s'", _PATH_CPP);
440 /*NOTREACHED*/ 458 /*NOTREACHED*/
441 default: 459 default:
442 /* parent -- fdopen *in to pipe output */ 460 /* parent -- fdopen *in to pipe output */
443 *in = fdopen(pdes[0], "r"); 461 *in = fdopen(pdes[0], "r");
444 (void)close(pdes[1]); 462 (void)close(pdes[1]);
@@ -485,49 +503,81 @@ closecal(FILE *fp) @@ -485,49 +503,81 @@ closecal(FILE *fp)
485 switch (fork()) { 503 switch (fork()) {
486 case -1: 504 case -1:
487 /* error */ 505 /* error */
488 (void)close(pdes[0]); 506 (void)close(pdes[0]);
489 (void)close(pdes[1]); 507 (void)close(pdes[1]);
490 break; 508 break;
491 case 0: 509 case 0:
492 /* child -- set stdin to pipe output */ 510 /* child -- set stdin to pipe output */
493 if (pdes[0] != STDIN_FILENO) { 511 if (pdes[0] != STDIN_FILENO) {
494 (void)dup2(pdes[0], STDIN_FILENO); 512 (void)dup2(pdes[0], STDIN_FILENO);
495 (void)close(pdes[0]); 513 (void)close(pdes[0]);
496 } 514 }
497 (void)close(pdes[1]); 515 (void)close(pdes[1]);
 516 if (doall) {
 517 /* become the user properly */
 518 changeuser();
 519 }
498 (void)execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", 520 (void)execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
499 "\"Reminder Service\"", "-f", "root", NULL); 521 "\"Reminder Service\"", "-f", "root", NULL);
500 err(EXIT_FAILURE, "Cannot exec `%s'", _PATH_SENDMAIL); 522 err(EXIT_FAILURE, "Cannot exec `%s'", _PATH_SENDMAIL);
501 /*NOTREACHED*/ 523 /*NOTREACHED*/
502 default: 524 default:
503 /* parent -- write to pipe input */ 525 /* parent -- write to pipe input */
504 (void)close(pdes[0]); 526 (void)close(pdes[0]);
505 527
506 header[1].iov_base = header[3].iov_base = (void *)pw->pw_name; 528 header[1].iov_base = header[3].iov_base = (void *)pw->pw_name;
507 header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); 529 header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
508 (void)writev(pdes[1], header, 7); 530 (void)writev(pdes[1], header, 7);
509 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) 531 while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
510 (void)write(pdes[1], buf, (size_t)nread); 532 (void)write(pdes[1], buf, (size_t)nread);
511 (void)close(pdes[1]); 533 (void)close(pdes[1]);
512 break; 534 break;
513 } 535 }
514 536
515done: (void)fclose(fp); 537done: (void)fclose(fp);
516 (void)unlink(path); 538 (void)unlink(path);
517 while (wait(&status) != -1) 539 while (wait(&status) != -1)
518 continue; 540 continue;
519} 541}
520 542
 543static void
 544changeuser(void)
 545{
 546 uid_t uid;
 547 gid_t gid;
 548
 549 uid = geteuid();
 550 gid = getegid();
 551 assert(uid == pw->pw_uid);
 552 assert(gid == pw->pw_gid);
 553
 554 if (seteuid(0) == -1) {
 555 err(EXIT_FAILURE, "%s: changing user: cannot reassert uid 0",
 556 pw->pw_name);
 557 }
 558 if (setgid(gid) == -1) {
 559 err(EXIT_FAILURE, "%s: cannot assume gid %d",
 560 pw->pw_name, (int)gid);
 561 }
 562 if (initgroups(pw->pw_name, gid) == -1) {
 563 err(EXIT_FAILURE, "%s: cannot initgroups", pw->pw_name);
 564 }
 565 if (setuid(uid) == -1) {
 566 err(EXIT_FAILURE, "%s: cannot assume uid %d",
 567 pw->pw_name, (int)uid);
 568 }
 569}
 570
521static int 571static int
522getmonth(char *s) 572getmonth(char *s)
523{ 573{
524 const char **p; 574 const char **p;
525 575
526 for (p = months; *p; ++p) 576 for (p = months; *p; ++p)
527 if (strncasecmp(s, *p, 3) == 0) 577 if (strncasecmp(s, *p, 3) == 0)
528 return (int)(p - months) + 1; 578 return (int)(p - months) + 1;
529 return 0; 579 return 0;
530} 580}
531 581
532static int 582static int
533getday(char *s) 583getday(char *s)