static ni_status ni_idlist2binding(void *ni, ni_idlist *idlist, krb5_config_section **ret) { int i; ni_status nis; krb5_config_section **next; for (i = 0; i < idlist->ni_idlist_len; i++) { ni_proplist pl; ni_id nid; ni_idlist children; krb5_config_binding *b; ni_index index; nid.nii_instance = 0; nid.nii_object = idlist->ni_idlist_val[i]; nis = ni_read(ni, &nid, &pl); if (nis != NI_OK) { return nis; } index = ni_proplist_match(pl, "name", NULL); b = malloc(sizeof(*b)); if (b == NULL) return NI_FAILED; if (i == 0) { *ret = b; } else { *next = b; } b->type = krb5_config_list; b->name = ni_name_dup(pl.nipl_val[index].nip_val.ninl_val[0]); b->next = NULL; b->u.list = NULL; /* get the child directories */ nis = ni_children(ni, &nid, &children); if (nis == NI_OK) { nis = ni_idlist2binding(ni, &children, &b->u.list); if (nis != NI_OK) { return nis; } } nis = ni_proplist2binding(&pl, b->u.list == NULL ? &b->u.list : &b->u.list->next); ni_proplist_free(&pl); if (nis != NI_OK) { return nis; } next = &b->next; } ni_idlist_free(idlist); return NI_OK; }
void ni_delete_prop(ni_proplist * pl_p, ni_name prop, boolean_t * modified) { int where; where = (int)ni_proplist_match(*pl_p, prop, NULL); if (where != NI_INDEX_NULL) { ni_proplist_delete(pl_p, where); if (modified) *modified = TRUE; } return; }
PLCacheEntry_t * PLCache_lookup_prop(PLCache_t * PLCache, char * prop, char * value, boolean_t make_head) { PLCacheEntry_t * scan; for (scan = PLCache->head; scan; scan = scan->next) { int name_index; name_index = ni_proplist_match(scan->pl, prop, value); if (name_index != NI_INDEX_NULL) { if (make_head) { PLCache_make_head(PLCache, scan); } return (scan); } } return (NULL); }
/* * 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; }
static int is_root_on_master(void *d) { int uid; char myhostname[MAXHOSTNAMELEN + 1]; char *p; ni_index where; ni_proplist pl; int status; ni_id dir; struct sockaddr_in addr; char *tag; uid = getuid(); if (uid != 0) return 0; gethostname(myhostname, MAXHOSTNAMELEN); p = strchr(myhostname, '.'); if (p != NULL) *p = '\0'; status = ni_root(d, &dir); if (status != NI_OK) return 0; status = ni_read(d, &dir, &pl); if (status != NI_OK) return 0; where = ni_proplist_match(pl, "master", NULL); if (where == NI_INDEX_NULL) { ni_proplist_free(&pl); return 0; } if (pl.ni_proplist_val[where].nip_val.ni_namelist_len == 0) { ni_proplist_free(&pl); fprintf(stderr, "No value for NetInfo master property\n"); return 0; } p = strchr(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], '/'); if (p != NULL) *p = '\0'; p = strchr(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], '.'); if (p != NULL) *p = '\0'; if (!strcmp(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], myhostname)) { ni_proplist_free(&pl); return 1; } if (!strcmp(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], "localhost")) { ni_proplist_free(&pl); ni_addrtag(d, &addr, &tag); if (sys_ismyaddress(addr.sin_addr.s_addr)) return 1; } ni_proplist_free(&pl); return 0; }
static int dns_extract_data(char *reply, uint32_t rlen, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen) { XDR xdr; uint32_t n; int32_t test, b64len, status; ni_index where; ni_proplist *pl; char *b64; struct in_addr addr4; struct sockaddr_in sin4; struct in6_addr addr6; struct sockaddr_in6 sin6; if (reply == NULL) return -1; if (rlen == 0) return -1; xdrmem_create(&xdr, reply, rlen, XDR_DECODE); if (!xdr_int(&xdr, &n)) { xdr_destroy(&xdr); return -1; } if (n != 1) { xdr_destroy(&xdr); return -1; } pl = _lookupd_xdr_dictionary(&xdr); xdr_destroy(&xdr); if (pl == NULL) return -1; where = ni_proplist_match(*pl, "buffer", NULL); if (where == NI_INDEX_NULL) { ni_proplist_free(pl); return -1; } if (pl->ni_proplist_val[where].nip_val.ni_namelist_len == 0) { ni_proplist_free(pl); return -1; } b64 = pl->ni_proplist_val[where].nip_val.ni_namelist_val[0]; b64len = strlen(b64); *buf = calloc(1, b64len); test = b64_pton(b64, *buf, b64len); if (test < 0) { free(*buf); ni_proplist_free(pl); return -1; } *len = test; *from = NULL; where = ni_proplist_match(*pl, "server", NULL); if (where == NI_INDEX_NULL) { ni_proplist_free(pl); return 0; } if (pl->ni_proplist_val[where].nip_val.ni_namelist_len == 0) { ni_proplist_free(pl); return 0; } memset(&addr4, 0, sizeof(struct in_addr)); memset(&sin4, 0, sizeof(struct sockaddr_in)); memset(&addr6, 0, sizeof(struct in6_addr)); memset(&sin6, 0, sizeof(struct sockaddr_in6)); status = inet_pton(AF_INET6, pl->ni_proplist_val[where].nip_val.ni_namelist_val[0], &addr6); if (status == 1) { sin6.sin6_addr = addr6; sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); *from = (struct sockaddr *)calloc(1, sin6.sin6_len); memcpy(*from, &sin6, sin6.sin6_len); *fromlen = sin6.sin6_len; return 0; } status = inet_pton(AF_INET, pl->ni_proplist_val[where].nip_val.ni_namelist_val[0], &addr4); if (status == 1) { sin4.sin_addr = addr4; sin4.sin_family = AF_INET; sin4.sin_len = sizeof(struct sockaddr_in); *from = (struct sockaddr *)calloc(1, sin4.sin_len); memcpy(*from, &sin4, sin4.sin_len); *fromlen = sin4.sin_len; return 0; } return -1; }