00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include "sbuild-auth.h"
00023 #include "sbuild-auth-conv.h"
00024 #include "sbuild-auth-conv-tty.h"
00025
00026 #include <cassert>
00027 #include <cerrno>
00028 #include <cstdlib>
00029 #include <cstring>
00030 #include <iostream>
00031 #include <sstream>
00032
00033 #include <syslog.h>
00034
00035 #include <boost/format.hpp>
00036
00037 using std::cerr;
00038 using std::endl;
00039 using boost::format;
00040 using namespace sbuild;
00041
00042 namespace
00043 {
00044
00045 typedef std::pair<sbuild::auth::error_code,const char *> emap;
00046
00051 emap init_errors[] =
00052 {
00053 emap(auth::HOSTNAME, N_("Failed to get hostname")),
00054
00055 emap(auth::USER, N_("User '%1%' not found")),
00056 emap(auth::AUTHENTICATION, N_("Authentication failed")),
00057 emap(auth::AUTHORISATION, N_("Access not authorised")),
00058 emap(auth::PAM_DOUBLE_INIT, N_("PAM is already initialised")),
00059 emap(auth::PAM, N_("PAM error"))
00060 };
00061
00062 }
00063
00064 template<>
00065 error<auth::error_code>::map_type
00066 error<auth::error_code>::error_strings
00067 (init_errors,
00068 init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
00069
00070 namespace
00071 {
00072
00073
00074 int
00075 auth_conv_hook (int num_msg,
00076 const struct pam_message **msgm,
00077 struct pam_response **response,
00078 void *appdata_ptr)
00079 {
00080 log_debug(DEBUG_NOTICE) << "PAM conversation hook started" << endl;
00081
00082 try
00083 {
00084 if (appdata_ptr == 0)
00085 return PAM_CONV_ERR;
00086
00087 auth_conv *conv = static_cast<auth_conv *>(appdata_ptr);
00088 assert (conv != 0);
00089
00090
00091 auth_conv::message_list messages;
00092 for (int i = 0; i < num_msg; ++i)
00093 {
00094 const struct pam_message *source = msgm[i];
00095
00096 auth_message
00097 message(static_cast<auth_message::message_type>(source->msg_style),
00098 source->msg);
00099 messages.push_back(message);
00100 }
00101
00102
00103 conv->conversation(messages);
00104
00105
00106 struct pam_response *reply =
00107 static_cast<struct pam_response *>
00108 (malloc(sizeof(struct pam_response) * num_msg));
00109
00110 for (int i = 0; i < num_msg; ++i)
00111 {
00112 reply[i].resp_retcode = 0;
00113 reply[i].resp = strdup(messages[i].response.c_str());
00114 }
00115
00116 *response = reply;
00117 reply = 0;
00118
00119 return PAM_SUCCESS;
00120 }
00121 catch (std::exception const& e)
00122 {
00123 sbuild::log_exception_error(e);
00124 }
00125 catch (...)
00126 {
00127 sbuild::log_error() << _("An unknown exception occurred") << endl;
00128 }
00129
00130 return PAM_CONV_ERR;
00131 }
00132
00133 }
00134
00135
00136 auth::auth (std::string const& service_name):
00137 pam(),
00138 service(service_name),
00139 uid(0),
00140 gid(0),
00141 user(),
00142 command(),
00143 home(),
00144 wd(),
00145 shell(),
00146 user_environment(),
00147 ruid(),
00148 ruser(),
00149 conv(new auth_conv_tty),
00150 message_verbosity(VERBOSITY_NORMAL)
00151 {
00152 this->ruid = getuid();
00153 struct passwd *pwent = getpwuid(this->ruid);
00154 if (pwent == 0)
00155 {
00156 if (errno)
00157 throw error(this->ruid, USER, strerror(errno));
00158 else
00159 throw error(this->ruid, USER);
00160 }
00161 this->ruser = pwent->pw_name;
00162
00163
00164 set_user(this->ruser);
00165 }
00166
00167 auth::~auth ()
00168 {
00169
00170 try
00171 {
00172 stop();
00173 }
00174 catch (error const& e)
00175 {
00176 sbuild::log_exception_error(e);
00177 }
00178 }
00179
00180 std::string const&
00181 auth::get_service () const
00182 {
00183 return this->service;
00184 }
00185
00186 uid_t
00187 auth::get_uid () const
00188 {
00189 return this->uid;
00190 }
00191
00192 gid_t
00193 auth::get_gid () const
00194 {
00195 return this->gid;
00196 }
00197
00198 std::string const&
00199 auth::get_user () const
00200 {
00201 return this->user;
00202 }
00203
00204 void
00205 auth::set_user (std::string const& user)
00206 {
00207 this->uid = getuid();
00208 this->gid = getgid();
00209 this->home = "/";
00210 this->shell = "/bin/false";
00211
00212 this->user = user;
00213
00214 struct passwd *pwent = getpwnam(this->user.c_str());
00215 if (pwent == 0)
00216 {
00217 if (errno)
00218 throw error(user, USER, strerror(errno));
00219 else
00220 throw error(user, USER);
00221 }
00222 this->uid = pwent->pw_uid;
00223 this->gid = pwent->pw_gid;
00224 this->home = pwent->pw_dir;
00225 this->shell = pwent->pw_shell;
00226 log_debug(DEBUG_INFO)
00227 << format("auth uid = %1%, gid = %2%") % this->uid % this->gid
00228 << endl;
00229 }
00230
00231 string_list const&
00232 auth::get_command () const
00233 {
00234 return this->command;
00235 }
00236
00237 void
00238 auth::set_command (string_list const& command)
00239 {
00240 this->command = command;
00241 }
00242
00243 std::string const&
00244 auth::get_home () const
00245 {
00246 return this->home;
00247 }
00248
00249 std::string const&
00250 auth::get_wd () const
00251 {
00252 return this->wd;
00253 }
00254
00255 void
00256 auth::set_wd (std::string const& wd)
00257 {
00258 this->wd = wd;
00259 }
00260
00261 std::string const&
00262 auth::get_shell () const
00263 {
00264 return this->shell;
00265 }
00266
00267 environment const&
00268 auth::get_environment () const
00269 {
00270 return this->user_environment;
00271 }
00272
00273 void
00274 auth::set_environment (char **environment)
00275 {
00276 set_environment(sbuild::environment(environment));
00277 }
00278
00279 void
00280 auth::set_environment (environment const& environment)
00281 {
00282 this->user_environment = environment;
00283 }
00284
00285 environment
00286 auth::get_pam_environment () const
00287 {
00288 return environment(pam_getenvlist(this->pam));
00289 }
00290
00291 uid_t
00292 auth::get_ruid () const
00293 {
00294 return this->ruid;
00295 }
00296
00297 std::string const&
00298 auth::get_ruser () const
00299 {
00300 return this->ruser;
00301 }
00302
00303 auth::verbosity
00304 auth::get_verbosity () const
00305 {
00306 return this->message_verbosity;
00307 }
00308
00309 void
00310 auth::set_verbosity (auth::verbosity verbosity)
00311 {
00312 this->message_verbosity = verbosity;
00313 }
00314
00315 auth::conv_ptr&
00316 auth::get_conv ()
00317 {
00318 return this->conv;
00319 }
00320
00321 void
00322 auth::set_conv (conv_ptr& conv)
00323 {
00324 this->conv = conv;
00325 }
00326
00327 void
00328 auth::run ()
00329 {
00330 try
00331 {
00332 start();
00333 authenticate();
00334 setupenv();
00335 account();
00336 try
00337 {
00338 cred_establish();
00339
00340 const char *authuser = 0;
00341 const void *tmpcast = reinterpret_cast<const void *>(authuser);
00342 pam_get_item(this->pam, PAM_USER, &tmpcast);
00343 log_debug(DEBUG_INFO)
00344 << format("PAM authentication succeeded for user %1%") % authuser
00345 << endl;
00346
00347 run_impl();
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 }
00360 catch (error const& e)
00361 {
00362 try
00363 {
00364 cred_delete();
00365 }
00366 catch (error const& discard)
00367 {
00368 }
00369 throw;
00370 }
00371 cred_delete();
00372 }
00373 catch (error const& e)
00374 {
00375 try
00376 {
00377
00378
00379 stop();
00380 }
00381 catch (error const& discard)
00382 {
00383 }
00384 throw;
00385 }
00386 stop();
00387 }
00388
00389 void
00390 auth::start ()
00391 {
00392 assert(!this->user.empty());
00393
00394 if (this->pam != 0)
00395 {
00396 log_debug(DEBUG_CRITICAL)
00397 << "pam_start FAIL (already initialised)" << endl;
00398 throw error("Init PAM", PAM_DOUBLE_INIT);
00399 }
00400
00401 struct pam_conv conv_hook =
00402 {
00403 auth_conv_hook,
00404 reinterpret_cast<void *>(this->conv.get())
00405 };
00406
00407 int pam_status;
00408
00409 if ((pam_status =
00410 pam_start(this->service.c_str(), this->user.c_str(),
00411 &conv_hook, &this->pam)) != PAM_SUCCESS)
00412 {
00413 log_debug(DEBUG_WARNING) << "pam_start FAIL" << endl;
00414 throw error(PAM, pam_strerror(pam_status));
00415 }
00416
00417 log_debug(DEBUG_NOTICE) << "pam_start OK" << endl;
00418 }
00419
00420 void
00421 auth::stop ()
00422 {
00423 if (this->pam);
00424 {
00425 int pam_status;
00426
00427 if ((pam_status =
00428 pam_end(this->pam, PAM_SUCCESS)) != PAM_SUCCESS)
00429 {
00430 log_debug(DEBUG_WARNING) << "pam_end FAIL" << endl;
00431 throw error(PAM, pam_strerror(pam_status));
00432 }
00433
00434 this->pam = 0;
00435 log_debug(DEBUG_NOTICE) << "pam_end OK" << endl;
00436 }
00437 }
00438
00439 void
00440 auth::authenticate ()
00441 {
00442 assert(!this->user.empty());
00443 assert(this->pam != 0);
00444
00445 int pam_status;
00446
00447 if ((pam_status =
00448 pam_set_item(this->pam, PAM_RUSER, this->ruser.c_str())) != PAM_SUCCESS)
00449 {
00450 log_debug(DEBUG_WARNING) << "pam_set_item (PAM_RUSER) FAIL" << endl;
00451 throw error(_("Set RUSER"), PAM, pam_strerror(pam_status));
00452 }
00453
00454 long hl = 256;
00455
00456 char *hostname = new char[hl];
00457 try
00458 {
00459 if (gethostname(hostname, hl) != 0)
00460 {
00461 log_debug(DEBUG_CRITICAL) << "gethostname FAIL" << endl;
00462 throw error(HOSTNAME, strerror(errno));
00463 }
00464
00465 if ((pam_status =
00466 pam_set_item(this->pam, PAM_RHOST, hostname)) != PAM_SUCCESS)
00467 {
00468 log_debug(DEBUG_WARNING) << "pam_set_item (PAM_RHOST) FAIL" << endl;
00469 throw error(_("Set RHOST"), PAM, pam_strerror(pam_status));
00470 }
00471 }
00472 catch (error const& e)
00473 {
00474 delete[] hostname;
00475 hostname = 0;
00476 throw;
00477 }
00478 delete[] hostname;
00479 hostname = 0;
00480
00481 const char *tty = ttyname(STDIN_FILENO);
00482 if (tty)
00483 {
00484 if ((pam_status =
00485 pam_set_item(this->pam, PAM_TTY, tty)) != PAM_SUCCESS)
00486 {
00487 log_debug(DEBUG_WARNING) << "pam_set_item (PAM_TTY) FAIL" << endl;
00488 throw error(_("Set TTY"), PAM, pam_strerror(pam_status));
00489 }
00490 }
00491
00492
00493 switch (get_auth_status())
00494 {
00495 case STATUS_NONE:
00496 if ((pam_status = pam_set_item(this->pam, PAM_USER, this->user.c_str()))
00497 != PAM_SUCCESS)
00498 {
00499 log_debug(DEBUG_WARNING) << "pam_set_item (PAM_USER) FAIL" << endl;
00500 throw error(_("Set USER"), PAM, pam_strerror(pam_status));
00501 }
00502 break;
00503
00504 case STATUS_USER:
00505 if ((pam_status = pam_authenticate(this->pam, 0)) != PAM_SUCCESS)
00506 {
00507 log_debug(DEBUG_INFO) << "pam_authenticate FAIL" << endl;
00508 syslog(LOG_AUTH|LOG_WARNING, "%s->%s Authentication failure",
00509 this->ruser.c_str(), this->user.c_str());
00510 throw error(AUTHENTICATION, pam_strerror(pam_status));
00511 }
00512 log_debug(DEBUG_NOTICE) << "pam_authenticate OK" << endl;
00513 break;
00514
00515 case STATUS_FAIL:
00516 {
00517 log_debug(DEBUG_INFO) << "PAM auth premature FAIL" << endl;
00518 syslog(LOG_AUTH|LOG_WARNING,
00519 "%s->%s Unauthorised",
00520 this->ruser.c_str(), this->user.c_str());
00521 error e(AUTHORISATION);
00522
00523 std::string reason(_("You do not have permission to access the %1% service."));
00524 reason += '\n';
00525 reason += _("This failure will be reported.");
00526 format fmt(reason);
00527 fmt % this->service;
00528 e.set_reason(fmt.str());
00529 throw e;
00530 }
00531 default:
00532 break;
00533 }
00534 }
00535
00536 void
00537 auth::setupenv ()
00538 {
00539 assert(this->pam != 0);
00540
00541 int pam_status;
00542
00543 environment environment;
00544 if (!this->user_environment.empty())
00545 environment = this->user_environment;
00546
00547
00548
00549 if (this->uid == 0)
00550 environment.add(std::make_pair("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11"));
00551 else if (this->user_environment.empty())
00552 environment.add(std::make_pair("PATH", "/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games"));
00553
00554 if (this->user_environment.empty())
00555 {
00556 if (!this->home.empty() )
00557 environment.add(std::make_pair("HOME", this->home));
00558 else
00559 environment.add(std::make_pair("HOME", "/"));
00560 if (!this->user.empty())
00561 {
00562 environment.add(std::make_pair("LOGNAME", this->user));
00563 environment.add(std::make_pair("USER", this->user));
00564 }
00565 {
00566 const char *term = getenv("TERM");
00567 if (term)
00568 environment.add(std::make_pair("TERM", term));
00569 }
00570 if (!this->shell.empty())
00571 environment.add(std::make_pair("SHELL", this->shell));
00572 }
00573
00574
00575 environment.remove("BASH_ENV");
00576 environment.remove("CDPATH");
00577 environment.remove("ENV");
00578 environment.remove("HOSTALIASES");
00579 environment.remove("IFS");
00580 environment.remove("KRB5_CONFIG");
00581 environment.remove("KRBCONFDIR");
00582 environment.remove("KRBTKFILE");
00583 environment.remove("KRB_CONF");
00584 environment.remove("LOCALDOMAIN");
00585 environment.remove("NLSPATH");
00586 environment.remove("PATH_LOCALE");
00587 environment.remove("RES_OPTIONS");
00588 environment.remove("TERMINFO");
00589 environment.remove("TERMINFO_DIRS");
00590 environment.remove("TERMPATH");
00591
00592
00593 string_list ldvars;
00594 for (environment::const_iterator cur = environment.begin();
00595 cur != environment.end();)
00596 {
00597 environment::const_iterator next = cur;
00598 next++;
00599
00600 if (cur->first.substr(0,3) == "LD_")
00601 environment.remove(cur->first);
00602
00603 cur = next;
00604 }
00605
00606
00607 for (environment::const_iterator cur = environment.begin();
00608 cur != environment.end();
00609 ++cur)
00610 {
00611 std::string env_string = cur->first + "=" + cur->second;
00612 if ((pam_status =
00613 pam_putenv(this->pam, env_string.c_str())) != PAM_SUCCESS)
00614 {
00615 log_debug(DEBUG_WARNING) << "pam_putenv FAIL" << endl;
00616 throw error(PAM, pam_strerror(pam_status));
00617 }
00618 log_debug(DEBUG_INFO)
00619 << format("pam_putenv: set %1%=%2%") % cur->first % cur->second
00620 << endl;
00621 }
00622
00623 log_debug(DEBUG_NOTICE) << "pam_putenv OK" << endl;
00624 }
00625
00626 void
00627 auth::account ()
00628 {
00629 assert(this->pam != 0);
00630
00631 int pam_status;
00632
00633 if ((pam_status =
00634 pam_acct_mgmt(this->pam, 0)) != PAM_SUCCESS)
00635 {
00636
00637
00638 log_debug(DEBUG_WARNING) << "pam_acct_mgmt FAIL" << endl;
00639 throw error(PAM, pam_strerror(pam_status));
00640 }
00641
00642 log_debug(DEBUG_NOTICE) << "pam_acct_mgmt OK" << endl;
00643 }
00644
00645 void
00646 auth::cred_establish ()
00647 {
00648 assert(this->pam != 0);
00649
00650 int pam_status;
00651
00652 if ((pam_status =
00653 pam_setcred(this->pam, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
00654 {
00655 log_debug(DEBUG_WARNING) << "pam_setcred FAIL" << endl;
00656 throw error(PAM, pam_strerror(pam_status));
00657 }
00658
00659 log_debug(DEBUG_NOTICE) << "pam_setcred OK" << endl;
00660 }
00661
00662 void
00663 auth::cred_delete ()
00664 {
00665 assert(this->pam != 0);
00666
00667 int pam_status;
00668
00669 if ((pam_status =
00670 pam_setcred(this->pam, PAM_DELETE_CRED)) != PAM_SUCCESS)
00671 {
00672 log_debug(DEBUG_WARNING) << "pam_setcred (delete) FAIL" << endl;
00673 throw error(PAM, pam_strerror(pam_status));
00674 }
00675
00676 log_debug(DEBUG_NOTICE) << "pam_setcred (delete) OK" << endl;
00677 }
00678
00679 void
00680 auth::open_session ()
00681 {
00682 assert(this->pam != 0);
00683
00684 int pam_status;
00685
00686 if ((pam_status =
00687 pam_open_session(this->pam, 0)) != PAM_SUCCESS)
00688 {
00689 log_debug(DEBUG_WARNING) << "pam_open_session FAIL" << endl;
00690 throw error(PAM, pam_strerror(pam_status));
00691 }
00692
00693 log_debug(DEBUG_NOTICE) << "pam_open_session OK" << endl;
00694 }
00695
00696 void
00697 auth::close_session ()
00698 {
00699 assert(this->pam != 0);
00700
00701 int pam_status;
00702
00703 if ((pam_status =
00704 pam_close_session(this->pam, 0)) != PAM_SUCCESS)
00705 {
00706 log_debug(DEBUG_WARNING) << "pam_close_session FAIL" << endl;
00707 throw error(PAM, pam_strerror(pam_status));
00708 }
00709
00710 log_debug(DEBUG_NOTICE) << "pam_close_session OK" << endl;
00711 }
00712
00713 auth::status
00714 auth::get_auth_status () const
00715 {
00716 status authtype = STATUS_NONE;
00717
00718 authtype = change_auth(authtype, STATUS_USER);
00719
00720 return authtype;
00721 }
00722
00723 const char *
00724 auth::pam_strerror (int pam_error)
00725 {
00726 assert(this->pam != 0);
00727
00728 return ::pam_strerror (this->pam, pam_error);
00729 }