static int password_lifetime() { void *d, *d1; int status; ni_id dir; ni_namelist nl; status = ni_open(NULL, ".", &d); while (status == NI_OK) { status = ni_pathsearch(d, &dir, "/users"); if (status == NI_OK) { status = ni_lookupprop(d, &dir, "password_lifetime", &nl); if (status == NI_OK) { if (nl.ni_namelist_val[0] != NULL) { ni_free(d); /* free namelist? */ return atoi(nl.ni_namelist_val[0]); } } } d1 = d; status = ni_open(d1, "..", &d); ni_free(d1); } return -1; }
int NetInfoPrefsSource::GetValueByIndex(const char* inKey, UInt32 inIndex, char* ioValue) { ni_status status = NI_OK; ni_namelist nameList = {}; void* localDomain = NULL; ni_id qtssDir = {}; ioValue[0] = '\0'; status = ni_open(NULL, ".", &localDomain); if (status != NI_OK) return false; if (status == NI_OK) status = ni_pathsearch(localDomain, &qtssDir, gQTSSPropertiesPath); if (status == NI_OK) status = ni_lookupprop(localDomain, &qtssDir, inKey, &nameList); if (status == NI_OK) { if (nameList.ni_namelist_len > inIndex) strcpy(ioValue, nameList.ni_namelist_val[inIndex]); else status = NI_BADID; ni_namelist_free(&nameList); } ni_free(localDomain); return (status == NI_OK); }
static int secure_passwords() { void *d, *d1; int status; ni_index where; ni_id dir; ni_namelist nl; status = ni_open(NULL, ".", &d); while (status == NI_OK) { dir.nii_object = 0; status = ni_lookupprop(d, &dir, "security_options", &nl); if (status == NI_OK) { where = ni_namelist_match(nl, "secure_passwords"); if (where != NI_INDEX_NULL) { ni_free(d); return 1; } } d1 = d; status = ni_open(d1, "..", &d); ni_free(d1); } return 0; }
ni_status ni2_lookupprop(void *domain, char *pathname, const ni_name key, ni_namelist *values) { /* read a property */ ni_status ret; ni_id dir; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni_lookupprop(domain, &dir, key, values); }
/* * Change a user's password in NetInfo. */ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) { char *oldHash, *newHash; char *oldPassword = NULL, *newPassword = NULL; void *d; int status, isroot, tries, maxTries; int options = 0; int amChangingExpiredPassword; ni_id dir; ni_proplist pl; ni_property p; ni_namelist nl; int ni_uid, uid, secure, minlen, lifetime; ni_index where; struct pam_conv *appconv; struct pam_message msg, *pmsg; struct pam_response *resp; const char *cmiscptr = NULL; char *uname; char salt[9]; int i; amChangingExpiredPassword = flags & PAM_CHANGE_EXPIRED_AUTHTOK; status = pam_get_item(pamh, PAM_CONV, (void **) &appconv); if (status != PAM_SUCCESS) return status; status = pam_get_item(pamh, PAM_USER, (void **) &uname); if (status != PAM_SUCCESS) return status; if (uname == NULL) return PAM_USER_UNKNOWN; status = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **) &oldPassword); if (status != PAM_SUCCESS) { return status; } if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) || pam_test_option(&options, PAM_OPT_TRY_FIRST_PASS, NULL)) { if (pam_get_item(pamh, PAM_AUTHTOK, (void **) &newPassword) != PAM_SUCCESS) newPassword = NULL; if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) && newPassword == NULL) return PAM_AUTHTOK_RECOVER_ERR; } d = domain_for_user(uname, NULL, &dir); if (d == (void *) NULL) { syslog(LOG_ERR, "user %s not found in NetInfo", uname); return PAM_USER_UNKNOWN; } /* * These should be configurable in NetInfo. */ secure = secure_passwords(); maxTries = secure ? 3 : 5; minlen = secure ? 8 : 5; /* * Read the passwd and uid from NetInfo. */ status = ni_lookupprop(d, &dir, "passwd", &nl); if (status == NI_NOPROP) nl.ni_namelist_len = 0; else if (status != NI_OK) { ni_free(d); syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status)); return netinfo2PamStatus(status); } oldHash = NULL; if (nl.ni_namelist_len > 0) oldHash = nl.ni_namelist_val[0]; status = ni_lookupprop(d, &dir, "uid", &nl); if (status != NI_OK) { ni_free(d); syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status)); return netinfo2PamStatus(status); } ni_uid = -2; if (nl.ni_namelist_len > 0) ni_uid = atoi(nl.ni_namelist_val[0]); /* * See if I'm uid 0 on the master host for the user's NetInfo domain. */ isroot = is_root_on_master(d); uid = getuid(); if (isroot) { if (flags & PAM_PRELIM_CHECK) { /* Don't need old password. */ return PAM_SUCCESS; } } else if (uid != ni_uid) { ni_free(d); return PAM_PERM_DENIED; } if (flags & PAM_PRELIM_CHECK) { /* * If we are not root, we should verify the old * password. */ char *encrypted; if (oldPassword != NULL && (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) || pam_test_option(&options, PAM_OPT_TRY_FIRST_PASS, NULL))) { encrypted = crypt(oldPassword, oldHash); if (oldPassword[0] == '\0' && oldHash != '\0') encrypted = ":"; status = strcmp(encrypted, oldHash) == 0 ? PAM_SUCCESS : PAM_AUTH_ERR; if (status != PAM_SUCCESS) { if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL)) sendConversationMessage(appconv, "NetInfo password incorrect", PAM_ERROR_MSG, &options); else sendConversationMessage(appconv, "NetInfo password incorrect: try again", PAM_ERROR_MSG, &options); } else { ni_free(d); return PAM_SUCCESS; } } tries = 0; while (oldPassword == NULL && tries++ < maxTries) { pmsg = &msg; msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = OLD_PASSWORD_PROMPT; resp = NULL; status = appconv->conv(1, (struct pam_message **) & pmsg, &resp, appconv->appdata_ptr); if (status != PAM_SUCCESS) { ni_free(d); return status; } oldPassword = resp->resp; free(resp); encrypted = crypt(oldPassword, oldHash); if (oldPassword[0] == '\0' && oldHash != '\0') encrypted = ":"; status = strcmp(encrypted, oldHash) == 0 ? PAM_SUCCESS : PAM_AUTH_ERR; if (status != PAM_SUCCESS) { int abortMe = 0; if (oldPassword != NULL && oldPassword[0] == '\0') abortMe = 1; _pam_overwrite(oldPassword); _pam_drop(oldPassword); if (!amChangingExpiredPassword & abortMe) { sendConversationMessage(appconv, "Password change aborted", PAM_ERROR_MSG, &options); ni_free(d); return PAM_AUTHTOK_RECOVER_ERR; } else { sendConversationMessage(appconv, "NetInfo password incorrect: try again", PAM_ERROR_MSG, &options); } } } if (oldPassword == NULL) { status = PAM_MAXTRIES; } (void) pam_set_item(pamh, PAM_OLDAUTHTOK, oldPassword); ni_free(d); return status; } /* PAM_PRELIM_CHECK */ status = PAM_ABORT; tries = 0; while (newPassword == NULL && tries++ < maxTries) { pmsg = &msg; msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = NEW_PASSWORD_PROMPT; resp = NULL; status = appconv->conv(1, &pmsg, &resp, appconv->appdata_ptr); if (status != PAM_SUCCESS) { ni_free(d); return status; } newPassword = resp->resp; free(resp); if (newPassword[0] == '\0') { free(newPassword); newPassword = NULL; } if (newPassword != NULL) { if (isroot == 0) { if (oldPassword != NULL && !strcmp(oldPassword, newPassword)) { cmiscptr = "Passwords must differ"; newPassword = NULL; } else if (strlen(newPassword) < minlen) { cmiscptr = "Password too short"; newPassword = NULL; } } } else { ni_free(d); return PAM_AUTHTOK_RECOVER_ERR; } if (cmiscptr == NULL) { /* get password again */ char *miscptr; pmsg = &msg; msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = AGAIN_PASSWORD_PROMPT; resp = NULL; status = appconv->conv(1, &pmsg, &resp, appconv->appdata_ptr); if (status != PAM_SUCCESS) { ni_free(d); return status; } miscptr = resp->resp; free(resp); if (miscptr[0] == '\0') { free(miscptr); miscptr = NULL; } if (miscptr == NULL) { if (!amChangingExpiredPassword) { sendConversationMessage(appconv, "Password change aborted", PAM_ERROR_MSG, &options); ni_free(d); return PAM_AUTHTOK_RECOVER_ERR; } } else if (!strcmp(newPassword, miscptr)) { miscptr = NULL; break; } sendConversationMessage(appconv, "You must enter the same password", PAM_ERROR_MSG, &options); miscptr = NULL; newPassword = NULL; } else { sendConversationMessage(appconv, cmiscptr, PAM_ERROR_MSG, &options); cmiscptr = NULL; newPassword = NULL; } } if (cmiscptr != NULL || newPassword == NULL) { ni_free(d); return PAM_MAXTRIES; } /* * Lock onto the master server. */ ni_needwrite(d, 1); /* * Authenticate if necessary */ if (isroot == 0) { ni_setuser(d, uname); ni_setpassword(d, oldPassword); } /* * Create a random salt */ srandom((int) time((time_t *) NULL)); salt[0] = saltchars[random() % strlen(saltchars)]; salt[1] = saltchars[random() % strlen(saltchars)]; salt[2] = '\0'; newHash = crypt(newPassword, salt); /* * Change the password in NetInfo. */ status = ni_read(d, &dir, &pl); if (status != NI_OK) { ni_free(d); syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status)); return netinfo2PamStatus(status); } p.nip_name = "passwd"; p.nip_val.ni_namelist_len = 1; p.nip_val.ni_namelist_val = (ni_name *) malloc(sizeof(ni_name)); p.nip_val.ni_namelist_val[0] = newHash; where = ni_proplist_match(pl, p.nip_name, NULL); if (where == NI_INDEX_NULL) status = ni_createprop(d, &dir, p, NI_INDEX_NULL); else status = ni_writeprop(d, &dir, where, p.nip_val); if (status != NI_OK) { ni_free(d); syslog(LOG_ERR, "NetInfo write property \"passwd\" failed: %s", ni_error(status)); return netinfo2PamStatus(status); } /* * Now, update "change" property. If this fails, we've still * updated the password... perhaps the user should be alerted * of this. */ lifetime = password_lifetime(); if (lifetime > 0) { struct timeval tp; char change[64]; where = ni_proplist_match(pl, "change", NULL); gettimeofday(&tp, NULL); tp.tv_sec += lifetime; snprintf(change, sizeof(change), "%ld", tp.tv_sec); p.nip_name = "change"; p.nip_val.ni_namelist_len = 1; p.nip_val.ni_namelist_val[0] = change; if (where == NI_INDEX_NULL) status = ni_createprop(d, &dir, p, NI_INDEX_NULL); else status = ni_writeprop(d, &dir, where, p.nip_val); if (status != NI_OK) { ni_free(d); syslog(LOG_ERR, "NetInfo write property \"change\" failed: %s", ni_error(status)); return netinfo2PamStatus(status); } } free(p.nip_val.ni_namelist_val); ni_free(d); /* tell lookupd to invalidate its cache */ { int i, proc = -1; unit lookup_buf[MAX_INLINE_UNITS]; #ifdef __NeXT__ port_t port; #else mach_port_t port; #endif port = _lookupd_port(0); (void) _lookup_link(port, "_invalidatecache", &proc); (void) _lookup_one(port, proc, NULL, 0, lookup_buf, &i); } return PAM_SUCCESS; }