Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: session_manager_service.cc

Issue 553016: port to use centralized constants files, and add input validation (Closed)
Patch Set: address shell injection, otehr comments (per wad) Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « session_manager_service.h ('k') | session_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009-2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "login_manager/session_manager_service.h" 5 #include "login_manager/session_manager_service.h"
6 6
7 #include <glib.h> 7 #include <glib.h>
8 #include <grp.h> 8 #include <grp.h>
9 #include <sys/errno.h> 9 #include <sys/errno.h>
10 #include <sys/types.h> 10 #include <sys/types.h>
11 #include <sys/wait.h> 11 #include <sys/wait.h>
12 #include <signal.h> 12 #include <signal.h>
13 #include <stdio.h> 13 #include <stdio.h>
14 #include <unistd.h> 14 #include <unistd.h>
15 15
16 #include <base/basictypes.h> 16 #include <base/basictypes.h>
17 #include <base/command_line.h> 17 #include <base/command_line.h>
18 #include <base/logging.h> 18 #include <base/logging.h>
19 #include <base/string_util.h>
19 #include <chromeos/dbus/dbus.h> 20 #include <chromeos/dbus/dbus.h>
20 21
21 #include "login_manager/child_job.h" 22 #include "login_manager/child_job.h"
22 #include "login_manager/interface.h" 23 #include "login_manager/interface.h"
23 24
24 // Forcibly namespace the dbus-bindings generated server bindings instead of 25 // Forcibly namespace the dbus-bindings generated server bindings instead of
25 // modifying the files afterward. 26 // modifying the files afterward.
26 namespace login_manager { // NOLINT 27 namespace login_manager { // NOLINT
27 namespace gobject { // NOLINT 28 namespace gobject { // NOLINT
28 #include "login_manager/bindings/server.h" 29 #include "login_manager/bindings/server.h"
29 } // namespace gobject 30 } // namespace gobject
30 } // namespace login_manager 31 } // namespace login_manager
31 32
32 namespace login_manager { 33 namespace login_manager {
33 34
35 using std::string;
36
37 //static
38 const uint32 SessionManagerService::kMaxEmailSize = 200;
39 //static
40 const char SessionManagerService::kEmailSeparator = '@';
41 //static
42 const char SessionManagerService::kLegalCharacters[] =
43 "abcdefghijklmnopqrstuvwxyz"
44 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
45 ".@1234567890";
46
34 SessionManagerService::SessionManagerService(ChildJob* child) 47 SessionManagerService::SessionManagerService(ChildJob* child)
35 : child_job_(child), 48 : child_job_(child),
36 exit_on_child_done_(false), 49 exit_on_child_done_(false),
37 main_loop_(g_main_loop_new(NULL, FALSE)) { 50 child_pgid_(0),
51 main_loop_(g_main_loop_new(NULL, FALSE)),
52 system_(new SystemUtils) {
38 CHECK(child); 53 CHECK(child);
39 SetupHandlers(); 54 SetupHandlers();
40 } 55 }
41
42 SessionManagerService::SessionManagerService(ChildJob* child,
43 bool exit_on_child_done)
44 : child_job_(child),
45 exit_on_child_done_(exit_on_child_done),
46 main_loop_(g_main_loop_new(NULL, FALSE)) {
47 CHECK(child);
48 SetupHandlers();
49 }
50 56
51 SessionManagerService::~SessionManagerService() { 57 SessionManagerService::~SessionManagerService() {
52 g_main_loop_unref(main_loop_); 58 g_main_loop_unref(main_loop_);
53 59
54 struct sigaction action; 60 struct sigaction action;
55 memset(&action, 0, sizeof(action)); 61 memset(&action, 0, sizeof(action));
56 action.sa_handler = SIG_DFL; 62 action.sa_handler = SIG_DFL;
57 CHECK(sigaction(SIGUSR1, &action, NULL) == 0); 63 CHECK(sigaction(SIGUSR1, &action, NULL) == 0);
58 } 64 }
59 65
(...skipping 23 matching lines...) Expand all
83 return false; 89 return false;
84 } 90 }
85 return true; 91 return true;
86 } 92 }
87 93
88 bool SessionManagerService::Run() { 94 bool SessionManagerService::Run() {
89 if (!main_loop_) { 95 if (!main_loop_) {
90 LOG(ERROR) << "You must have a main loop to call Run."; 96 LOG(ERROR) << "You must have a main loop to call Run.";
91 return false; 97 return false;
92 } 98 }
93 int pid = RunChild();
94 if (pid == -1) {
95 // We couldn't fork...maybe we should wait and try again later?
96 PLOG(ERROR) << "Failed to fork!";
97 99
100 if (should_run_child()) {
101 int pid = RunChild();
102 if (pid == -1) {
103 // We couldn't fork...maybe we should wait and try again later?
104 PLOG(ERROR) << "Failed to fork!";
105 return false;
106 }
107 child_pgid_ = -pid;
98 } else { 108 } else {
99 // In the parent. 109 AllowGracefulExit();
100 g_main_loop_run(main_loop_);
101 } 110 }
111
112 // In the parent.
113 g_main_loop_run(main_loop_);
114
115 if (child_pgid_ != 0) // otherwise, we never created a child.
116 CleanupChildren(3);
117
102 return true; 118 return true;
103 } 119 }
104 120
105 int SessionManagerService::RunChild() { 121 int SessionManagerService::RunChild() {
106 int pid = fork(); 122 int pid = fork();
107 if (pid == 0) { 123 if (pid == 0) {
108 // In the child. 124 // In the child.
109 child_job_->Run(); 125 child_job_->Run();
110 exit(1); // Run() is not supposed to return. 126 exit(1); // Run() is not supposed to return.
111 } 127 }
(...skipping 13 matching lines...) Expand all
125 NULL); 141 NULL);
126 } 142 }
127 } 143 }
128 144
129 /////////////////////////////////////////////////////////////////////////////// 145 ///////////////////////////////////////////////////////////////////////////////
130 // SessionManagerService commands 146 // SessionManagerService commands
131 147
132 gboolean SessionManagerService::EmitLoginPromptReady(gboolean *OUT_emitted, 148 gboolean SessionManagerService::EmitLoginPromptReady(gboolean *OUT_emitted,
133 GError **error) { 149 GError **error) {
134 DLOG(INFO) << "emitting login-prompt-ready "; 150 DLOG(INFO) << "emitting login-prompt-ready ";
135 system("/sbin/initctl emit login-prompt-ready &"); 151 *OUT_emitted = system("/sbin/initctl emit login-prompt-ready &") == 0;
136 *OUT_emitted = TRUE; 152 return *OUT_emitted;
137 return TRUE;
138 } 153 }
139 154
140 gboolean SessionManagerService::StartSession(gchar *email_address, 155 gboolean SessionManagerService::StartSession(gchar *email_address,
141 gchar *unique_identifier, 156 gchar *unique_identifier,
142 gboolean *OUT_done, 157 gboolean *OUT_done,
143 GError **error) { 158 GError **error) {
144 DLOG(INFO) << "emitting start-user-session"; 159 // basic validity checking; avoid buffer overflows here, and
145 system("/sbin/initctl emit start-user-session &"); 160 // canonicalize the email address a little.
146 child_job_->Toggle(); 161 char email[kMaxEmailSize + 1];
147 *OUT_done = TRUE; 162 snprintf(email, sizeof(email), "%s", email_address);
148 return TRUE; 163 email[kMaxEmailSize] = '\0'; // Just to be sure.
164 string email_string(email);
165 if (!ValidateEmail(email_string)) {
166 *OUT_done = FALSE;
167 return FALSE;
168 }
169 string email_lower = StringToLowerASCII(email_string);
170 DLOG(INFO) << "emitting start-user-session for " << email_lower;
171 string command =
172 StringPrintf("/sbin/initctl emit start-user-session CHROMEOS_USER=%s &",
173 email_lower.c_str());
174 *OUT_done = system(command.c_str()) == 0;
175 if (*OUT_done)
176 child_job_->Toggle();
177 return *OUT_done;
149 } 178 }
150 179
151 gboolean SessionManagerService::StopSession(gchar *unique_identifier, 180 gboolean SessionManagerService::StopSession(gchar *unique_identifier,
152 gboolean *OUT_done, 181 gboolean *OUT_done,
153 GError **error) { 182 GError **error) {
154 DLOG(INFO) << "emitting stop-user-session"; 183 DLOG(INFO) << "emitting stop-user-session";
155 system("/sbin/initctl emit stop-user-session &"); 184 *OUT_done = system("/sbin/initctl emit stop-user-session &") == 0;
156 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, 185 if (*OUT_done) {
157 ServiceShutdown, 186 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
158 this, 187 ServiceShutdown,
159 NULL); 188 this,
160 child_job_->Toggle(); 189 NULL);
161 *OUT_done = TRUE; 190 child_job_->Toggle();
162 return TRUE; 191 }
192 return *OUT_done;
163 } 193 }
164 194
165 195
166 /////////////////////////////////////////////////////////////////////////////// 196 ///////////////////////////////////////////////////////////////////////////////
167 // glib event handlers 197 // glib event handlers
168 198
169 void SessionManagerService::HandleChildExit(GPid pid, 199 void SessionManagerService::HandleChildExit(GPid pid,
170 gint status, 200 gint status,
171 gpointer data) { 201 gpointer data) {
172 // If I could wait for descendants here, I would. Instead, I kill them. 202 // If I could wait for descendants here, I would. Instead, I kill them.
173 kill(-pid, SIGKILL); 203 kill(-pid, SIGKILL);
174 204
175 DLOG(INFO) << "exited waitpid.\n" 205 DLOG(INFO) << "exited waitpid.\n"
176 << " WIFSIGNALED is " << WIFSIGNALED(status) << "\n" 206 << " WIFSIGNALED is " << WIFSIGNALED(status) << "\n"
177 << " WTERMSIG is " << WTERMSIG(status) << "\n" 207 << " WTERMSIG is " << WTERMSIG(status) << "\n"
178 << " WIFEXITED is " << WIFEXITED(status) << "\n" 208 << " WIFEXITED is " << WIFEXITED(status) << "\n"
179 << " WEXITSTATUS is " << WEXITSTATUS(status); 209 << " WEXITSTATUS is " << WEXITSTATUS(status);
180 if (WIFEXITED(status)) { 210 if (WIFEXITED(status)) {
181 CHECK(WEXITSTATUS(status) != SetUidExecJob::kCantSetuid); 211 CHECK(WEXITSTATUS(status) != SetUidExecJob::kCantSetuid);
182 CHECK(WEXITSTATUS(status) != SetUidExecJob::kCantExec); 212 CHECK(WEXITSTATUS(status) != SetUidExecJob::kCantExec);
183 } 213 }
184 214
185 // If the child _ever_ exits, we want to start it up again. 215 // If the child _ever_ exits, we want to start it up again.
186 SessionManagerService* manager = static_cast<SessionManagerService*>(data); 216 SessionManagerService* manager = static_cast<SessionManagerService*>(data);
187 if (manager->should_run_child()) { 217 if (manager->should_run_child()) {
188 manager->RunChild(); 218 // TODO(cmasone): deal with fork failing in RunChild()
219 manager->set_child_pgid(-manager->RunChild());
189 } else { 220 } else {
190 LOG(INFO) << "Should NOT run"; 221 LOG(INFO) << "Should NOT run";
191 manager->AllowGracefulExit(); 222 manager->AllowGracefulExit();
192 } 223 }
193 } 224 }
194 225
195 gboolean SessionManagerService::ServiceShutdown(gpointer data) { 226 gboolean SessionManagerService::ServiceShutdown(gpointer data) {
196 SessionManagerService* manager = static_cast<SessionManagerService*>(data); 227 SessionManagerService* manager = static_cast<SessionManagerService*>(data);
197 manager->Shutdown(); 228 manager->Shutdown();
198 return FALSE; // So that the event source that called this gets removed. 229 return FALSE; // So that the event source that called this gets removed.
199 } 230 }
200 231
201 232
202 233
203 /////////////////////////////////////////////////////////////////////////////// 234 ///////////////////////////////////////////////////////////////////////////////
204 // Utility Methods 235 // Utility Methods
205 236
237 // This can probably be more efficient, if it needs to be.
238 // static
239 bool SessionManagerService::ValidateEmail(const string& email_address) {
240 if (email_address.find_first_not_of(kLegalCharacters) != string::npos)
241 return false;
242
243 size_t at = email_address.find(kEmailSeparator);
244 // it has NO @.
245 if (at == string::npos)
246 return false;
247
248 // it has more than one @.
249 if (email_address.find(kEmailSeparator, at+1) != string::npos)
250 return false;
251
252 return true;
253 }
254
206 void SessionManagerService::SetupHandlers() { 255 void SessionManagerService::SetupHandlers() {
207 // I have to ignore SIGUSR1, because Xorg sends it to this process when it's 256 // I have to ignore SIGUSR1, because Xorg sends it to this process when it's
208 // got no clients and is ready for new ones. If we don't ignore it, we die. 257 // got no clients and is ready for new ones. If we don't ignore it, we die.
209 struct sigaction chld_action; 258 struct sigaction chld_action;
210 memset(&chld_action, 0, sizeof(chld_action)); 259 memset(&chld_action, 0, sizeof(chld_action));
211 chld_action.sa_handler = SIG_IGN; 260 chld_action.sa_handler = SIG_IGN;
212 CHECK(sigaction(SIGUSR1, &chld_action, NULL) == 0); 261 CHECK(sigaction(SIGUSR1, &chld_action, NULL) == 0);
213 } 262 }
214 263
264 void SessionManagerService::CleanupChildren(int max_tries) {
265 int try_count = 0;
266 while(!system_->child_is_gone(child_pgid_)) {
267 system_->kill(child_pgid_, (try_count++ >= max_tries ? SIGKILL : SIGTERM));
268 // TODO(cmasone): add conversion constants/methods in common/ somewhere.
269 usleep(500 * 1000 /* milliseconds */);
270 }
271 }
272
215 } // namespace login_manager 273 } // namespace login_manager
OLDNEW
« no previous file with comments | « session_manager_service.h ('k') | session_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698