00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #define _GNU_SOURCE
00025 #include "../lib/nuclient.h"
00026 #include <sys/resource.h>
00027 #include <stdio.h>
00028 #include <locale.h>
00029 #include <langinfo.h>
00030 #include <syslog.h>
00031 #include <pwd.h>
00032 #include <signal.h>
00033 #include <stdlib.h>
00034 #include "security.h"
00035
00036
00037
00038
00039
00040
00041
00042
00043 #define PAM_SM_AUTH
00044 #define PAM_SM_ACCOUNT
00045 #define PAM_SM_SESSION
00046 #define PAM_SM_PASSWORD
00047
00048 #include <security/pam_modules.h>
00049 #include <security/_pam_macros.h>
00050
00051
00052 #define NUAUTH_SRV "192.168.12.1"
00053 #define NUAUTH_PORT "4129"
00054 #define FILE_LOCK ".pam_nufw"
00055
00056 #define MAX_RETRY_TIME 30
00057
00058 #define MAX_NOAUTH_USERS 10
00059
00060 const char *DEFAULT_USER = "nobody";
00061
00062
00063 char **no_auth_users = NULL;
00064 struct pam_nufw_s pn_s;
00065 nuauth_session_t *session = NULL;
00066 char *locale_charset = NULL;
00067
00068
00069 struct pam_nufw_s {
00070 char nuauth_srv[BUFSIZ];
00071 char nuauth_port[20];
00072 char file_lock[BUFSIZ];
00073 char **no_auth_users;
00074 int no_auth_cpt;
00075 nuclient_error_t *err;
00076 };
00077
00078
00079 static char *_init_pam_nufw_s(struct pam_nufw_s *pn_s)
00080 {
00081 struct rlimit core_limit;
00082
00083
00084 if (getrlimit(RLIMIT_CORE, &core_limit) == 0) {
00085 core_limit.rlim_cur = 0;
00086 setrlimit(RLIMIT_CORE, &core_limit);
00087 }
00088
00089
00090 setlocale(LC_ALL, "");
00091
00092
00093 locale_charset = nl_langinfo(CODESET);
00094 if (locale_charset == NULL) {
00095 return "Can't get locale charset!";
00096 }
00097
00098
00099 (void) chdir("/");
00100
00101 memset(pn_s, 0, sizeof(*pn_s));
00102 SECURE_STRNCPY(pn_s->nuauth_srv, NUAUTH_SRV,
00103 sizeof(pn_s->nuauth_srv));
00104 SECURE_STRNCPY(pn_s->nuauth_port, NUAUTH_PORT,
00105 sizeof(pn_s->nuauth_port));
00106 SECURE_STRNCPY(pn_s->file_lock, FILE_LOCK,
00107 sizeof(pn_s->file_lock));
00108 pn_s->no_auth_users = NULL;
00109 pn_s->no_auth_cpt = 0;
00110 return NULL;
00111 }
00112
00113
00114 static int _pam_parse(int argc, const char **argv, struct pam_nufw_s *pn)
00115 {
00116 int ctrl = 0;
00117 char *noauth;
00118 char *user;
00119 char *search = ",";
00120 int noauth_cpt = 0;
00121 char **no_auth_users = malloc(sizeof(char *) * MAX_NOAUTH_USERS);
00122 for (ctrl = 0; argc-- > 0; ++argv) {
00123 if (!strncmp(*argv, "server=", 7)) {
00124 SECURE_STRNCPY(pn->nuauth_srv, *argv + 7,
00125 sizeof(pn->nuauth_srv));
00126 } else if (!strncmp(*argv, "port=", 5)) {
00127 SECURE_STRNCPY(pn->nuauth_port, *argv + 5,
00128 sizeof(pn->nuauth_port));
00129 } else if (!strncmp(*argv, "lock=", 5)) {
00130 SECURE_STRNCPY(pn->file_lock, *argv + 5,
00131 sizeof(pn->file_lock));
00132 } else if (!strncmp(*argv, "noauth=", 7)) {
00133 noauth = strdup(*argv + 7);
00134 user = strtok(noauth, search);
00135 if (user) {
00136 no_auth_users[noauth_cpt] = x_strdup(user);
00137 noauth_cpt++;
00138 }
00139 while ((user = strtok(NULL, search)) != NULL) {
00140 no_auth_users[noauth_cpt] = x_strdup(user);
00141 noauth_cpt++;
00142 }
00143 }
00144 }
00145 pn->no_auth_cpt = noauth_cpt;
00146 pn->no_auth_users = no_auth_users;
00147 return ctrl;
00148 }
00149
00150 char *_get_runpid(struct pam_nufw_s *pn_s, char *home)
00151 {
00152 char path_dir[1024];
00153 int free_home = 0;
00154 if (home == NULL) {
00155 home = nu_get_home_dir();
00156 free_home = 1;
00157 }
00158 if (home == NULL) {
00159 return NULL;
00160 }
00161
00162
00163 snprintf(path_dir, sizeof(path_dir), "%s/.nufw", home);
00164 path_dir[sizeof(path_dir) - 1] = 0;
00165
00166
00167 if (access(path_dir, R_OK)) {
00168 mkdir(path_dir, S_IRWXU);
00169 }
00170
00171
00172 snprintf(path_dir, sizeof(path_dir), "%s/.nufw/%s", home,
00173 pn_s->file_lock);
00174 path_dir[sizeof(path_dir) - 1] = 0;
00175 if (free_home) {
00176 free(home);
00177 }
00178 return (char *) strdup(path_dir);
00179 }
00180
00181 static int _kill_nuclient(char *runpid)
00182 {
00183 pid_t pid;
00184 FILE *FD;
00185 int ok, ret;
00186
00187 if (runpid) {
00188 FD = fopen(runpid, "r");
00189 if (FD) {
00190 fscanf(FD, "%d", &pid);
00191 fclose(FD);
00192 ret = kill(pid, SIGTERM);
00193 ok = (ret == 0);
00194 if (ok) {
00195 syslog(LOG_INFO,
00196 "(pam_nufw) process killed (pid %lu)\n",
00197 (unsigned long) pid);
00198 return 0;
00199 } else {
00200 syslog(LOG_ERR,
00201 "(pam_nufw) fail to kill process: remove pid file\n");
00202 unlink(runpid);
00203 return 1;
00204 }
00205 }
00206 free(runpid);
00207 }
00208 return 0;
00209 }
00210
00211
00212
00213
00214
00215 void exit_client()
00216 {
00217 char *runpid;
00218 if (session) {
00219 nu_client_delete(session);
00220 }
00221 runpid = _get_runpid(&pn_s, NULL);
00222 if (runpid != NULL) {
00223 unlink(runpid);
00224 free(runpid);
00225 }
00226 nu_client_global_deinit();
00227 nu_client_error_destroy(pn_s.err);
00228 exit(EXIT_SUCCESS);
00229 }
00230
00231
00232 int do_auth_on_user(const char *username)
00233 {
00234 int i;
00235 for (i = 0; i < pn_s.no_auth_cpt; i++) {
00236 if (strcmp(pn_s.no_auth_users[i], username) == 0) {
00237 return 1;
00238 }
00239 }
00240 return 0;
00241 }
00242
00243
00244
00245
00251 nuauth_session_t *do_connect(char *username, char *password, nuclient_error_t * err)
00252 {
00253 nuauth_session_t *session = nu_client_new(username, password, 1, err);
00254 if (session == NULL) {
00255 return NULL;
00256 }
00257
00258
00259 memset(username, 0, strlen(username));
00260 memset(password, 0, strlen(password));
00261 free(username);
00262 free(password);
00263
00264 #if 0
00265 nu_client_set_debug(session, context->debug_mode);
00266
00267 if (!nu_client_setup_tls(session, NULL, NULL, NULL, NULL, err)) {
00268 nu_client_delete(session);
00269 return NULL;
00270 }
00271 #endif
00272
00273 if (!nu_client_connect
00274 (session, pn_s.nuauth_srv, pn_s.nuauth_port, err)) {
00275 nu_client_delete(session);
00276 return NULL;
00277 }
00278 return session;
00279 }
00280
00281 static void main_loop(struct pam_nufw_s *pn_s)
00282 {
00283 int connected = 1;
00284 int tempo = 1;
00285 unsigned long interval = 100;
00286
00287 for (;;) {
00288 if (!connected) {
00289 sleep(tempo);
00290 if (tempo < MAX_RETRY_TIME) {
00291 tempo = tempo * 2;
00292 }
00293
00294 if (nu_client_connect
00295 (session, pn_s->nuauth_srv, pn_s->nuauth_port,
00296 pn_s->err) != 0) {
00297 tempo = 1;
00298 connected = 1;
00299 } else {
00300 nu_client_reset(session);
00301
00302 syslog(LOG_ERR,
00303 "(pam_nufw) unable to reconnect to server: %s",
00304 nu_client_strerror(session, pn_s->err));
00305 if (pn_s->err->error ==
00306 BAD_CREDENTIALS_ERR) {
00307 syslog(LOG_ERR,
00308 "(pam_nufw) bad credentials: leaving");
00309 exit_client();
00310 }
00311 }
00312 } else {
00313 if (nu_client_check(session, pn_s->err) < 0) {
00314 nu_client_reset(session);
00315 connected = 0;
00316 syslog(LOG_ERR,
00317 "(pam_nufw) libnuclient error: %s",
00318 nu_client_strerror(session, pn_s->err));
00319 }
00320 }
00321 }
00322 }
00323
00324 struct user_info_s {
00325 const char *username;
00326 const char *password;
00327 uid_t uid;
00328 gid_t gid;
00329 char *home_dir;
00330 };
00331
00332 static void clear_user_info(struct user_info_s *user_info)
00333 {
00334 memset(user_info, 0, sizeof(*user_info));
00335 }
00336
00337 static int nufw_client_func(struct pam_nufw_s *pn_s,
00338 struct user_info_s *user_info)
00339 {
00340 int mypid;
00341 FILE *RunD;
00342 struct sigaction no_action;
00343 int res_err;
00344
00345
00346 if (setuid(user_info->uid) != 0) {
00347 syslog(LOG_ERR, "(pam_nufw) Fail to set sigaction");
00348 return PAM_AUTH_ERR;
00349 }
00350 setgid(user_info->gid);
00351 setenv("HOME", user_info->home_dir, 1);
00352
00353
00354 no_action.sa_handler = exit_client;
00355 sigemptyset(&(no_action.sa_mask));
00356 no_action.sa_flags = 0;
00357 if (sigaction(SIGINT, &no_action, NULL) != 0
00358 || sigaction(SIGTERM, &no_action, NULL) != 0) {
00359 syslog(LOG_ERR, "(pam_nufw) Fail to set sigaction");
00360 return PAM_AUTH_ERR;
00361 }
00362
00363
00364 res_err = nu_client_error_init(&pn_s->err);
00365 if (res_err != 0) {
00366 syslog(LOG_ERR,
00367 "(pam_nufw) Cannot init error structure! %i",
00368 res_err);
00369 return PAM_AUTH_ERR;
00370 }
00371
00372
00373 if (!nu_client_global_init(pn_s->err)) {
00374 syslog(LOG_ERR,
00375 "(pam_nufw) Cannot init nuclient library: %s",
00376 nu_client_strerror(session, pn_s->err));
00377 return PAM_AUTH_ERR;
00378 }
00379
00380
00381 session =
00382 do_connect(nu_client_to_utf8
00383 (user_info->username, locale_charset),
00384 nu_client_to_utf8(user_info->password,
00385 locale_charset), pn_s->err);
00386 clear_user_info(user_info);
00387
00388
00389 if (session == NULL) {
00390 int errno_copy = errno;
00391 syslog(LOG_ERR,
00392 "(pam_nufw) Cannot connect to nuauth_session_t Server");
00393 syslog(LOG_ERR, "(pam_nufw) Problem: %s\n",
00394 strerror(errno_copy));
00395 return PAM_SUCCESS;
00396 }
00397
00398
00399 mypid = getpid();
00400 RunD = fopen(_get_runpid(pn_s, user_info->home_dir), "w");
00401 if (RunD != NULL) {
00402 fprintf(RunD, "%d", mypid);
00403 fclose(RunD);
00404 syslog(LOG_INFO,
00405 "(pam_nufw) session to Nuauth server opened, username=%s, server=%s (pid=%lu)",
00406 user_info->username, pn_s->nuauth_srv,
00407 (unsigned long) mypid);
00408 }
00409
00410
00411 main_loop(pn_s);
00412 return PAM_SUCCESS;
00413 }
00414
00415 static int read_user_info(struct user_info_s *user_info,
00416 pam_handle_t * pamh,
00417 int argc, const char **argv, int *pam_result)
00418 {
00419 struct passwd *pw;
00420 int ctrl;
00421
00422
00423 ctrl = _pam_parse(argc, argv, &pn_s);
00424
00425
00426 *pam_result = pam_get_user(pamh, &user_info->username, NULL);
00427 if (*pam_result != PAM_SUCCESS) {
00428 syslog(LOG_ERR, "get user returned error: %s",
00429 pam_strerror(pamh, *pam_result));
00430 *pam_result = PAM_AUTH_ERR;
00431 return 0;
00432 }
00433
00434
00435 if (user_info->username == NULL || user_info->username[0] == '\0') {
00436 user_info->username = DEFAULT_USER;
00437 pam_set_item(pamh, PAM_USER, DEFAULT_USER);
00438 }
00439
00440
00441 if (do_auth_on_user(user_info->username) != 0) {
00442 syslog(LOG_INFO, "(pam_nufw) no auth for user %s",
00443 user_info->username);
00444 *pam_result = PAM_SUCCESS;
00445 return 0;
00446 }
00447
00448
00449 if (pam_get_item
00450 (pamh, PAM_AUTHTOK,
00451 (const void **) &user_info->password) == PAM_SUCCESS) {
00452 if (user_info->password == NULL)
00453 syslog(LOG_ERR, "(pam_nufw) password is NULL!");
00454 } else {
00455 syslog(LOG_ERR, "pam_nufw failed to get password");
00456 *pam_result = PAM_AUTH_ERR;
00457 return 0;
00458 }
00459
00460
00461 pw = (struct passwd *) getpwnam(user_info->username);
00462 user_info->uid = pw->pw_uid;
00463 user_info->gid = pw->pw_gid;
00464 user_info->home_dir = pw->pw_dir;
00465 *pam_result = PAM_SUCCESS;
00466 return 1;
00467 }
00468
00469
00470
00471
00472 PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags,
00473 int argc, const char **argv)
00474 {
00475 int retval;
00476 struct user_info_s user_info;
00477 char *errmsg;
00478 pid_t child_pid;
00479
00480 syslog(LOG_ERR, "(pam_nufw) do authenticate");
00481
00482
00483 if (!nu_check_version(NUCLIENT_VERSION)) {
00484 syslog(LOG_ERR,
00485 "(pam nufw) Wrong version of libnuclient (%s instead of %s)",
00486 nu_get_version(), NUCLIENT_VERSION);
00487 return PAM_AUTH_ERR;
00488 }
00489
00490
00491 errmsg = _init_pam_nufw_s(&pn_s);
00492 if (errmsg != NULL) {
00493 syslog(LOG_ERR, "(pam nufw) init failure: %s", errmsg);
00494 return PAM_AUTH_ERR;
00495 }
00496
00497
00498 if (!access(pn_s.file_lock, R_OK)) {
00499 FILE *fd;
00500 if ((fd = fopen(pn_s.file_lock, "r"))) {
00501 char line[20];
00502 if (fgets(line, 19, fd)) {
00503 pid_t pid = (pid_t) atoi(line);
00504 fclose(fd);
00505 if (kill(pid, 0)) {
00506 unlink(pn_s.file_lock);
00507 } else {
00508 return PAM_SUCCESS;
00509 }
00510 }
00511 }
00512 }
00513
00514
00515
00516
00517 if (!read_user_info(&user_info, pamh, argc, argv, &retval)) {
00518 clear_user_info(&user_info);
00519 return retval;
00520 }
00521
00522
00523 child_pid = fork();
00524 if (child_pid < 0) {
00525 syslog(LOG_ERR, "(pam_nufw) fork failed");
00526 clear_user_info(&user_info);
00527 return PAM_AUTH_ERR;
00528 }
00529
00530 if (child_pid != 0) {
00531
00532 retval = PAM_SUCCESS;
00533 } else {
00534
00535 retval = nufw_client_func(&pn_s, &user_info);
00536 }
00537 clear_user_info(&user_info);
00538 return retval;
00539 }
00540
00541 PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags, int argc,
00542 const char **argv)
00543 {
00544
00545 return PAM_SUCCESS;
00546 }
00547
00548
00549
00550 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc, const char **argv)
00551 {
00552 D(("pam_nufw sm_acct_mgmt"));
00553 return PAM_SUCCESS;
00554 }
00555
00556
00557
00558 PAM_EXTERN
00559 int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc,
00560 const char **argv)
00561 {
00562 D(("pam_nufw sm_chauthok"));
00563 return PAM_SUCCESS;
00564 }
00565
00566
00567
00568 PAM_EXTERN
00569 int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc,
00570 const char **argv)
00571 {
00572 syslog(LOG_INFO, "(pam_nufw) session opened");
00573 return PAM_SUCCESS;
00574 }
00575
00576
00577
00578
00579
00580 PAM_EXTERN
00581 int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc,
00582 const char **argv)
00583 {
00584
00585 int ctrl;
00586 struct passwd *pw;
00587 const char *user = NULL;
00588 char *errmsg;
00589 int retval;
00590
00591
00592 errmsg = _init_pam_nufw_s(&pn_s);
00593 if (errmsg != NULL) {
00594 syslog(LOG_ERR, "(pam nufw) init failure: %s", errmsg);
00595 return PAM_AUTH_ERR;
00596 }
00597
00598
00599 ctrl = _pam_parse(argc, argv, &pn_s);
00600
00601
00602 retval = pam_get_user(pamh, &user, NULL);
00603 if (do_auth_on_user(user) != 0) {
00604 return PAM_SUCCESS;
00605 }
00606 pw = (struct passwd *) getpwnam(user);
00607 setenv("HOME", pw->pw_dir, 1);
00608
00609
00610
00611 _kill_nuclient(_get_runpid(&pn_s, pw->pw_dir));
00612
00613 syslog(LOG_INFO, "(pam_nufw) session closed");
00614 return PAM_SUCCESS;
00615 }
00616
00617
00618
00619 #ifdef PAM_STATIC
00620
00621
00622
00623 struct pam_module _pam_permit_modstruct = {
00624 "pam_nufw",
00625 pam_sm_authenticate,
00626 pam_sm_setcred,
00627 pam_sm_acct_mgmt,
00628 pam_sm_open_session,
00629 pam_sm_close_session,
00630 pam_sm_chauthtok
00631 };
00632
00633 #endif