00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "pam_winbind.h"
00014
00015 #define _PAM_LOG_FUNCTION_ENTER(function, pamh, ctrl, flags) \
00016 do { \
00017 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "[pamh: 0x%08x] ENTER: " function " (flags: 0x%04x)", (uint32) pamh, flags); \
00018 _pam_log_state(pamh, ctrl); \
00019 } while (0)
00020
00021 #define _PAM_LOG_FUNCTION_LEAVE(function, pamh, ctrl, retval) \
00022 do { \
00023 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "[pamh: 0x%08x] LEAVE: " function " returning %d", (uint32) pamh, retval); \
00024 _pam_log_state(pamh, ctrl); \
00025 } while (0)
00026
00027
00028
00029 #define MAX_PASSWD_TRIES 3
00030
00031
00032
00033
00034
00035 static int _pam_get_item(const pam_handle_t *pamh, int item_type,
00036 const void *_item)
00037 {
00038 const void **item = (const void **)_item;
00039 return pam_get_item(pamh, item_type, item);
00040 }
00041 static int _pam_get_data(const pam_handle_t *pamh,
00042 const char *module_data_name, const void *_data)
00043 {
00044 const void **data = (const void **)_data;
00045 return pam_get_data(pamh, module_data_name, data);
00046 }
00047
00048
00049
00050 #ifdef HAVE_PAM_VSYSLOG
00051 static void _pam_log_int(const pam_handle_t *pamh, int err, const char *format, va_list args)
00052 {
00053 pam_vsyslog(pamh, err, format, args);
00054 }
00055 #else
00056 static void _pam_log_int(const pam_handle_t *pamh, int err, const char *format, va_list args)
00057 {
00058 char *format2 = NULL;
00059 const char *service;
00060
00061 _pam_get_item(pamh, PAM_SERVICE, &service);
00062
00063 format2 = malloc(strlen(MODULE_NAME)+strlen(format)+strlen(service)+5);
00064 if (format2 == NULL) {
00065
00066 vsyslog(err, format, args);
00067 return;
00068 }
00069
00070 sprintf(format2, "%s(%s): %s", MODULE_NAME, service, format);
00071 vsyslog(err, format2, args);
00072 SAFE_FREE(format2);
00073 }
00074 #endif
00075
00076 static BOOL _pam_log_is_silent(int ctrl)
00077 {
00078 return on(ctrl, WINBIND_SILENT);
00079 }
00080
00081 static void _pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
00082 static void _pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
00083 {
00084 va_list args;
00085
00086 if (_pam_log_is_silent(ctrl)) {
00087 return;
00088 }
00089
00090 va_start(args, format);
00091 _pam_log_int(pamh, err, format, args);
00092 va_end(args);
00093 }
00094
00095 static BOOL _pam_log_is_debug_enabled(int ctrl)
00096 {
00097 if (ctrl == -1) {
00098 return False;
00099 }
00100
00101 if (_pam_log_is_silent(ctrl)) {
00102 return False;
00103 }
00104
00105 if (!(ctrl & WINBIND_DEBUG_ARG)) {
00106 return False;
00107 }
00108
00109 return True;
00110 }
00111
00112 static BOOL _pam_log_is_debug_state_enabled(int ctrl)
00113 {
00114 if (!(ctrl & WINBIND_DEBUG_STATE)) {
00115 return False;
00116 }
00117
00118 return _pam_log_is_debug_enabled(ctrl);
00119 }
00120
00121 static void _pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
00122 static void _pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
00123 {
00124 va_list args;
00125
00126 if (!_pam_log_is_debug_enabled(ctrl)) {
00127 return;
00128 }
00129
00130 va_start(args, format);
00131 _pam_log_int(pamh, err, format, args);
00132 va_end(args);
00133 }
00134
00135 static void _pam_log_state_datum(const pam_handle_t *pamh, int ctrl, int item_type, const char *key, int is_string)
00136 {
00137 const void *data = NULL;
00138 if (item_type != 0) {
00139 pam_get_item(pamh, item_type, &data);
00140 } else {
00141 pam_get_data(pamh, key, &data);
00142 }
00143 if (data != NULL) {
00144 const char *type = (item_type != 0) ? "ITEM" : "DATA";
00145 if (is_string != 0) {
00146 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "[pamh: 0x%08x] STATE: %s(%s) = \"%s\" (0x%08x)", (uint32) pamh, type, key, (const char *) data, (uint32) data);
00147 } else {
00148 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "[pamh: 0x%08x] STATE: %s(%s) = 0x%08x", (uint32) pamh, type, key, (uint32) data);
00149 }
00150 }
00151 }
00152
00153 #define _PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, module_data_name) \
00154 _pam_log_state_datum(pamh, ctrl, 0, module_data_name, 0)
00155
00156 #define _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, module_data_name) \
00157 _pam_log_state_datum(pamh, ctrl, 0, module_data_name, 1)
00158
00159 #define _PAM_LOG_STATE_ITEM_POINTER(pamh, ctrl, item_type) \
00160 _pam_log_state_datum(pamh, ctrl, item_type, #item_type, 0)
00161
00162 #define _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, item_type) \
00163 _pam_log_state_datum(pamh, ctrl, item_type, #item_type, 1)
00164
00165 #ifdef DEBUG_PASSWORD
00166 #define _LOG_PASSWORD_AS_STRING 1
00167 #else
00168 #define _LOG_PASSWORD_AS_STRING 0
00169 #endif
00170
00171 #define _PAM_LOG_STATE_ITEM_PASSWORD(pamh, ctrl, item_type) \
00172 _pam_log_state_datum(pamh, ctrl, item_type, #item_type, _LOG_PASSWORD_AS_STRING)
00173
00174 static void _pam_log_state(const pam_handle_t *pamh, int ctrl)
00175 {
00176 if (!_pam_log_is_debug_state_enabled(ctrl)) {
00177 return;
00178 }
00179
00180 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_SERVICE);
00181 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_USER);
00182 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_TTY);
00183 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_RHOST);
00184 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_RUSER);
00185 _PAM_LOG_STATE_ITEM_PASSWORD(pamh, ctrl, PAM_OLDAUTHTOK);
00186 _PAM_LOG_STATE_ITEM_PASSWORD(pamh, ctrl, PAM_AUTHTOK);
00187 _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, PAM_USER_PROMPT);
00188 _PAM_LOG_STATE_ITEM_POINTER(pamh, ctrl, PAM_CONV);
00189 #ifdef PAM_FAIL_DELAY
00190 _PAM_LOG_STATE_ITEM_POINTER(pamh, ctrl, PAM_FAIL_DELAY);
00191 #endif
00192 #ifdef PAM_REPOSITORY
00193 _PAM_LOG_STATE_ITEM_POINTER(pamh, ctrl, PAM_REPOSITORY);
00194 #endif
00195
00196 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_HOMEDIR);
00197 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_LOGONSCRIPT);
00198 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_LOGONSERVER);
00199 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_PROFILEPATH);
00200 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD);
00201 _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH);
00202 _PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, PAM_WINBIND_PWD_LAST_SET);
00203 }
00204
00205 static int _pam_parse(const pam_handle_t *pamh, int flags, int argc, const char **argv, dictionary **result_d)
00206 {
00207 int ctrl = 0;
00208 const char *config_file = NULL;
00209 int i;
00210 const char **v;
00211 dictionary *d = NULL;
00212
00213 if (flags & PAM_SILENT) {
00214 ctrl |= WINBIND_SILENT;
00215 }
00216
00217 for (i=argc,v=argv; i-- > 0; ++v) {
00218 if (!strncasecmp(*v, "config", strlen("config"))) {
00219 ctrl |= WINBIND_CONFIG_FILE;
00220 config_file = v[i];
00221 break;
00222 }
00223 }
00224
00225 if (config_file == NULL) {
00226 config_file = PAM_WINBIND_CONFIG_FILE;
00227 }
00228
00229 d = iniparser_load(config_file);
00230 if (d == NULL) {
00231 goto config_from_pam;
00232 }
00233
00234 if (iniparser_getboolean(d, "global:debug", False)) {
00235 ctrl |= WINBIND_DEBUG_ARG;
00236 }
00237
00238 if (iniparser_getboolean(d, "global:debug_state", False)) {
00239 ctrl |= WINBIND_DEBUG_STATE;
00240 }
00241
00242 if (iniparser_getboolean(d, "global:cached_login", False)) {
00243 ctrl |= WINBIND_CACHED_LOGIN;
00244 }
00245
00246 if (iniparser_getboolean(d, "global:krb5_auth", False)) {
00247 ctrl |= WINBIND_KRB5_AUTH;
00248 }
00249
00250 if (iniparser_getboolean(d, "global:silent", False)) {
00251 ctrl |= WINBIND_SILENT;
00252 }
00253
00254 if (iniparser_getstr(d, "global:krb5_ccache_type") != NULL) {
00255 ctrl |= WINBIND_KRB5_CCACHE_TYPE;
00256 }
00257
00258 if ((iniparser_getstr(d, "global:require-membership-of") != NULL) ||
00259 (iniparser_getstr(d, "global:require_membership_of") != NULL)) {
00260 ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
00261 }
00262
00263 if (iniparser_getboolean(d, "global:try_first_pass", False)) {
00264 ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
00265 }
00266
00267 config_from_pam:
00268
00269 for (i=argc,v=argv; i-- > 0; ++v) {
00270
00271
00272 if (!strcmp(*v,"debug"))
00273 ctrl |= WINBIND_DEBUG_ARG;
00274 else if (!strcasecmp(*v, "debug_state"))
00275 ctrl |= WINBIND_DEBUG_STATE;
00276 else if (!strcasecmp(*v, "use_authtok"))
00277 ctrl |= WINBIND_USE_AUTHTOK_ARG;
00278 else if (!strcasecmp(*v, "use_first_pass"))
00279 ctrl |= WINBIND_USE_FIRST_PASS_ARG;
00280 else if (!strcasecmp(*v, "try_first_pass"))
00281 ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
00282 else if (!strcasecmp(*v, "unknown_ok"))
00283 ctrl |= WINBIND_UNKNOWN_OK_ARG;
00284 else if (!strncasecmp(*v, "require_membership_of", strlen("require_membership_of")))
00285 ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
00286 else if (!strncasecmp(*v, "require-membership-of", strlen("require-membership-of")))
00287 ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
00288 else if (!strcasecmp(*v, "krb5_auth"))
00289 ctrl |= WINBIND_KRB5_AUTH;
00290 else if (!strncasecmp(*v, "krb5_ccache_type", strlen("krb5_ccache_type")))
00291 ctrl |= WINBIND_KRB5_CCACHE_TYPE;
00292 else if (!strcasecmp(*v, "cached_login"))
00293 ctrl |= WINBIND_CACHED_LOGIN;
00294 else {
00295 _pam_log(pamh, ctrl, LOG_ERR, "pam_parse: unknown option: %s", *v);
00296 return -1;
00297 }
00298
00299 }
00300
00301 if (result_d) {
00302 *result_d = d;
00303 } else {
00304 if (d) {
00305 iniparser_freedict(d);
00306 }
00307 }
00308
00309 return ctrl;
00310 };
00311
00312 static void _pam_winbind_cleanup_func(pam_handle_t *pamh, void *data, int error_status)
00313 {
00314 int ctrl = _pam_parse(pamh, 0, 0, NULL, NULL);
00315 if (_pam_log_is_debug_state_enabled(ctrl)) {
00316 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "[pamh: 0x%08x] CLEAN: cleaning up PAM data 0x%08x (error_status = %d)", (uint32) pamh, (uint32) data, error_status);
00317 }
00318 SAFE_FREE(data);
00319 }
00320
00321
00322 static const struct ntstatus_errors {
00323 const char *ntstatus_string;
00324 const char *error_string;
00325 } ntstatus_errors[] = {
00326 {"NT_STATUS_OK", "Success"},
00327 {"NT_STATUS_BACKUP_CONTROLLER", "No primary Domain Controler available"},
00328 {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", "No domain controllers found"},
00329 {"NT_STATUS_NO_LOGON_SERVERS", "No logon servers"},
00330 {"NT_STATUS_PWD_TOO_SHORT", "Password too short"},
00331 {"NT_STATUS_PWD_TOO_RECENT", "The password of this user is too recent to change"},
00332 {"NT_STATUS_PWD_HISTORY_CONFLICT", "Password is already in password history"},
00333 {"NT_STATUS_PASSWORD_EXPIRED", "Your password has expired"},
00334 {"NT_STATUS_PASSWORD_MUST_CHANGE", "You need to change your password now"},
00335 {"NT_STATUS_INVALID_WORKSTATION", "You are not allowed to logon from this workstation"},
00336 {"NT_STATUS_INVALID_LOGON_HOURS", "You are not allowed to logon at this time"},
00337 {"NT_STATUS_ACCOUNT_EXPIRED", "Your account has expired. Please contact your System administrator"},
00338 {"NT_STATUS_ACCOUNT_DISABLED", "Your account is disabled. Please contact your System administrator"},
00339 {"NT_STATUS_ACCOUNT_LOCKED_OUT", "Your account has been locked. Please contact your System administrator"},
00340 {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", "Invalid Trust Account"},
00341 {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", "Invalid Trust Account"},
00342 {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", "Invalid Trust Account"},
00343 {"NT_STATUS_ACCESS_DENIED", "Access is denied"},
00344 {NULL, NULL}
00345 };
00346
00347 const char *_get_ntstatus_error_string(const char *nt_status_string)
00348 {
00349 int i;
00350 for (i=0; ntstatus_errors[i].ntstatus_string != NULL; i++) {
00351 if (!strcasecmp(ntstatus_errors[i].ntstatus_string, nt_status_string)) {
00352 return ntstatus_errors[i].error_string;
00353 }
00354 }
00355 return NULL;
00356 }
00357
00358
00359
00360
00361
00362 static int converse(pam_handle_t *pamh, int nargs,
00363 struct pam_message **message,
00364 struct pam_response **response)
00365 {
00366 int retval;
00367 struct pam_conv *conv;
00368
00369 retval = _pam_get_item(pamh, PAM_CONV, &conv );
00370 if (retval == PAM_SUCCESS) {
00371 retval = conv->conv(nargs, (const struct pam_message **)message,
00372 response, conv->appdata_ptr);
00373 }
00374
00375 return retval;
00376 }
00377
00378
00379 static int _make_remark(pam_handle_t * pamh, int flags, int type, const char *text)
00380 {
00381 int retval = PAM_SUCCESS;
00382
00383 struct pam_message *pmsg[1], msg[1];
00384 struct pam_response *resp;
00385
00386 if (flags & WINBIND_SILENT) {
00387 return PAM_SUCCESS;
00388 }
00389
00390 pmsg[0] = &msg[0];
00391 msg[0].msg = CONST_DISCARD(char *, text);
00392 msg[0].msg_style = type;
00393
00394 resp = NULL;
00395 retval = converse(pamh, 1, pmsg, &resp);
00396
00397 if (resp) {
00398 _pam_drop_reply(resp, 1);
00399 }
00400 return retval;
00401 }
00402
00403 static int _make_remark_v(pam_handle_t * pamh, int flags, int type, const char *format, va_list args)
00404 {
00405 char *var;
00406 int ret;
00407
00408 ret = vasprintf(&var, format, args);
00409 if (ret < 0) {
00410 _pam_log(pamh, 0, LOG_ERR, "memory allocation failure");
00411 return ret;
00412 }
00413
00414 ret = _make_remark(pamh, flags, type, var);
00415 SAFE_FREE(var);
00416 return ret;
00417 }
00418
00419 static int _make_remark_format(pam_handle_t * pamh, int flags, int type, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
00420 static int _make_remark_format(pam_handle_t * pamh, int flags, int type, const char *format, ...)
00421 {
00422 int ret;
00423 va_list args;
00424
00425 va_start(args, format);
00426 ret = _make_remark_v(pamh, flags, type, format, args);
00427 va_end(args);
00428 return ret;
00429 }
00430
00431 static int pam_winbind_request(pam_handle_t * pamh, int ctrl,
00432 enum winbindd_cmd req_type,
00433 struct winbindd_request *request,
00434 struct winbindd_response *response)
00435 {
00436
00437 init_request(request, req_type);
00438
00439 if (write_sock(request, sizeof(*request), 0, 0) == -1) {
00440 _pam_log(pamh, ctrl, LOG_ERR, "pam_winbind_request: write to socket failed!");
00441 close_sock();
00442 return PAM_SERVICE_ERR;
00443 }
00444
00445
00446 if (read_reply(response) == -1) {
00447 _pam_log(pamh, ctrl, LOG_ERR, "pam_winbind_request: read from socket failed!");
00448 close_sock();
00449 return PAM_SERVICE_ERR;
00450 }
00451
00452
00453 close_sock();
00454
00455
00456 if (response->result == WINBINDD_OK) {
00457 return PAM_SUCCESS;
00458 }
00459
00460
00461 switch (req_type) {
00462
00463 case WINBINDD_GETPWNAM:
00464 case WINBINDD_LOOKUPNAME:
00465 if (strlen(response->data.auth.nt_status_string) > 0) {
00466 _pam_log(pamh, ctrl, LOG_ERR, "request failed, NT error was %s",
00467 response->data.auth.nt_status_string);
00468 } else {
00469 _pam_log(pamh, ctrl, LOG_ERR, "request failed");
00470 }
00471 return PAM_USER_UNKNOWN;
00472 default:
00473 break;
00474 }
00475
00476 if (response->data.auth.pam_error != PAM_SUCCESS) {
00477 _pam_log(pamh, ctrl, LOG_ERR, "request failed: %s, PAM error was %s (%d), NT error was %s",
00478 response->data.auth.error_string,
00479 pam_strerror(pamh, response->data.auth.pam_error),
00480 response->data.auth.pam_error,
00481 response->data.auth.nt_status_string);
00482 return response->data.auth.pam_error;
00483 }
00484
00485 _pam_log(pamh, ctrl, LOG_ERR, "request failed, but PAM error 0!");
00486
00487 return PAM_SERVICE_ERR;
00488 }
00489
00490 static int pam_winbind_request_log(pam_handle_t * pamh,
00491 int ctrl,
00492 enum winbindd_cmd req_type,
00493 struct winbindd_request *request,
00494 struct winbindd_response *response,
00495 const char *user)
00496 {
00497 int retval;
00498
00499 retval = pam_winbind_request(pamh, ctrl, req_type, request, response);
00500
00501 switch (retval) {
00502 case PAM_AUTH_ERR:
00503
00504 _pam_log(pamh, ctrl, LOG_WARNING, "user '%s' denied access (incorrect password or invalid membership)", user);
00505 return retval;
00506 case PAM_ACCT_EXPIRED:
00507
00508 _pam_log(pamh, ctrl, LOG_WARNING, "user '%s' account expired", user);
00509 return retval;
00510 case PAM_AUTHTOK_EXPIRED:
00511
00512 _pam_log(pamh, ctrl, LOG_WARNING, "user '%s' password expired", user);
00513 return retval;
00514 case PAM_NEW_AUTHTOK_REQD:
00515
00516 _pam_log(pamh, ctrl, LOG_WARNING, "user '%s' new password required", user);
00517 return retval;
00518 case PAM_USER_UNKNOWN:
00519
00520 _pam_log_debug(pamh, ctrl, LOG_NOTICE, "user '%s' not found", user);
00521 if (ctrl & WINBIND_UNKNOWN_OK_ARG) {
00522 return PAM_IGNORE;
00523 }
00524 return retval;
00525 case PAM_SUCCESS:
00526
00527 switch (req_type) {
00528 case WINBINDD_INFO:
00529 break;
00530 case WINBINDD_PAM_AUTH:
00531 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' granted access", user);
00532 break;
00533 case WINBINDD_PAM_CHAUTHTOK:
00534 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' password changed", user);
00535 break;
00536 default:
00537 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' OK", user);
00538 break;
00539 }
00540
00541 return retval;
00542 default:
00543
00544 _pam_log(pamh, ctrl, LOG_ERR, "internal module error (retval = %d, user = '%s')",
00545 retval, user);
00546 return retval;
00547 }
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 static BOOL _pam_send_password_expiry_message(pam_handle_t *pamh, int ctrl, time_t next_change, time_t now, BOOL *already_expired)
00563 {
00564 int days = 0;
00565 struct tm tm_now, tm_next_change;
00566
00567 if (already_expired) {
00568 *already_expired = False;
00569 }
00570
00571 if (next_change <= now) {
00572 PAM_WB_REMARK_DIRECT(pamh, ctrl, "NT_STATUS_PASSWORD_EXPIRED");
00573 if (already_expired) {
00574 *already_expired = True;
00575 }
00576 return True;
00577 }
00578
00579 if ((next_change < 0) ||
00580 (next_change > now + DAYS_TO_WARN_BEFORE_PWD_EXPIRES * SECONDS_PER_DAY)) {
00581 return False;
00582 }
00583
00584 if ((localtime_r(&now, &tm_now) == NULL) ||
00585 (localtime_r(&next_change, &tm_next_change) == NULL)) {
00586 return False;
00587 }
00588
00589 days = (tm_next_change.tm_yday+tm_next_change.tm_year*365) - (tm_now.tm_yday+tm_now.tm_year*365);
00590
00591 if (days == 0) {
00592 _make_remark(pamh, ctrl, PAM_TEXT_INFO, "Your password expires today");
00593 return True;
00594 }
00595
00596 if (days > 0 && days < DAYS_TO_WARN_BEFORE_PWD_EXPIRES) {
00597 _make_remark_format(pamh, ctrl, PAM_TEXT_INFO, "Your password will expire in %d %s",
00598 days, (days > 1) ? "days":"day");
00599 return True;
00600 }
00601
00602 return False;
00603 }
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 static void _pam_warn_password_expiry(pam_handle_t *pamh,
00617 int flags,
00618 const struct winbindd_response *response,
00619 BOOL *already_expired)
00620 {
00621 time_t now = time(NULL);
00622 time_t next_change = 0;
00623
00624 if (already_expired) {
00625 *already_expired = False;
00626 }
00627
00628
00629 if (response->data.auth.info3.acct_flags & ACB_PWNOEXP) {
00630 return;
00631 }
00632
00633
00634 if (PAM_WB_GRACE_LOGON(response->data.auth.info3.user_flgs)) {
00635 return;
00636 }
00637
00638
00639 next_change = response->data.auth.info3.pass_must_change_time;
00640
00641 if (_pam_send_password_expiry_message(pamh, flags, next_change, now,
00642 already_expired)) {
00643 return;
00644 }
00645
00646
00647
00648
00649 if (response->data.auth.policy.expire <= 0) {
00650 return;
00651 }
00652
00653 next_change = response->data.auth.info3.pass_last_set_time +
00654 response->data.auth.policy.expire;
00655
00656 if (_pam_send_password_expiry_message(pamh, flags, next_change, now,
00657 already_expired)) {
00658 return;
00659 }
00660
00661
00662 }
00663
00664 #define IS_SID_STRING(name) (strncmp("S-", name, 2) == 0)
00665
00666 static BOOL safe_append_string(char *dest,
00667 const char *src,
00668 int dest_buffer_size)
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 {
00680 int dest_length = strlen(dest);
00681 int src_length = strlen(src);
00682
00683 if ( dest_length + src_length + 1 > dest_buffer_size ) {
00684 return False;
00685 }
00686
00687 memcpy(dest + dest_length, src, src_length + 1);
00688 return True;
00689 }
00690
00691 static BOOL winbind_name_to_sid_string(pam_handle_t *pamh,
00692 int ctrl,
00693 const char *user,
00694 const char *name,
00695 char *sid_list_buffer,
00696 int sid_list_buffer_size)
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 {
00710 const char* sid_string;
00711 struct winbindd_response sid_response;
00712
00713
00714 if (IS_SID_STRING(name)) {
00715 sid_string = name;
00716 } else {
00717 struct winbindd_request sid_request;
00718
00719 ZERO_STRUCT(sid_request);
00720 ZERO_STRUCT(sid_response);
00721
00722 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "no sid given, looking up: %s\n", name);
00723
00724
00725 strncpy(sid_request.data.name.name, name,
00726 sizeof(sid_request.data.name.name) - 1);
00727
00728 if (pam_winbind_request_log(pamh, ctrl, WINBINDD_LOOKUPNAME, &sid_request, &sid_response, user)) {
00729 _pam_log(pamh, ctrl, LOG_INFO, "could not lookup name: %s\n", name);
00730 return False;
00731 }
00732
00733 sid_string = sid_response.data.sid.sid;
00734 }
00735
00736 if (!safe_append_string(sid_list_buffer, sid_string, sid_list_buffer_size)) {
00737 return False;
00738 }
00739
00740 return True;
00741 }
00742
00743 static BOOL winbind_name_list_to_sid_string_list(pam_handle_t *pamh,
00744 int ctrl,
00745 const char *user,
00746 const char *name_list,
00747 char *sid_list_buffer,
00748 int sid_list_buffer_size)
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 {
00762 BOOL result = False;
00763 char *current_name = NULL;
00764 const char *search_location;
00765 const char *comma;
00766
00767 if ( sid_list_buffer_size > 0 ) {
00768 sid_list_buffer[0] = 0;
00769 }
00770
00771 search_location = name_list;
00772 while ( (comma = strstr(search_location, ",")) != NULL ) {
00773 current_name = strndup(search_location, comma - search_location);
00774 if (NULL == current_name) {
00775 goto out;
00776 }
00777
00778 if (!winbind_name_to_sid_string(pamh, ctrl, user, current_name, sid_list_buffer, sid_list_buffer_size)) {
00779 goto out;
00780 }
00781
00782 SAFE_FREE(current_name);
00783
00784 if (!safe_append_string(sid_list_buffer, ",", sid_list_buffer_size)) {
00785 goto out;
00786 }
00787
00788 search_location = comma + 1;
00789 }
00790
00791 if (!winbind_name_to_sid_string(pamh, ctrl, user, search_location, sid_list_buffer, sid_list_buffer_size)) {
00792 goto out;
00793 }
00794
00795 result = True;
00796
00797 out:
00798 SAFE_FREE(current_name);
00799 return result;
00800 }
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 static void _pam_setup_krb5_env(pam_handle_t *pamh, int ctrl, const char *krb5ccname)
00813 {
00814 char var[PATH_MAX];
00815 int ret;
00816
00817 if (off(ctrl, WINBIND_KRB5_AUTH)) {
00818 return;
00819 }
00820
00821 if (!krb5ccname || (strlen(krb5ccname) == 0)) {
00822 return;
00823 }
00824
00825 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "request returned KRB5CCNAME: %s", krb5ccname);
00826
00827 if (snprintf(var, sizeof(var), "KRB5CCNAME=%s", krb5ccname) == -1) {
00828 return;
00829 }
00830
00831 ret = pam_putenv(pamh, var);
00832 if (ret) {
00833 _pam_log(pamh, ctrl, LOG_ERR, "failed to set KRB5CCNAME to %s: %s",
00834 var, pam_strerror(pamh, ret));
00835 }
00836 }
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849 static void _pam_set_data_string(pam_handle_t *pamh, int ctrl, const char *data_name, const char *value)
00850 {
00851 int ret;
00852
00853 if ( !data_name || !value || (strlen(data_name) == 0) || (strlen(value) == 0) ) {
00854 return;
00855 }
00856
00857 ret = pam_set_data(pamh, data_name, (void *)strdup(value), _pam_winbind_cleanup_func);
00858 if (ret) {
00859 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "Could not set data %s: %s\n",
00860 data_name, pam_strerror(pamh, ret));
00861 }
00862
00863 }
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 static void _pam_set_data_info3(pam_handle_t *pamh, int ctrl, struct winbindd_response *response)
00877 {
00878 _pam_set_data_string(pamh, ctrl, PAM_WINBIND_HOMEDIR, response->data.auth.info3.home_dir);
00879 _pam_set_data_string(pamh, ctrl, PAM_WINBIND_LOGONSCRIPT, response->data.auth.info3.logon_script);
00880 _pam_set_data_string(pamh, ctrl, PAM_WINBIND_LOGONSERVER, response->data.auth.info3.logon_srv);
00881 _pam_set_data_string(pamh, ctrl, PAM_WINBIND_PROFILEPATH, response->data.auth.info3.profile_path);
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 static void _pam_free_data_info3(pam_handle_t *pamh)
00893 {
00894 pam_set_data(pamh, PAM_WINBIND_HOMEDIR, NULL, NULL);
00895 pam_set_data(pamh, PAM_WINBIND_LOGONSCRIPT, NULL, NULL);
00896 pam_set_data(pamh, PAM_WINBIND_LOGONSERVER, NULL, NULL);
00897 pam_set_data(pamh, PAM_WINBIND_PROFILEPATH, NULL, NULL);
00898 }
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 static void _pam_warn_logon_type(pam_handle_t *pamh, int ctrl, const char *username, uint32 info3_user_flgs)
00912 {
00913
00914 if (PAM_WB_GRACE_LOGON(info3_user_flgs)) {
00915
00916 _make_remark(pamh, ctrl, PAM_ERROR_MSG,
00917 "Grace login. Please change your password as soon you're online again");
00918 _pam_log_debug(pamh, ctrl, LOG_DEBUG,
00919 "User %s logged on using grace logon\n", username);
00920
00921 } else if (PAM_WB_CACHED_LOGON(info3_user_flgs)) {
00922
00923 _make_remark(pamh, ctrl, PAM_ERROR_MSG,
00924 "Domain Controller unreachable, using cached credentials instead. Network resources may be unavailable");
00925 _pam_log_debug(pamh, ctrl, LOG_DEBUG,
00926 "User %s logged on using cached credentials\n", username);
00927 }
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 static char *_pam_compose_pwd_restriction_string(struct winbindd_response *response)
00939 {
00940 char *str = NULL;
00941 size_t offset = 0, ret = 0, str_size = 1024;
00942
00943 str = (char *)malloc(str_size);
00944 if (!str) {
00945 return NULL;
00946 }
00947
00948 memset(str, '\0', str_size);
00949
00950 offset = snprintf(str, str_size, "Your password ");
00951 if (offset == -1) {
00952 goto failed;
00953 }
00954
00955 if (response->data.auth.policy.min_length_password > 0) {
00956 ret = snprintf(str+offset, str_size-offset,
00957 "must be at least %d characters; ",
00958 response->data.auth.policy.min_length_password);
00959 if (ret == -1) {
00960 goto failed;
00961 }
00962 offset += ret;
00963 }
00964
00965 if (response->data.auth.policy.password_history > 0) {
00966 ret = snprintf(str+offset, str_size-offset,
00967 "cannot repeat any of your previous %d passwords; ",
00968 response->data.auth.policy.password_history);
00969 if (ret == -1) {
00970 goto failed;
00971 }
00972 offset += ret;
00973 }
00974
00975 if (response->data.auth.policy.password_properties & DOMAIN_PASSWORD_COMPLEX) {
00976 ret = snprintf(str+offset, str_size-offset,
00977 "must contain capitals, numerals or punctuation; "
00978 "and cannot contain your account or full name; ");
00979 if (ret == -1) {
00980 goto failed;
00981 }
00982 offset += ret;
00983 }
00984
00985 ret = snprintf(str+offset, str_size-offset,
00986 "Please type a different password. "
00987 "Type a password which meets these requirements in both text boxes.");
00988 if (ret == -1) {
00989 goto failed;
00990 }
00991
00992 return str;
00993
00994 failed:
00995 SAFE_FREE(str);
00996 return NULL;
00997 }
00998
00999
01000 static int winbind_auth_request(pam_handle_t * pamh,
01001 int ctrl,
01002 const char *user,
01003 const char *pass,
01004 const char *member,
01005 const char *cctype,
01006 struct winbindd_response *p_response,
01007 time_t *pwd_last_set,
01008 char **user_ret)
01009 {
01010 struct winbindd_request request;
01011 struct winbindd_response response;
01012 int ret;
01013 BOOL already_expired = False;
01014
01015 ZERO_STRUCT(request);
01016 ZERO_STRUCT(response);
01017
01018 if (pwd_last_set) {
01019 *pwd_last_set = 0;
01020 }
01021
01022 strncpy(request.data.auth.user, user,
01023 sizeof(request.data.auth.user)-1);
01024
01025 strncpy(request.data.auth.pass, pass,
01026 sizeof(request.data.auth.pass)-1);
01027
01028 request.data.auth.krb5_cc_type[0] = '\0';
01029 request.data.auth.uid = -1;
01030
01031 request.flags = WBFLAG_PAM_INFO3_TEXT |
01032 WBFLAG_PAM_GET_PWD_POLICY |
01033 WBFLAG_PAM_CONTACT_TRUSTDOM;
01034
01035 if (ctrl & (WINBIND_KRB5_AUTH|WINBIND_CACHED_LOGIN)) {
01036 struct passwd *pwd = NULL;
01037
01038 pwd = getpwnam(user);
01039 if (pwd == NULL) {
01040 return PAM_USER_UNKNOWN;
01041 }
01042 request.data.auth.uid = pwd->pw_uid;
01043 }
01044
01045 if (ctrl & WINBIND_KRB5_AUTH) {
01046
01047 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling krb5 login flag\n");
01048
01049 request.flags |= WBFLAG_PAM_KRB5 | WBFLAG_PAM_FALLBACK_AFTER_KRB5;
01050 }
01051
01052 if (ctrl & WINBIND_CACHED_LOGIN) {
01053 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling cached login flag\n");
01054 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
01055 }
01056
01057 if (user_ret) {
01058 *user_ret = NULL;
01059 request.flags |= WBFLAG_PAM_UNIX_NAME;
01060 }
01061
01062 if (cctype != NULL) {
01063 strncpy(request.data.auth.krb5_cc_type, cctype,
01064 sizeof(request.data.auth.krb5_cc_type) - 1);
01065 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "enabling request for a %s krb5 ccache\n", cctype);
01066 }
01067
01068 request.data.auth.require_membership_of_sid[0] = '\0';
01069
01070 if (member != NULL) {
01071
01072 if (!winbind_name_list_to_sid_string_list(pamh, ctrl, user, member,
01073 request.data.auth.require_membership_of_sid,
01074 sizeof(request.data.auth.require_membership_of_sid))) {
01075
01076 _pam_log_debug(pamh, ctrl, LOG_ERR, "failed to serialize membership of sid \"%s\"\n", member);
01077 return PAM_AUTH_ERR;
01078 }
01079 }
01080
01081 ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_AUTH, &request, &response, user);
01082
01083 if (pwd_last_set) {
01084 *pwd_last_set = response.data.auth.info3.pass_last_set_time;
01085 }
01086
01087 if (p_response) {
01088
01089 *p_response = response;
01090 return ret;
01091 }
01092
01093 if (ret) {
01094 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_PASSWORD_EXPIRED");
01095 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_PASSWORD_MUST_CHANGE");
01096 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_INVALID_WORKSTATION");
01097 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_INVALID_LOGON_HOURS");
01098 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCOUNT_EXPIRED");
01099 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCOUNT_DISABLED");
01100 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCOUNT_LOCKED_OUT");
01101 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT");
01102 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT");
01103 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT");
01104 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
01105 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NO_LOGON_SERVERS");
01106 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_WRONG_PASSWORD");
01107 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCESS_DENIED");
01108 }
01109
01110 if (ret == PAM_SUCCESS) {
01111
01112
01113 _pam_warn_password_expiry(pamh, ctrl, &response, &already_expired);
01114
01115 if (already_expired == True) {
01116 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "Password has expired "
01117 "(Password was last set: %lld, the policy says "
01118 "it should expire here %lld (now it's: %lu))\n",
01119 response.data.auth.info3.pass_last_set_time,
01120 response.data.auth.info3.pass_last_set_time +
01121 response.data.auth.policy.expire,
01122 time(NULL));
01123
01124 return PAM_AUTHTOK_EXPIRED;
01125 }
01126
01127
01128 _pam_warn_logon_type(pamh, ctrl, user, response.data.auth.info3.user_flgs);
01129
01130
01131 _pam_set_data_info3(pamh, ctrl, &response);
01132
01133
01134 _pam_setup_krb5_env(pamh, ctrl, response.data.auth.krb5ccname);
01135
01136
01137 if (user_ret && response.extra_data.data) {
01138
01139 *user_ret = (char *)response.extra_data.data;
01140 }
01141 }
01142
01143 return ret;
01144 }
01145
01146
01147 static int winbind_chauthtok_request(pam_handle_t * pamh,
01148 int ctrl,
01149 const char *user,
01150 const char *oldpass,
01151 const char *newpass,
01152 time_t pwd_last_set)
01153 {
01154 struct winbindd_request request;
01155 struct winbindd_response response;
01156 int ret;
01157
01158 ZERO_STRUCT(request);
01159 ZERO_STRUCT(response);
01160
01161 if (request.data.chauthtok.user == NULL) return -2;
01162
01163 strncpy(request.data.chauthtok.user, user,
01164 sizeof(request.data.chauthtok.user) - 1);
01165
01166 if (oldpass != NULL) {
01167 strncpy(request.data.chauthtok.oldpass, oldpass,
01168 sizeof(request.data.chauthtok.oldpass) - 1);
01169 } else {
01170 request.data.chauthtok.oldpass[0] = '\0';
01171 }
01172
01173 if (newpass != NULL) {
01174 strncpy(request.data.chauthtok.newpass, newpass,
01175 sizeof(request.data.chauthtok.newpass) - 1);
01176 } else {
01177 request.data.chauthtok.newpass[0] = '\0';
01178 }
01179
01180 if (ctrl & WINBIND_KRB5_AUTH) {
01181 request.flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM;
01182 }
01183
01184 if (ctrl & WINBIND_CACHED_LOGIN) {
01185 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
01186 }
01187
01188 ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_CHAUTHTOK, &request, &response, user);
01189
01190 if (ret == PAM_SUCCESS) {
01191 return ret;
01192 }
01193
01194 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_BACKUP_CONTROLLER");
01195 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
01196 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_NO_LOGON_SERVERS");
01197 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_ACCESS_DENIED");
01198
01199
01200 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_PWD_TOO_SHORT");
01201
01202
01203 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_PWD_TOO_RECENT");
01204
01205
01206 PAM_WB_REMARK_CHECK_RESPONSE_RET(pamh, ctrl, response, "NT_STATUS_PWD_HISTORY_CONFLICT");
01207
01208 if (!strcasecmp(response.data.auth.nt_status_string, "NT_STATUS_PASSWORD_RESTRICTION")) {
01209
01210 char *pwd_restriction_string = NULL;
01211
01212
01213 switch (response.data.auth.reject_reason) {
01214 case -1:
01215 break;
01216 case REJECT_REASON_OTHER:
01217 if ((response.data.auth.policy.min_passwordage > 0) &&
01218 (pwd_last_set + response.data.auth.policy.min_passwordage > time(NULL))) {
01219 PAM_WB_REMARK_DIRECT(pamh, ctrl, "NT_STATUS_PWD_TOO_RECENT");
01220 }
01221 break;
01222 case REJECT_REASON_TOO_SHORT:
01223 PAM_WB_REMARK_DIRECT(pamh, ctrl, "NT_STATUS_PWD_TOO_SHORT");
01224 break;
01225 case REJECT_REASON_IN_HISTORY:
01226 PAM_WB_REMARK_DIRECT(pamh, ctrl, "NT_STATUS_PWD_HISTORY_CONFLICT");
01227 break;
01228 case REJECT_REASON_NOT_COMPLEX:
01229 _make_remark(pamh, ctrl, PAM_ERROR_MSG, "Password does not meet complexity requirements");
01230 break;
01231 default:
01232 _pam_log_debug(pamh, ctrl, LOG_DEBUG,
01233 "unknown password change reject reason: %d",
01234 response.data.auth.reject_reason);
01235 break;
01236 }
01237
01238 pwd_restriction_string = _pam_compose_pwd_restriction_string(&response);
01239 if (pwd_restriction_string) {
01240 _make_remark(pamh, ctrl, PAM_ERROR_MSG, pwd_restriction_string);
01241 SAFE_FREE(pwd_restriction_string);
01242 }
01243 }
01244
01245 return ret;
01246 }
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256 static int valid_user(pam_handle_t *pamh, int ctrl, const char *user)
01257 {
01258
01259
01260
01261
01262 struct passwd *pwd = NULL;
01263 struct winbindd_request request;
01264 struct winbindd_response response;
01265 int ret;
01266
01267 ZERO_STRUCT(request);
01268 ZERO_STRUCT(response);
01269
01270 pwd = getpwnam(user);
01271 if (pwd == NULL) {
01272 return 1;
01273 }
01274
01275 strncpy(request.data.username, user,
01276 sizeof(request.data.username) - 1);
01277
01278 ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_GETPWNAM, &request, &response, user);
01279
01280 switch (ret) {
01281 case PAM_USER_UNKNOWN:
01282 return 1;
01283 case PAM_SUCCESS:
01284 return 0;
01285 default:
01286 break;
01287 }
01288 return -1;
01289 }
01290
01291 static char *_pam_delete(register char *xx)
01292 {
01293 _pam_overwrite(xx);
01294 _pam_drop(xx);
01295 return NULL;
01296 }
01297
01298
01299
01300
01301
01302 static int _winbind_read_password(pam_handle_t * pamh,
01303 unsigned int ctrl,
01304 const char *comment,
01305 const char *prompt1,
01306 const char *prompt2,
01307 const char **pass)
01308 {
01309 int authtok_flag;
01310 int retval;
01311 const char *item;
01312 char *token;
01313
01314 _pam_log(pamh, ctrl, LOG_DEBUG, "getting password (0x%08x)", ctrl);
01315
01316
01317
01318
01319
01320 *pass = token = NULL;
01321
01322
01323
01324
01325
01326 authtok_flag = on(WINBIND__OLD_PASSWORD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
01327
01328
01329
01330
01331
01332 if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) || on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
01333 retval = _pam_get_item(pamh, authtok_flag, &item);
01334 if (retval != PAM_SUCCESS) {
01335
01336 _pam_log(pamh, ctrl, LOG_ALERT,
01337 "pam_get_item returned error to unix-read-password"
01338 );
01339 return retval;
01340 } else if (item != NULL) {
01341 *pass = item;
01342 item = NULL;
01343 _pam_log(pamh, ctrl, LOG_DEBUG,
01344 "pam_get_item returned a password");
01345 return PAM_SUCCESS;
01346 } else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
01347 return PAM_AUTHTOK_RECOVER_ERR;
01348 } else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl)
01349 && off(WINBIND__OLD_PASSWORD, ctrl)) {
01350 return PAM_AUTHTOK_RECOVER_ERR;
01351 }
01352 }
01353
01354
01355
01356
01357
01358 {
01359 struct pam_message msg[3], *pmsg[3];
01360 struct pam_response *resp;
01361 int i, replies;
01362
01363
01364
01365 if (comment != NULL && off(ctrl, WINBIND_SILENT)) {
01366 pmsg[0] = &msg[0];
01367 msg[0].msg_style = PAM_TEXT_INFO;
01368 msg[0].msg = CONST_DISCARD(char *, comment);
01369 i = 1;
01370 } else {
01371 i = 0;
01372 }
01373
01374 pmsg[i] = &msg[i];
01375 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
01376 msg[i++].msg = CONST_DISCARD(char *, prompt1);
01377 replies = 1;
01378
01379 if (prompt2 != NULL) {
01380 pmsg[i] = &msg[i];
01381 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
01382 msg[i++].msg = CONST_DISCARD(char *, prompt2);
01383 ++replies;
01384 }
01385
01386 resp = NULL;
01387 retval = converse(pamh, i, pmsg, &resp);
01388
01389 if (resp != NULL) {
01390
01391
01392
01393 if (retval == PAM_SUCCESS) {
01394
01395 token = x_strdup(resp[i - replies].resp);
01396 if (token != NULL) {
01397 if (replies == 2) {
01398
01399 if (!resp[i - 1].resp
01400 || strcmp(token, resp[i - 1].resp)) {
01401 _pam_delete(token);
01402 retval = PAM_AUTHTOK_RECOVER_ERR;
01403 _make_remark(pamh, ctrl, PAM_ERROR_MSG, MISTYPED_PASS);
01404 }
01405 }
01406 } else {
01407 _pam_log(pamh, ctrl, LOG_NOTICE, "could not recover authentication token");
01408 retval = PAM_AUTHTOK_RECOVER_ERR;
01409 }
01410
01411 }
01412
01413
01414
01415
01416
01417 _pam_drop_reply(resp, i);
01418
01419 } else {
01420 retval = (retval == PAM_SUCCESS)
01421 ? PAM_AUTHTOK_RECOVER_ERR : retval;
01422 }
01423 }
01424
01425 if (retval != PAM_SUCCESS) {
01426 _pam_log_debug(pamh, ctrl, LOG_DEBUG,
01427 "unable to obtain a password");
01428 return retval;
01429 }
01430
01431
01432
01433
01434 retval = pam_set_item(pamh, authtok_flag, token);
01435 _pam_delete(token);
01436 if (retval != PAM_SUCCESS ||
01437 (retval = _pam_get_item(pamh, authtok_flag, &item)) != PAM_SUCCESS) {
01438
01439 _pam_log(pamh, ctrl, LOG_CRIT, "error manipulating password");
01440 return retval;
01441
01442 }
01443
01444 *pass = item;
01445 item = NULL;
01446
01447 return PAM_SUCCESS;
01448 }
01449
01450 const char *get_conf_item_string(const pam_handle_t *pamh,
01451 int argc,
01452 const char **argv,
01453 int ctrl,
01454 dictionary *d,
01455 const char *item,
01456 int config_flag)
01457 {
01458 int i = 0;
01459 const char *parm_opt = NULL;
01460 char *key = NULL;
01461
01462 if (!(ctrl & config_flag)) {
01463 goto out;
01464 }
01465
01466
01467
01468 if (d != NULL) {
01469
01470 if (!asprintf(&key, "global:%s", item)) {
01471 goto out;
01472 }
01473
01474 parm_opt = iniparser_getstr(d, key);
01475 SAFE_FREE(key);
01476 }
01477
01478 for ( i=0; i<argc; i++ ) {
01479
01480 if ((strncmp(argv[i], item, strlen(item)) == 0)) {
01481 char *p;
01482
01483 if ( (p = strchr( argv[i], '=' )) == NULL) {
01484 _pam_log(pamh, ctrl, LOG_INFO, "no \"=\" delimiter for \"%s\" found\n", item);
01485 goto out;
01486 }
01487 _pam_log_debug(pamh, ctrl, LOG_INFO, "PAM config: %s '%s'\n", item, p+1);
01488 return p + 1;
01489 }
01490 }
01491
01492 if (d != NULL) {
01493 _pam_log_debug(pamh, ctrl, LOG_INFO, "CONFIG file: %s '%s'\n", item, parm_opt);
01494 }
01495 out:
01496 return parm_opt;
01497 }
01498
01499 const char *get_krb5_cc_type_from_config(const pam_handle_t *pamh, int argc, const char **argv, int ctrl, dictionary *d)
01500 {
01501 return get_conf_item_string(pamh, argc, argv, ctrl, d, "krb5_ccache_type", WINBIND_KRB5_CCACHE_TYPE);
01502 }
01503
01504 const char *get_member_from_config(const pam_handle_t *pamh, int argc, const char **argv, int ctrl, dictionary *d)
01505 {
01506 const char *ret = NULL;
01507 ret = get_conf_item_string(pamh, argc, argv, ctrl, d, "require_membership_of", WINBIND_REQUIRED_MEMBERSHIP);
01508 if (ret) {
01509 return ret;
01510 }
01511 return get_conf_item_string(pamh, argc, argv, ctrl, d, "require-membership-of", WINBIND_REQUIRED_MEMBERSHIP);
01512 }
01513
01514 PAM_EXTERN
01515 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
01516 int argc, const char **argv)
01517 {
01518 const char *username;
01519 const char *password;
01520 const char *member = NULL;
01521 const char *cctype = NULL;
01522 int retval = PAM_AUTH_ERR;
01523 dictionary *d = NULL;
01524 char *username_ret = NULL;
01525 char *new_authtok_required = NULL;
01526 char *real_username = NULL;
01527
01528
01529 int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01530 if (ctrl == -1) {
01531 retval = PAM_SYSTEM_ERR;
01532 goto out;
01533 }
01534
01535 _PAM_LOG_FUNCTION_ENTER("pam_sm_authenticate", pamh, ctrl, flags);
01536
01537
01538 retval = pam_get_user(pamh, &username, NULL);
01539 if ((retval != PAM_SUCCESS) || (!username)) {
01540 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "can not get the username");
01541 retval = PAM_SERVICE_ERR;
01542 goto out;
01543 }
01544
01545 #if defined(AIX)
01546
01547
01548
01549 if ( username[0] == '_' ) {
01550 uid_t id = atoi( &username[1] );
01551 struct passwd *pw = NULL;
01552
01553 if ( (id!=0) && ((pw = getpwuid( id )) != NULL) ) {
01554 real_username = strdup( pw->pw_name );
01555 }
01556 }
01557 #endif
01558
01559 if ( !real_username ) {
01560
01561 if ( (real_username = strdup( username )) == NULL ) {
01562 _pam_log_debug(pamh, ctrl, LOG_DEBUG,
01563 "memory allocation failure when copying username");
01564 retval = PAM_SERVICE_ERR;
01565 goto out;
01566 }
01567 }
01568
01569 retval = _winbind_read_password(pamh, ctrl, NULL,
01570 "Password: ", NULL,
01571 &password);
01572
01573 if (retval != PAM_SUCCESS) {
01574 _pam_log(pamh, ctrl, LOG_ERR, "Could not retrieve user's password");
01575 retval = PAM_AUTHTOK_ERR;
01576 goto out;
01577 }
01578
01579
01580
01581 #ifdef DEBUG_PASSWORD
01582 _pam_log_debug(pamh, ctrl, LOG_INFO, "Verify user '%s' with password '%s'",
01583 real_username, password);
01584 #else
01585 _pam_log_debug(pamh, ctrl, LOG_INFO, "Verify user '%s'", real_username);
01586 #endif
01587
01588 member = get_member_from_config(pamh, argc, argv, ctrl, d);
01589
01590 cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d);
01591
01592
01593 retval = winbind_auth_request(pamh, ctrl, username, password, member,
01594 cctype, NULL, NULL, &username_ret);
01595
01596 if (retval == PAM_NEW_AUTHTOK_REQD ||
01597 retval == PAM_AUTHTOK_EXPIRED) {
01598
01599 char *new_authtok_required_during_auth = NULL;
01600
01601 if (!asprintf(&new_authtok_required, "%d", retval)) {
01602 retval = PAM_BUF_ERR;
01603 goto out;
01604 }
01605
01606 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, new_authtok_required, _pam_winbind_cleanup_func);
01607
01608 retval = PAM_SUCCESS;
01609
01610 if (!asprintf(&new_authtok_required_during_auth, "%d", True)) {
01611 retval = PAM_BUF_ERR;
01612 goto out;
01613 }
01614
01615 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
01616 new_authtok_required_during_auth, _pam_winbind_cleanup_func);
01617
01618 goto out;
01619 }
01620
01621 out:
01622 if (username_ret) {
01623 pam_set_item (pamh, PAM_USER, username_ret);
01624 _pam_log_debug(pamh, ctrl, LOG_INFO, "Returned user was '%s'", username_ret);
01625 free(username_ret);
01626 }
01627
01628 if ( real_username ) {
01629 free( real_username );
01630 }
01631
01632 if (d) {
01633 iniparser_freedict(d);
01634 }
01635
01636 if (!new_authtok_required) {
01637 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, NULL, NULL);
01638 }
01639
01640 if (retval != PAM_SUCCESS) {
01641 _pam_free_data_info3(pamh);
01642 }
01643
01644 _PAM_LOG_FUNCTION_LEAVE("pam_sm_authenticate", pamh, ctrl, retval);
01645
01646 return retval;
01647 }
01648
01649 PAM_EXTERN
01650 int pam_sm_setcred(pam_handle_t *pamh, int flags,
01651 int argc, const char **argv)
01652 {
01653 int ret = PAM_SYSTEM_ERR;
01654 dictionary *d = NULL;
01655
01656
01657 int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01658 if (ctrl == -1) {
01659 ret = PAM_SYSTEM_ERR;
01660 goto out;
01661 }
01662
01663 _PAM_LOG_FUNCTION_ENTER("pam_sm_setcred", pamh, ctrl, flags);
01664
01665 switch (flags & ~PAM_SILENT) {
01666
01667 case PAM_DELETE_CRED:
01668 ret = pam_sm_close_session(pamh, flags, argc, argv);
01669 break;
01670 case PAM_REFRESH_CRED:
01671 _pam_log_debug(pamh, ctrl, LOG_WARNING, "PAM_REFRESH_CRED not implemented");
01672 ret = PAM_SUCCESS;
01673 break;
01674 case PAM_REINITIALIZE_CRED:
01675 _pam_log_debug(pamh, ctrl, LOG_WARNING, "PAM_REINITIALIZE_CRED not implemented");
01676 ret = PAM_SUCCESS;
01677 break;
01678 case PAM_ESTABLISH_CRED:
01679 _pam_log_debug(pamh, ctrl, LOG_WARNING, "PAM_ESTABLISH_CRED not implemented");
01680 ret = PAM_SUCCESS;
01681 break;
01682 default:
01683 ret = PAM_SYSTEM_ERR;
01684 break;
01685 }
01686
01687 out:
01688 if (d) {
01689 iniparser_freedict(d);
01690 }
01691
01692 _PAM_LOG_FUNCTION_LEAVE("pam_sm_setcred", pamh, ctrl, ret);
01693
01694 return ret;
01695 }
01696
01697
01698
01699
01700
01701 PAM_EXTERN
01702 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
01703 int argc, const char **argv)
01704 {
01705 const char *username;
01706 int ret = PAM_USER_UNKNOWN;
01707 void *tmp = NULL;
01708 dictionary *d = NULL;
01709
01710
01711 int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01712 if (ctrl == -1) {
01713 return PAM_SYSTEM_ERR;
01714 }
01715
01716 _PAM_LOG_FUNCTION_ENTER("pam_sm_acct_mgmt", pamh, ctrl, flags);
01717
01718
01719
01720 ret = pam_get_user(pamh, &username, NULL);
01721 if ((ret != PAM_SUCCESS) || (!username)) {
01722 _pam_log_debug(pamh, ctrl, LOG_DEBUG,"can not get the username");
01723 ret = PAM_SERVICE_ERR;
01724 goto out;
01725 }
01726
01727
01728 ret = valid_user(pamh, ctrl, username);
01729 switch (ret) {
01730 case -1:
01731
01732 ret = PAM_SERVICE_ERR;
01733 goto out;
01734 case 1:
01735
01736 _pam_log_debug(pamh, ctrl, LOG_NOTICE, "user '%s' not found", username);
01737 if (ctrl & WINBIND_UNKNOWN_OK_ARG) {
01738 ret = PAM_IGNORE;
01739 goto out;
01740 }
01741 ret = PAM_USER_UNKNOWN;
01742 goto out;
01743 case 0:
01744 pam_get_data( pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, (const void **)&tmp);
01745 if (tmp != NULL) {
01746 ret = atoi((const char *)tmp);
01747 switch (ret) {
01748 case PAM_AUTHTOK_EXPIRED:
01749
01750 case PAM_NEW_AUTHTOK_REQD:
01751 _pam_log(pamh, ctrl, LOG_WARNING, "pam_sm_acct_mgmt success but %s is set",
01752 PAM_WINBIND_NEW_AUTHTOK_REQD);
01753 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' needs new password", username);
01754
01755 ret = PAM_NEW_AUTHTOK_REQD;
01756 goto out;
01757 default:
01758 _pam_log(pamh, ctrl, LOG_WARNING, "pam_sm_acct_mgmt success");
01759 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' granted access", username);
01760 ret = PAM_SUCCESS;
01761 goto out;
01762 }
01763 }
01764
01765
01766 _pam_log(pamh, ctrl, LOG_NOTICE, "user '%s' granted access", username);
01767 ret = PAM_SUCCESS;
01768 goto out;
01769 default:
01770
01771 _pam_log(pamh, ctrl, LOG_ERR, "internal module error (ret = %d, user = '%s')",
01772 ret, username);
01773 ret = PAM_SERVICE_ERR;
01774 goto out;
01775 }
01776
01777
01778 ret = PAM_IGNORE;
01779
01780 out:
01781
01782 if (d) {
01783 iniparser_freedict(d);
01784 }
01785
01786 _PAM_LOG_FUNCTION_LEAVE("pam_sm_acct_mgmt", pamh, ctrl, ret);
01787
01788 return ret;
01789 }
01790
01791 PAM_EXTERN
01792 int pam_sm_open_session(pam_handle_t *pamh, int flags,
01793 int argc, const char **argv)
01794 {
01795 int ret = PAM_SYSTEM_ERR;
01796 dictionary *d = NULL;
01797
01798
01799 int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01800 if (ctrl == -1) {
01801 ret = PAM_SYSTEM_ERR;
01802 goto out;
01803 }
01804
01805 _PAM_LOG_FUNCTION_ENTER("pam_sm_open_session", pamh, ctrl, flags);
01806
01807 ret = PAM_SUCCESS;
01808
01809 out:
01810 if (d) {
01811 iniparser_freedict(d);
01812 }
01813
01814 _PAM_LOG_FUNCTION_LEAVE("pam_sm_open_session", pamh, ctrl, ret);
01815
01816 return ret;
01817 }
01818
01819 PAM_EXTERN
01820 int pam_sm_close_session(pam_handle_t *pamh, int flags,
01821 int argc, const char **argv)
01822 {
01823 dictionary *d = NULL;
01824 int retval = PAM_SUCCESS;
01825
01826
01827 int ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01828 if (ctrl == -1) {
01829 retval = PAM_SYSTEM_ERR;
01830 goto out;
01831 }
01832
01833 _PAM_LOG_FUNCTION_ENTER("pam_sm_close_session", pamh, ctrl, flags);
01834
01835 if (!(flags & PAM_DELETE_CRED)) {
01836 retval = PAM_SUCCESS;
01837 goto out;
01838 }
01839
01840 if (ctrl & WINBIND_KRB5_AUTH) {
01841
01842
01843 struct winbindd_request request;
01844 struct winbindd_response response;
01845 const char *user;
01846 const char *ccname = NULL;
01847 struct passwd *pwd = NULL;
01848
01849 ZERO_STRUCT(request);
01850 ZERO_STRUCT(response);
01851
01852 retval = pam_get_user(pamh, &user, "Username: ");
01853 if (retval) {
01854 _pam_log(pamh, ctrl, LOG_ERR, "could not identify user");
01855 goto out;
01856 }
01857
01858 if (user == NULL) {
01859 _pam_log(pamh, ctrl, LOG_ERR, "username was NULL!");
01860 retval = PAM_USER_UNKNOWN;
01861 goto out;
01862 }
01863
01864 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "username [%s] obtained", user);
01865
01866 ccname = pam_getenv(pamh, "KRB5CCNAME");
01867 if (ccname == NULL) {
01868 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "user has no KRB5CCNAME environment");
01869 }
01870
01871 strncpy(request.data.logoff.user, user,
01872 sizeof(request.data.logoff.user) - 1);
01873
01874 if (ccname) {
01875 strncpy(request.data.logoff.krb5ccname, ccname,
01876 sizeof(request.data.logoff.krb5ccname) - 1);
01877 }
01878
01879 pwd = getpwnam(user);
01880 if (pwd == NULL) {
01881 retval = PAM_USER_UNKNOWN;
01882 goto out;
01883 }
01884 request.data.logoff.uid = pwd->pw_uid;
01885
01886 request.flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM;
01887
01888 retval = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_LOGOFF, &request, &response, user);
01889 }
01890
01891 out:
01892 if (d) {
01893 iniparser_freedict(d);
01894 }
01895
01896 _PAM_LOG_FUNCTION_LEAVE("pam_sm_close_session", pamh, ctrl, retval);
01897
01898 return retval;
01899 }
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911 static BOOL _pam_require_krb5_auth_after_chauthtok(pam_handle_t *pamh, int ctrl, const char *user)
01912 {
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925 char *new_authtok_reqd_during_auth = NULL;
01926 struct passwd *pwd = NULL;
01927
01928 _pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, &new_authtok_reqd_during_auth);
01929 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, NULL, NULL);
01930
01931 if (new_authtok_reqd_during_auth) {
01932 return True;
01933 }
01934
01935 pwd = getpwnam(user);
01936 if (!pwd) {
01937 return False;
01938 }
01939
01940 if (getuid() == pwd->pw_uid) {
01941 return True;
01942 }
01943
01944 return False;
01945 }
01946
01947
01948 PAM_EXTERN
01949 int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
01950 int argc, const char **argv)
01951 {
01952 unsigned int lctrl;
01953 int ret;
01954 unsigned int ctrl;
01955 bool cached_login = False;
01956
01957
01958 const char *user;
01959 char *pass_old, *pass_new;
01960
01961
01962 char *Announce;
01963
01964 int retry = 0;
01965 dictionary *d = NULL;
01966 char *username_ret = NULL;
01967 struct winbindd_response response;
01968
01969 ZERO_STRUCT(response);
01970
01971 ctrl = _pam_parse(pamh, flags, argc, argv, &d);
01972 if (ctrl == -1) {
01973 ret = PAM_SYSTEM_ERR;
01974 goto out;
01975 }
01976
01977 _PAM_LOG_FUNCTION_ENTER("pam_sm_chauthtok", pamh, ctrl, flags);
01978
01979 cached_login = (ctrl & WINBIND_CACHED_LOGIN);
01980
01981
01982 ctrl &= ~WINBIND_CACHED_LOGIN;
01983
01984
01985
01986
01987 ret = pam_get_user(pamh, &user, "Username: ");
01988 if (ret) {
01989 _pam_log(pamh, ctrl, LOG_ERR,
01990 "password - could not identify user");
01991 goto out;
01992 }
01993
01994 if (user == NULL) {
01995 _pam_log(pamh, ctrl, LOG_ERR, "username was NULL!");
01996 ret = PAM_USER_UNKNOWN;
01997 goto out;
01998 }
01999
02000 _pam_log_debug(pamh, ctrl, LOG_DEBUG, "username [%s] obtained", user);
02001
02002
02003 ret = valid_user(pamh, ctrl, user);
02004 switch (ret) {
02005 case 1:
02006 ret = PAM_USER_UNKNOWN;
02007 goto out;
02008 case -1:
02009 ret = PAM_SYSTEM_ERR;
02010 goto out;
02011 default:
02012 break;
02013 }
02014
02015
02016
02017
02018
02019
02020 if (flags & PAM_PRELIM_CHECK) {
02021 time_t pwdlastset_prelim = 0;
02022
02023
02024 #define greeting "Changing password for "
02025 Announce = (char *) malloc(sizeof(greeting) + strlen(user));
02026 if (Announce == NULL) {
02027 _pam_log(pamh, ctrl, LOG_CRIT, "password - out of memory");
02028 ret = PAM_BUF_ERR;
02029 goto out;
02030 }
02031 (void) strcpy(Announce, greeting);
02032 (void) strcpy(Announce + sizeof(greeting) - 1, user);
02033 #undef greeting
02034
02035 lctrl = ctrl | WINBIND__OLD_PASSWORD;
02036 ret = _winbind_read_password(pamh, lctrl,
02037 Announce,
02038 "(current) NT password: ",
02039 NULL,
02040 (const char **) &pass_old);
02041 if (ret != PAM_SUCCESS) {
02042 _pam_log(pamh, ctrl, LOG_NOTICE, "password - (old) token not obtained");
02043 goto out;
02044 }
02045
02046
02047
02048 ret = winbind_auth_request(pamh, ctrl, user, pass_old,
02049 NULL, NULL, &response, &pwdlastset_prelim, NULL);
02050
02051 if (ret != PAM_ACCT_EXPIRED &&
02052 ret != PAM_AUTHTOK_EXPIRED &&
02053 ret != PAM_NEW_AUTHTOK_REQD &&
02054 ret != PAM_SUCCESS) {
02055 pass_old = NULL;
02056 goto out;
02057 }
02058
02059 pam_set_data(pamh, PAM_WINBIND_PWD_LAST_SET, (void *)pwdlastset_prelim, NULL);
02060
02061 ret = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
02062 pass_old = NULL;
02063 if (ret != PAM_SUCCESS) {
02064 _pam_log(pamh, ctrl, LOG_CRIT, "failed to set PAM_OLDAUTHTOK");
02065 }
02066 } else if (flags & PAM_UPDATE_AUTHTOK) {
02067
02068 time_t pwdlastset_update = 0;
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078 ret = _pam_get_item(pamh, PAM_OLDAUTHTOK, &pass_old);
02079
02080 if (ret != PAM_SUCCESS) {
02081 _pam_log(pamh, ctrl, LOG_NOTICE, "user not authenticated");
02082 goto out;
02083 }
02084
02085 lctrl = ctrl & ~WINBIND_TRY_FIRST_PASS_ARG;
02086
02087 if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) {
02088 lctrl |= WINBIND_USE_FIRST_PASS_ARG;
02089 }
02090 retry = 0;
02091 ret = PAM_AUTHTOK_ERR;
02092 while ((ret != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
02093
02094
02095
02096
02097
02098 ret = _winbind_read_password(pamh, lctrl,
02099 NULL,
02100 "Enter new NT password: ",
02101 "Retype new NT password: ",
02102 (const char **) &pass_new);
02103
02104 if (ret != PAM_SUCCESS) {
02105 _pam_log_debug(pamh, ctrl, LOG_ALERT
02106 ,"password - new password not obtained");
02107 pass_old = NULL;
02108 goto out;
02109 }
02110
02111
02112
02113
02114
02115
02116
02117 if (pass_new[0] == '\0') {
02118 pass_new = NULL;
02119 }
02120 }
02121
02122
02123
02124
02125
02126 _pam_get_data( pamh, PAM_WINBIND_PWD_LAST_SET,
02127 &pwdlastset_update);
02128
02129
02130
02131
02132
02133
02134 if (cached_login) {
02135 ctrl |= WINBIND_CACHED_LOGIN;
02136 }
02137
02138 ret = winbind_chauthtok_request(pamh, ctrl, user, pass_old, pass_new, pwdlastset_update);
02139 if (ret) {
02140 _pam_overwrite(pass_new);
02141 _pam_overwrite(pass_old);
02142 pass_old = pass_new = NULL;
02143 goto out;
02144 }
02145
02146 if (_pam_require_krb5_auth_after_chauthtok(pamh, ctrl, user)) {
02147
02148 const char *member = get_member_from_config(pamh, argc, argv, ctrl, d);
02149 const char *cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d);
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159 ret = winbind_auth_request(pamh, ctrl, user, pass_new,
02160 member, cctype, &response, NULL, &username_ret);
02161 _pam_overwrite(pass_new);
02162 _pam_overwrite(pass_old);
02163 pass_old = pass_new = NULL;
02164
02165 if (ret == PAM_SUCCESS) {
02166
02167
02168 _pam_warn_password_expiry(pamh, ctrl, &response, NULL);
02169
02170
02171 _pam_set_data_info3(pamh, ctrl, &response);
02172
02173
02174 _pam_setup_krb5_env(pamh, ctrl, response.data.auth.krb5ccname);
02175
02176 if (username_ret) {
02177 pam_set_item (pamh, PAM_USER, username_ret);
02178 _pam_log_debug(pamh, ctrl, LOG_INFO, "Returned user was '%s'", username_ret);
02179 free(username_ret);
02180 }
02181 }
02182
02183 goto out;
02184 }
02185 } else {
02186 ret = PAM_SERVICE_ERR;
02187 }
02188
02189 out:
02190 if (d) {
02191 iniparser_freedict(d);
02192 }
02193
02194
02195 PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_NO_LOGON_SERVERS");
02196 PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND");
02197 PAM_WB_REMARK_CHECK_RESPONSE(pamh, ctrl, response, "NT_STATUS_ACCESS_DENIED");
02198
02199 _PAM_LOG_FUNCTION_LEAVE("pam_sm_chauthtok", pamh, ctrl, ret);
02200
02201 return ret;
02202 }
02203
02204 #ifdef PAM_STATIC
02205
02206
02207
02208 struct pam_module _pam_winbind_modstruct = {
02209 MODULE_NAME,
02210 pam_sm_authenticate,
02211 pam_sm_setcred,
02212 pam_sm_acct_mgmt,
02213 pam_sm_open_session,
02214 pam_sm_close_session,
02215 pam_sm_chauthtok
02216 };
02217
02218 #endif
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261