/* * Get a group entry by name and allocate space for it. */ struct group * sudo_getgrnam(const char *name) { struct cache_item key, *item; struct rbnode *node; size_t len; key.k.name = (char *) name; if ((node = rbfind(grcache_byname, &key)) != NULL) { item = (struct cache_item *) node->data; goto done; } /* * Cache group db entry if it exists or a negative response if not. */ if ((key.d.gr = getgrnam(name)) != NULL) { item = make_gritem(key.d.gr, name); if (rbinsert(grcache_byname, item) != NULL) errorx(1, "unable to cache group %s, already exists", name); } else { len = strlen(name) + 1; item = emalloc(sizeof(*item) + len); item->refcnt = 1; item->k.name = (char *) item + sizeof(*item); memcpy(item->k.name, name, len); item->d.gr = NULL; if (rbinsert(grcache_byname, item) != NULL) errorx(1, "unable to cache group %s, already exists", name); } done: item->refcnt++; return item->d.gr; }
/* * Get a group entry by gid and allocate space for it. */ struct group * sudo_getgrgid(gid_t gid) { struct cache_item key, *item; struct rbnode *node; key.k.gid = gid; if ((node = rbfind(grcache_bygid, &key)) != NULL) { item = (struct cache_item *) node->data; goto done; } /* * Cache group db entry if it exists or a negative response if not. */ if ((key.d.gr = getgrgid(gid)) != NULL) { item = make_gritem(key.d.gr, NULL); if (rbinsert(grcache_bygid, item) != NULL) errorx(1, "unable to cache gid %u (%s), already exists", (unsigned int) gid, key.d.gr->gr_name); } else { item = emalloc(sizeof(*item)); item->refcnt = 1; item->k.gid = gid; item->d.gr = NULL; if (rbinsert(grcache_bygid, item) != NULL) errorx(1, "unable to cache gid %u, already exists", (unsigned int) gid); } done: item->refcnt++; return item->d.gr; }
/* * Take a user, uid and gid and return a faked up passwd struct. */ struct passwd * sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid) { struct cache_item_pw *pwitem; struct passwd *pw; struct rbnode *node; size_t len, namelen; int i; debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS) namelen = strlen(user); len = sizeof(*pwitem) + namelen + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); for (i = 0; i < 2; i++) { pwitem = ecalloc(1, len); pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, namelen + 1); pw->pw_passwd = pw->pw_name + namelen + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, "/", 2); pw->pw_shell = pw->pw_dir + 2; memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); pwitem->cache.refcnt = 1; pwitem->cache.d.pw = pw; if (i == 0) { /* Store by uid, overwriting cached version. */ pwitem->cache.k.uid = pw->pw_uid; if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { sudo_pw_delref_item(node->data); node->data = &pwitem->cache; } } else { /* Store by name, overwriting cached version. */ pwitem->cache.k.name = pw->pw_name; if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { sudo_pw_delref_item(node->data); node->data = &pwitem->cache; } } } pwitem->cache.refcnt++; debug_return_ptr(pw); }
/* * Take a uid in string form "#123" and return a faked up passwd struct. */ struct passwd * sudo_fakepwnam(const char *user, gid_t gid) { struct cache_item *item; struct passwd *pw; struct rbnode *node; size_t len, namelen; int i; namelen = strlen(user); len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); for (i = 0; i < 2; i++) { item = emalloc(len); zero_bytes(item, sizeof(*item) + sizeof(*pw)); pw = (struct passwd *) ((char *)item + sizeof(*item)); pw->pw_uid = (uid_t) atoi(user + 1); pw->pw_gid = gid; pw->pw_name = (char *)pw + sizeof(struct passwd); memcpy(pw->pw_name, user, namelen + 1); pw->pw_passwd = pw->pw_name + namelen + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, "/", 2); pw->pw_shell = pw->pw_dir + 2; memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); item->refcnt = 1; item->d.pw = pw; if (i == 0) { /* Store by uid, overwriting cached version. */ item->k.uid = pw->pw_uid; if ((node = rbinsert(pwcache_byuid, item)) != NULL) { pw_delref_item(node->data); node->data = item; } } else { /* Store by name, overwriting cached version. */ item->k.name = pw->pw_name; if ((node = rbinsert(pwcache_byname, item)) != NULL) { pw_delref_item(node->data); node->data = item; } } } item->refcnt++; return pw; }
/* * Add an alias to the aliases redblack tree. * Note that "file" must be a reference-counted string. * Returns NULL on success and an error string on failure. */ const char * alias_add(char *name, int type, char *file, int lineno, struct member *members) { static char errbuf[512]; struct alias *a; debug_decl(alias_add, SUDOERS_DEBUG_ALIAS) a = calloc(1, sizeof(*a)); if (a == NULL) { strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf)); debug_return_str(errbuf); } a->name = name; a->type = type; /* a->used = false; */ a->file = rcstr_addref(file); a->lineno = lineno; HLTQ_TO_TAILQ(&a->members, members, entries); switch (rbinsert(aliases, a, NULL)) { case 1: snprintf(errbuf, sizeof(errbuf), N_("Alias \"%s\" already defined"), name); alias_free(a); debug_return_str(errbuf); case -1: strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf)); alias_free(a); debug_return_str(errbuf); } debug_return_str(NULL); }
/* * Get a password entry by uid and allocate space for it. */ struct passwd * sudo_getpwuid(uid_t uid) { struct cache_item key, *item; struct rbnode *node; debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS) key.k.uid = uid; if ((node = rbfind(pwcache_byuid, &key)) != NULL) { item = (struct cache_item *) node->data; goto done; } /* * Cache passwd db entry if it exists or a negative response if not. */ #ifdef HAVE_SETAUTHDB aix_setauthdb(IDtouser(uid)); #endif item = sudo_make_pwitem(uid, NULL); if (item == NULL) { item = ecalloc(1, sizeof(*item)); item->refcnt = 1; item->k.uid = uid; /* item->d.pw = NULL; */ } if (rbinsert(pwcache_byuid, item) != NULL) fatalx(_("unable to cache uid %u, already exists"), (unsigned int) uid); #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif done: item->refcnt++; debug_return_ptr(item->d.pw); }
void inserisci_a_caso(rbtree* p){ int x,y; x = BSTGetRootX(adm_positions); y = BSTGetRootY(adm_positions); rbinsert(p,x,y); adm_positions = BSTdelete(adm_positions,x,y); }
/* * Take a gid in string form "#123" and return a faked up group struct. */ struct group * sudo_fakegrnam(const char *group) { struct cache_item *item; struct group *gr; struct rbnode *node; size_t len, namelen; int i; namelen = strlen(group); len = sizeof(*item) + sizeof(*gr) + namelen + 1; for (i = 0; i < 2; i++) { item = emalloc(len); zero_bytes(item, sizeof(*item) + sizeof(*gr)); gr = (struct group *) ((char *)item + sizeof(*item)); gr->gr_gid = (gid_t) atoi(group + 1); gr->gr_name = (char *)gr + sizeof(struct group); memcpy(gr->gr_name, group, namelen + 1); item->refcnt = 1; item->d.gr = gr; if (i == 0) { /* Store by gid, overwriting cached version. */ item->k.gid = gr->gr_gid; if ((node = rbinsert(grcache_bygid, item)) != NULL) { gr_delref_item(node->data); node->data = item; } } else { /* Store by name, overwriting cached version. */ item->k.name = gr->gr_name; if ((node = rbinsert(grcache_byname, item)) != NULL) { gr_delref_item(node->data); node->data = item; } } } item->refcnt++; return gr; }
/* * Get a password entry by name and allocate space for it. */ struct passwd * sudo_getpwnam(const char *name) { struct cache_item key, *item; struct rbnode *node; size_t len; debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS) key.k.name = (char *) name; if ((node = rbfind(pwcache_byname, &key)) != NULL) { item = (struct cache_item *) node->data; goto done; } /* * Cache passwd db entry if it exists or a negative response if not. */ #ifdef HAVE_SETAUTHDB aix_setauthdb((char *) name); #endif if ((key.d.pw = getpwnam(name)) != NULL) { item = make_pwitem(key.d.pw, name); if (rbinsert(pwcache_byname, item) != NULL) errorx(1, _("unable to cache user %s, already exists"), name); } else { len = strlen(name) + 1; item = ecalloc(1, sizeof(*item) + len); item->refcnt = 1; item->k.name = (char *) item + sizeof(*item); memcpy(item->k.name, name, len); /* item->d.pw = NULL; */ if (rbinsert(pwcache_byname, item) != NULL) errorx(1, _("unable to cache user %s, already exists"), name); } #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif done: item->refcnt++; debug_return_ptr(item->d.pw); }
/* * Get a password entry by uid and allocate space for it. * Fills in pw_passwd from shadow file if necessary. */ struct passwd * sudo_getpwuid(uid_t uid) { struct cache_item key, *item; struct rbnode *node; key.k.uid = uid; if ((node = rbfind(pwcache_byuid, &key)) != NULL) { item = (struct cache_item *) node->data; goto done; } /* * Cache passwd db entry if it exists or a negative response if not. */ #ifdef HAVE_SETAUTHDB aix_setauthdb(IDtouser(uid)); #endif if ((key.d.pw = getpwuid(uid)) != NULL) { item = make_pwitem(key.d.pw, NULL); if (rbinsert(pwcache_byuid, item) != NULL) errorx(1, "unable to cache uid %u (%s), already exists", (unsigned int) uid, item->d.pw->pw_name); } else { item = emalloc(sizeof(*item)); item->refcnt = 1; item->k.uid = uid; item->d.pw = NULL; if (rbinsert(pwcache_byuid, item) != NULL) errorx(1, "unable to cache uid %u, already exists", (unsigned int) uid); } #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif done: item->refcnt++; return item->d.pw; }
rbtree* nuovo(){ rbtree* mosaico = createrbtree(); adm_positions = BSTinit(); mosaico->count = 0; mosaico->xdown=0; mosaico->yup=0; mosaico->ydown=0; mosaico->yup=0; mosaico->ordine = 1; adm_positions = BSTinsert( adm_positions, 0, 0 ); rbinsert(mosaico,0,0); mosaico->perimetro = 4; return mosaico; }
/* * Add an alias to the aliases redblack tree. * Returns NULL on success and an error string on failure. */ char * alias_add(char *name, int type, struct member *members) { static char errbuf[512]; struct alias *a; debug_decl(alias_add, SUDO_DEBUG_ALIAS) a = ecalloc(1, sizeof(*a)); a->name = name; a->type = type; /* a->used = false; */ list2tq(&a->members, members); if (rbinsert(aliases, a)) { snprintf(errbuf, sizeof(errbuf), N_("Alias `%s' already defined"), name); alias_free(a); debug_return_str(errbuf); } debug_return_str(NULL); }
void connect_do(void *pri_work, const ip_report_t *r) { char shost_s[32]; union { void *ptr; send_pri_workunit_t *w; uint8_t *inc; } w_u; union { void *ptr; connection_status_t *c; } c_u; union { const uint8_t *packet; const ip_report_t *r; const uint16_t *len; } r_u; struct in_addr ia; uint64_t state_key=0; size_t dlen=0, pk_len=0; uint32_t dhost=0, shost=0; uint16_t sport=0, dport=0; if (r == NULL) { PANIC("r ptr NULL"); } if (state_tbl == NULL) { PANIC("state table null"); } if (pri_work == NULL) { PANIC("pri_work NULL"); } if (r->magic != IP_REPORT_MAGIC) { ERR("wrong magic number for IP report"); return; } state_key=get_connectionkey(r); dhost=r->host_addr; dport=r->sport; sport=r->dport; shost=r->send_addr; if (rbfind(state_tbl, state_key, &c_u.ptr) > 0) { DBG(M_CON, "connection with flags are %s status is %d", strtcpflgs(r->type), c_u.c->status); r_u.r=r; if (r_u.r->doff) { pk_len=r_u.r->doff; r_u.packet += sizeof(ip_report_t); if (*r_u.len != pk_len) { ERR("report is damaged?, packet seems broken"); return; } else { r_u.len++; dlen=try_and_extract_tcp_data(r_u.packet, pk_len, c_u.c); if (dlen > 0) { c_u.c->tseq += dlen; } } } if (c_u.c->m_tstamp == 0 || c_u.c->t_tstamp == 0) { c_u.c->m_tstamp=0; c_u.c->t_tstamp=0; } else { c_u.c->m_tstamp++; /* XXX good enough for testing */ } if (dlen < c_u.c->window) c_u.c->window -= dlen; if (r->type & TH_RST) { c_u.c->status=U_TCP_CLOSE; s->stats.stream_remote_abort++; a_conns--; } switch (c_u.c->status) { case U_TCP_ESTABLISHED: if (r->type & TH_PSH) { w_u.ptr=xmalloc(sizeof(send_pri_workunit_t)); w_u.w->magic=PRI_4SEND_MAGIC; w_u.w->dhost=dhost; w_u.w->dport=dport; w_u.w->sport=sport; w_u.w->shost=c_u.c->send_ip; w_u.w->tseq=c_u.c->tseq; w_u.w->mseq=c_u.c->mseq; w_u.w->window_size=c_u.c->window; w_u.w->flags=TH_ACK|TH_FIN; w_u.w->doff=0; w_u.w->t_tstamp=c_u.c->t_tstamp; w_u.w->m_tstamp=c_u.c->m_tstamp; c_u.c->m_tstamp++; DBG(M_CON, "setting connection state into FIN_WAIT2 and sending ACK|FIN"); c_u.c->status=U_TCP_FIN_WAIT2; fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; c_u.c->mseq++; w_u.ptr=NULL; } else if (r->type & TH_FIN) { c_u.c->tseq += 1; /* FIN eats a seq ;] */ w_u.ptr=xmalloc(sizeof(send_pri_workunit_t)); w_u.w->magic=PRI_4SEND_MAGIC; w_u.w->dhost=dhost; w_u.w->dport=dport; w_u.w->sport=sport; w_u.w->shost=c_u.c->send_ip; w_u.w->tseq=c_u.c->tseq; w_u.w->mseq=c_u.c->mseq; w_u.w->window_size=c_u.c->window; w_u.w->flags=TH_ACK; w_u.w->doff=0; w_u.w->t_tstamp=c_u.c->t_tstamp; w_u.w->m_tstamp=c_u.c->m_tstamp; DBG(M_CON, "acking FIN"); fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; w_u.ptr=xmalloc(sizeof(send_pri_workunit_t)); w_u.w->magic=PRI_4SEND_MAGIC; w_u.w->dhost=dhost; w_u.w->dport=dport; w_u.w->sport=sport; w_u.w->shost=c_u.c->send_ip; w_u.w->tseq=c_u.c->tseq; w_u.w->mseq=c_u.c->mseq; w_u.w->window_size=c_u.c->window; w_u.w->flags=TH_ACK|TH_FIN; w_u.w->doff=0; w_u.w->t_tstamp=c_u.c->t_tstamp; w_u.w->m_tstamp=c_u.c->m_tstamp; c_u.c->m_tstamp++; DBG(M_CON, "setting connection into state closed and sending ACK|FIN"); fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; c_u.c->status=U_TCP_CLOSE; fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; w_u.ptr=NULL; c_u.c->mseq++; a_conns--; } break; /* U_TCP_ESTABLISHED: */ case U_TCP_CLOSE: if (r->type == TH_ACK) { break; } DBG(M_CON, "reseting a packet type %s (no connection entry)", strtcpflgs(r->type)); s->stats.stream_closed_alien_pkt++; w_u.ptr=xmalloc(sizeof(send_pri_workunit_t)); w_u.w->magic=PRI_4SEND_MAGIC; w_u.w->dhost=dhost; w_u.w->dport=dport; w_u.w->sport=sport; w_u.w->shost=c_u.c->send_ip; w_u.w->tseq=c_u.c->tseq; w_u.w->mseq=c_u.c->mseq; w_u.w->window_size=c_u.c->window; w_u.w->flags=TH_RST; w_u.w->doff=0; w_u.w->t_tstamp=c_u.c->t_tstamp; w_u.w->m_tstamp=c_u.c->m_tstamp; c_u.c->m_tstamp++; DBG(M_CON, "reseting packed to closed connection"); fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; w_u.ptr=NULL; break; /* U_TCP_CLOSE */ case U_TCP_FIN_WAIT2: if (r->type & TH_FIN) { /* ok its closed both ways, lets ack the fin and be done with it */ c_u.c->tseq += 1; w_u.ptr=xmalloc(sizeof(send_pri_workunit_t)); w_u.w->magic=PRI_4SEND_MAGIC; w_u.w->dhost=dhost; w_u.w->dport=dport; w_u.w->sport=sport; w_u.w->shost=c_u.c->send_ip; w_u.w->tseq=c_u.c->tseq; w_u.w->mseq=c_u.c->mseq; w_u.w->window_size=c_u.c->window; w_u.w->flags=TH_ACK; w_u.w->doff=0; w_u.w->t_tstamp=c_u.c->t_tstamp; w_u.w->m_tstamp=c_u.c->m_tstamp; c_u.c->m_tstamp++; c_u.c->status=U_TCP_CLOSE; fifo_push(pri_work, w_u.ptr); s->stats.stream_segments_sent++; w_u.ptr=NULL; DBG(M_CON, "Setting connection to closed and acking final fin"); } break; /* U_TCP_FIN_WAIT2 */ # if 0 if (r->type & (TH_ACK|TH_SYN)) { } break; case U_TCP_FIN_WAIT1: case U_TCP_FIN_WAIT2: case U_TCP_CLOSING: case U_TCP_TIME_WAIT: case U_TCP_CLOSE_WAIT: case U_TCP_LAST_ACK: case U_TCP_CLOSE: # endif default: ERR("I have no code. I have no code"); break; } } /* found in state table */ else if ((r->type & (TH_ACK|TH_SYN)) == (TH_ACK|TH_SYN)) { /* should it be in state table */ DBG(M_CON, "Connection with flags %s", strtcpflgs(r->type)); /* yes this is a new connection */ c_u.ptr=xmalloc(sizeof(connection_status_t)); memset(c_u.ptr, 0, sizeof(connection_status_t)); c_u.c->status=U_TCP_ESTABLISHED; c_u.c->send_ip=shost; /* Our IP */ c_u.c->recv_len=0; c_u.c->send_len=0; c_u.c->send_buf=NULL; c_u.c->recv_buf=NULL; c_u.c->recv_stseq=0; c_u.c->tseq=r->tseq; c_u.c->mseq=r->mseq; c_u.c->window=r->window_size; /* XXX wscale */ c_u.c->t_tstamp=r->t_tstamp; c_u.c->m_tstamp=r->m_tstamp; c_u.c->ack_pending=1; if (GET_IMMEDIATE()) { ia.s_addr=shost; snprintf(shost_s, sizeof(shost_s) -1, "%s", inet_ntoa(ia)); ia.s_addr=dhost; VRB(0, "connected %s:%u -> %s:%u", shost_s, sport, inet_ntoa(ia), dport); } s->stats.stream_connections_est++; rbinsert(state_tbl, state_key, c_u.ptr); a_conns++; send_connect(state_key, c_u.c, pri_work, r); } /* looks like something we want to connect to ;] */ else { s->stats.stream_completely_alien_packet++; DBG(M_CON, "ignoring packet with flags %s", strtcpflgs(r->type)); } return; }
/* * Take a user, uid, gid, home and shell and return a faked up passwd struct. * If home or shell are NULL default values will be used. */ struct passwd * sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home, const char *shell) { struct cache_item_pw *pwitem; struct passwd *pw; struct rbnode *node; size_t len, name_len, home_len, shell_len; int i; debug_decl(sudo_mkpwent, SUDO_DEBUG_NSS) /* Optional arguments. */ if (home == NULL) home = "/"; if (shell == NULL) shell = _PATH_BSHELL; name_len = strlen(user); home_len = strlen(home); shell_len = strlen(shell); len = sizeof(*pwitem) + name_len + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */; for (i = 0; i < 2; i++) { pwitem = ecalloc(1, len); pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, name_len + 1); pw->pw_passwd = pw->pw_name + name_len + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, home, home_len + 1); pw->pw_shell = pw->pw_dir + home_len + 1; memcpy(pw->pw_shell, shell, shell_len + 1); pwitem->cache.refcnt = 1; pwitem->cache.d.pw = pw; if (i == 0) { /* Store by uid if it doesn't already exist. */ pwitem->cache.k.uid = pw->pw_uid; if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { /* Already exists, free the item we created. */ efree(pwitem); pwitem = (struct cache_item_pw *) node->data; } } else { /* Store by name if it doesn't already exist. */ pwitem->cache.k.name = pw->pw_name; if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { /* Already exists, free the item we created. */ efree(pwitem); pwitem = (struct cache_item_pw *) node->data; } } } pwitem->cache.refcnt++; debug_return_ptr(&pwitem->pw); }
/* * Take a user, uid, gid, home and shell and return a faked up passwd struct. * If home or shell are NULL default values will be used. */ struct passwd * sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home, const char *shell) { struct cache_item_pw *pwitem; struct cache_item *item; struct passwd *pw; size_t len, name_len, home_len, shell_len; int i; debug_decl(sudo_mkpwent, SUDOERS_DEBUG_NSS) /* Optional arguments. */ if (home == NULL) home = "/"; if (shell == NULL) shell = _PATH_BSHELL; name_len = strlen(user); home_len = strlen(home); shell_len = strlen(shell); len = sizeof(*pwitem) + name_len + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */; for (i = 0; i < 2; i++) { struct rbtree *pwcache; struct rbnode *node; pwitem = sudo_ecalloc(1, len); pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, name_len + 1); pw->pw_passwd = pw->pw_name + name_len + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, home, home_len + 1); pw->pw_shell = pw->pw_dir + home_len + 1; memcpy(pw->pw_shell, shell, shell_len + 1); item = &pwitem->cache; item->refcnt = 1; item->d.pw = pw; if (i == 0) { /* Store by uid if it doesn't already exist. */ item->k.uid = pw->pw_uid; pwcache = pwcache_byuid; } else { /* Store by name if it doesn't already exist. */ item->k.name = pw->pw_name; pwcache = pwcache_byname; } if ((node = rbinsert(pwcache, item)) != NULL) { /* Already exists. */ item = node->data; if (item->d.pw == NULL) { /* Negative cache entry, replace with ours. */ sudo_pw_delref_item(item); item = node->data = &pwitem->cache; } else { /* Good entry, discard our fake one. */ sudo_efree(pwitem); } } } item->refcnt++; debug_return_ptr(item->d.pw); }