/** Remove \a cptr from lists that it is a member of. * Specifically, this delinks \a cptr from #GlobalClientList, updates * the whowas history list, frees its Client::cli_user and * Client::cli_serv fields, and finally calls free_client() on it. * @param[in] cptr Client to remove from lists and free. */ void remove_client_from_list(struct Client *cptr) { assert(cli_verify(cptr)); assert(con_verify(cli_connect(cptr))); assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr))); assert(!cli_next(cptr) || cli_verify(cli_next(cptr))); assert(!IsMe(cptr)); /* Only try remove cptr from the list if it IS in the list. * cli_next(cptr) cannot be NULL here, as &me is always the end * the list, and we never remove &me. -GW */ if(cli_next(cptr)) { if (cli_prev(cptr)) cli_next(cli_prev(cptr)) = cli_next(cptr); else { GlobalClientList = cli_next(cptr); cli_prev(GlobalClientList) = 0; } cli_prev(cli_next(cptr)) = cli_prev(cptr); } cli_next(cptr) = cli_prev(cptr) = 0; if (IsUser(cptr) && cli_user(cptr)) { add_history(cptr, 0); off_history(cptr); } if (cli_user(cptr)) { free_user(cli_user(cptr)); cli_user(cptr) = 0; } if (cli_serv(cptr)) { if (cli_serv(cptr)->user) { free_user(cli_serv(cptr)->user); cli_serv(cptr)->user = 0; } if (cli_serv(cptr)->client_list) MyFree(cli_serv(cptr)->client_list); MyFree(cli_serv(cptr)->last_error_msg); MyFree(cli_serv(cptr)); --servs.inuse; --servs.alloc; } free_client(cptr); }
/** Try to send a buffer to a client, queueing it if needed. * @param[in,out] to Client to send message to. * @param[in] buf Message to send. * @param[in] prio If non-zero, send as high priority. */ void send_buffer(struct Client* to, struct MsgBuf* buf, int prio) { assert(0 != to); assert(0 != buf); if (cli_from(to)) to = cli_from(to); if (!can_send(to)) /* * This socket has already been marked as dead */ return; if (MsgQLength(&(cli_sendQ(to))) > get_sendq(to)) { if (IsServer(to)) sendto_opmask_butone(0, SNO_OLDSNO, "Max SendQ limit exceeded for %C: " "%zu > %zu", to, MsgQLength(&(cli_sendQ(to))), get_sendq(to)); dead_link(to, "Max sendQ exceeded"); return; } Debug((DEBUG_SEND, "Sending [%p] to %s", buf, cli_name(to))); msgq_add(&(cli_sendQ(to)), buf, prio); client_add_sendq(cli_connect(to), &send_queues); update_write(to); /* * Update statistics. The following is slightly incorrect * because it counts messages even if queued, but bytes * only really sent. Queued bytes get updated in SendQueued. */ ++(cli_sendM(to)); ++(cli_sendM(&me)); /* * This little bit is to stop the sendQ from growing too large when * there is no need for it to. Thus we call send_queued() every time * 2k has been added to the queue since the last non-fatal write. * Also stops us from deliberately building a large sendQ and then * trying to flood that link with data (possible during the net * relinking done by servers with a large load). */ if (MsgQLength(&(cli_sendQ(to))) / 1024 > cli_lastsq(to)) send_queued(to); }
int main(int argc, char *argv[]) { do_init(); cli_cont = new iocont; int iRet; iRet = cli_connect("127.0.0.1",9000); if(iRet!=0) { return 1; } daemon_init(); while(1) { check(); usleep(100); do_poll(); } }
/** Mark a client as dead, even if they are not the current message source. * This is done by setting the DEADSOCKET flag on the user and letting the * main loop perform the actual exit logic. * @param[in,out] to Client being killed. * @param[in] notice Message for local opers. */ static void dead_link(struct Client *to, char *notice) { SetFlag(to, FLAG_DEADSOCKET); /* * If because of BUFFERPOOL problem then clean dbuf's now so that * notices don't hurt operators below. */ DBufClear(&(cli_recvQ(to))); MsgQClear(&(cli_sendQ(to))); client_drop_sendq(cli_connect(to)); /* * Keep a copy of the last comment, for later use... */ ircd_strncpy(cli_info(to), notice, REALLEN); if (!IsUser(to) && !IsUnknown(to) && !HasFlag(to, FLAG_CLOSING)) sendto_opmask_butone(0, SNO_OLDSNO, "%s for %s", cli_info(to), cli_name(to)); Debug((DEBUG_ERROR, cli_info(to))); }
int main(void) { int sd, ret, i; struct sockaddr_in srv; socklen_t len = sizeof(srv); sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ERRP(sd == -1, goto ERR1, 2, "socket"); srv.sin_family = AF_INET; srv.sin_port = htons(9999); srv.sin_addr.s_addr = 0; ret = bind(sd, (struct sockaddr *)&srv, len); ERRP(ret == -1, goto ERR2, 2, "bind"); ret = listen(sd, 20); ERRP(ret == -1, goto ERR2, 2, "listen"); for (i = 0; i < 5; i++) { if (fork() == 0) { cli_connect(sd); exit(0); } } getchar(); kill(0, SIGKILL); ERR2: close(sd); ERR1: return 0; }
/***************************************************** return a connection to a server (existing or new) *******************************************************/ struct smbw_server *smbw_server(char *server, char *share) { struct smbw_server *srv=NULL; struct cli_state c; char *username; char *password; char *workgroup; struct nmb_name called, calling; char *p, *server_n = server; fstring group; pstring ipenv; struct in_addr ip; zero_ip(&ip); ZERO_STRUCT(c); get_auth_data_fn(server, share, &workgroup, &username, &password); /* try to use an existing connection */ for (srv=smbw_srvs;srv;srv=srv->next) { if (strcmp(server,srv->server_name)==0 && strcmp(share,srv->share_name)==0 && strcmp(workgroup,srv->workgroup)==0 && strcmp(username, srv->username) == 0) return srv; } if (server[0] == 0) { errno = EPERM; return NULL; } make_nmb_name(&calling, global_myname, 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); if ((p=strchr(server_n,'#')) && (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { struct in_addr sip; pstring s; fstrcpy(group, server_n); p = strchr(group,'#'); *p = 0; /* cache the workgroup master lookup */ slprintf(s,sizeof(s)-1,"MASTER_%s", group); if (!(server_n = smbw_getshared(s))) { if (!find_master_ip(group, &sip)) { errno = ENOENT; return NULL; } fstrcpy(group, inet_ntoa(sip)); server_n = group; smbw_setshared(s,server_n); } } DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); zero_ip(&ip); if ((p=smbw_getshared(ipenv))) { ip = *(interpret_addr2(p)); } /* have to open a new connection */ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) { errno = ENOENT; return NULL; } if (!cli_session_request(&c, &calling, &called)) { cli_shutdown(&c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } errno = ENOENT; return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(&c)) { cli_shutdown(&c); errno = ENOENT; return NULL; } if (!cli_session_setup(&c, username, password, strlen(password), password, strlen(password), workgroup) && /* try an anonymous login if it failed */ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) { cli_shutdown(&c); errno = EPERM; return NULL; } DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(&c, share, "?????", password, strlen(password)+1)) { errno = smbw_errno(&c); cli_shutdown(&c); return NULL; } smbw_setshared(ipenv,inet_ntoa(ip)); DEBUG(4,(" tconx ok\n")); srv = (struct smbw_server *)malloc(sizeof(*srv)); if (!srv) { errno = ENOMEM; goto failed; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->server_name = strdup(server); if (!srv->server_name) { errno = ENOMEM; goto failed; } srv->share_name = strdup(share); if (!srv->share_name) { errno = ENOMEM; goto failed; } srv->workgroup = strdup(workgroup); if (!srv->workgroup) { errno = ENOMEM; goto failed; } srv->username = strdup(username); if (!srv->username) { errno = ENOMEM; goto failed; } /* some programs play with file descriptors fairly intimately. We try to get out of the way by duping to a high fd number */ if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) { if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == srv->cli.fd+SMBW_CLI_FD) { close(srv->cli.fd); srv->cli.fd += SMBW_CLI_FD; } } DLIST_ADD(smbw_srvs, srv); return srv; failed: cli_shutdown(&c); if (!srv) return NULL; SAFE_FREE(srv->server_name); SAFE_FREE(srv->share_name); SAFE_FREE(srv); return NULL; }
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr) { struct in_addr ip; struct sockaddr_storage ss; struct nmb_name called, calling; pstring myname; pstring message; pstring shortfilename; char* lastslash; static pstring lastfile; static pstring lastip; #if SAMBA_VERSION_MAJOR==3 fstrcpy(remote_machine, get_remote_machine_name()); DEBUG(5, ("remote machine is: %s\n", remote_machine)); #endif /* Only notify once for a given virus/ip combo - otherwise the * scanner will go crazy reaccessing the file and sending * messages once the user hits the "okay" button */ if (strncmp(lastfile,filename,sizeof(pstring)) == 0) { if (strncmp(lastip,ipaddr,sizeof(pstring)) == 0) { DEBUG(5,("Both IP and Filename are the same, not notifying\n")); return 0; } } ZERO_ARRAY(lastfile); ZERO_ARRAY(lastip); pstrcpy(lastfile,filename); pstrcpy(lastip,ipaddr); ZERO_ARRAY(myname); pstrcpy(myname,myhostname()); ZERO_ARRAY(username); /* could make this configurable */ snprintf(username,sizeof(pstring)-1,"%s VIRUS SCANNER",myname); /* We need to get the real ip structure from the ip string * is this info already available somewhere else in samba? */ zero_ip_v4(&ip); if (inet_aton(ipaddr,&ip) == 0) { DEBUG(5,("Cannot resolve ip address %s\n", ipaddr)); return 1; } in_addr_to_sockaddr_storage(&ss, ip); make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , remote_machine, name_type); if (!(cli=cli_initialise())) { DEBUG(5,("Connection to %s failed\n", remote_machine)); return 1; } cli_set_port(cli, port); if (!NT_STATUS_IS_OK(cli_connect(cli, remote_machine, &ss))) { DEBUG(5,("Connection to %s failed\n", remote_machine)); return 1; } if (!cli_session_request(cli, &calling, &called)) { DEBUG(5,("session request failed\n")); cli_shutdown(cli); return 1; } ZERO_ARRAY(shortfilename); /* we don't want the entire filename, otherwise the message service may choke * so we chop off the path up to the very last forward-slash * assumption: unix-style pathnames in filename (don't know if there's a * portable file-separator variable... */ lastslash = strrchr(filename,'/'); if (lastslash != NULL && lastslash != filename) { pstrcpy(shortfilename,lastslash+1); } else { pstrcpy(shortfilename,filename); } ZERO_ARRAY(message); /* could make the message configurable and language specific? */ snprintf(message,sizeof(pstring)-1, "%s IS INFECTED WITH VIRUS %s.\r\n\r\nAccess will be denied.\r\nPlease contact your system administrator", shortfilename, virname); /* actually send the message... */ send_message(message); cli_shutdown(cli); return 0; }
/** Creates a client which has just connected to us on the given fd. * The sockhost field is initialized with the ip# of the host. * The client is not added to the linked list of clients, it is * passed off to the auth handler for dns and ident queries. * @param listener Listening socket that received the connection. * @param fd File descriptor of new connection. */ void add_connection(struct Listener* listener, int fd) { struct irc_sockaddr addr; struct Client *new_client; time_t next_target = 0; const char* const throttle_message = "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n"; /* 12345678901234567890123456789012345679012345678901234567890123456 */ const char* const register_message = "ERROR :Unable to complete your registration\r\n"; assert(0 != listener); /* * Removed preliminary access check. Full check is performed in m_server and * m_user instead. Also connection time out help to get rid of unwanted * connections. */ if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) { ++ServerStats->is_ref; close(fd); return; } /* * Disable IP (*not* TCP) options. In particular, this makes it impossible * to use source routing to connect to the server. If we didn't do this * (and if intermediate networks didn't drop source-routed packets), an * attacker could successfully IP spoof us...and even return the anti-spoof * ping, because the options would cause the packet to be routed back to * the spoofer's machine. When we disable the IP options, we delete the * source route, and the normal routing takes over. */ os_disable_options(fd); if (listener_server(listener)) { new_client = make_client(0, STAT_UNKNOWN_SERVER); } else { /* * Add this local client to the IPcheck registry. * * If they're throttled, murder them, but tell them why first. */ if (!IPcheck_local_connect(&addr.addr, &next_target)) { ++ServerStats->is_ref; write(fd, throttle_message, strlen(throttle_message)); close(fd); return; } new_client = make_client(0, STAT_UNKNOWN_USER); SetIPChecked(new_client); } /* * Copy ascii address to 'sockhost' just in case. Then we have something * valid to put into error messages... */ ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr); strcpy(cli_sockhost(new_client), cli_sock_ip(new_client)); memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client))); if (next_target) cli_nexttarget(new_client) = next_target; cli_fd(new_client) = fd; if (!socket_add(&(cli_socket(new_client)), client_sock_callback, (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) { ++ServerStats->is_ref; write(fd, register_message, strlen(register_message)); close(fd); cli_fd(new_client) = -1; return; } cli_freeflag(new_client) |= FREEFLAG_SOCKET; cli_listener(new_client) = listener; ++listener->ref_count; Count_newunknown(UserStats); /* if we've made it this far we can put the client on the auth query pile */ start_auth(new_client); }
/**************************************************************************** establishes a connection right up to doing tconX, reading in a password. ****************************************************************************/ BOOL cli_establish_connection(struct cli_state *cli, char *dest_host, struct in_addr *dest_ip, struct nmb_name *calling, struct nmb_name *called, char *service, char *service_type, BOOL do_shutdown, BOOL do_tcon) { cli->dbg(5, "cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n", nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip), cli->user_name, cli->domain); /* establish connection */ if ((!cli->initialised)) { return False; } if (!cli_connect(cli, dest_host, dest_ip)) { cli->dbg(1, "cli_establish_connection: failed to connect to %s (%s)\n", nmb_namestr(calling), inet_ntoa(*dest_ip)); return False; } if (!cli_session_request(cli, calling, called)) { cli->dbg(1, "failed session request\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (!cli_negprot(cli)) { cli->dbg(1, "failed negprot\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (cli->pwd.cleartext || cli->pwd.null_pwd) { fstring passwd; int pass_len; if (cli->pwd.null_pwd) { /* attempt null session */ passwd[0] = 0; pass_len = 1; } else { /* attempt clear-text session */ pwd_get_cleartext(&(cli->pwd), passwd); pass_len = strlen(passwd); } /* attempt clear-text session */ if (!cli_session_setup(cli, cli->user_name, passwd, pass_len, NULL, 0, cli->domain)) { cli->dbg(1, "failed session setup\n"); if (do_shutdown) { cli_shutdown(cli); } return False; } if (do_tcon) { if (!cli_send_tconX(cli, service, service_type, (char *)passwd, strlen(passwd))) { cli->dbg(1, "failed tcon_X\n"); if (do_shutdown) { cli_shutdown(cli); } return False; } } } else { /* attempt encrypted session */ unsigned char nt_sess_pwd[24]; unsigned char lm_sess_pwd[24]; /* creates (storing a copy of) and then obtains a 24 byte password OWF */ pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey); pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd); /* attempt encrypted session */ if (!cli_session_setup(cli, cli->user_name, (char *)lm_sess_pwd, sizeof(lm_sess_pwd), (char *)nt_sess_pwd, sizeof(nt_sess_pwd), cli->domain)) { cli->dbg(1, "failed session setup\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (do_tcon) { if (!cli_send_tconX(cli, service, service_type, (char *)nt_sess_pwd, sizeof(nt_sess_pwd))) { cli->dbg(1, "failed tcon_X\n"); if (do_shutdown) cli_shutdown(cli); return False; } } } if (do_shutdown) cli_shutdown(cli); return True; }
/** Read a 'packet' of data from a connection and process it. Read in * 8k chunks to give a better performance rating (for server * connections). Do some tricky stuff for client connections to make * sure they don't do any flooding >:-) -avalon * @param cptr Client from which to read data. * @param socket_ready If non-zero, more data can be read from the client's socket. * @return Positive number on success, zero on connection-fatal failure, negative * if user is killed. */ static int read_packet(struct Client *cptr, int socket_ready) { unsigned int dolen = 0; unsigned int length = 0; if (socket_ready && !(IsUser(cptr) && !IsOper(cptr) && DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))) { switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) { case IO_SUCCESS: if (length) { cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); ClrFlag(cptr, FLAG_NONL); if (cli_lasttime(cptr) > cli_since(cptr)) cli_since(cptr) = cli_lasttime(cptr); } break; case IO_BLOCKED: break; case IO_FAILURE: cli_error(cptr) = errno; /* SetFlag(cptr, FLAG_DEADSOCKET); */ return 0; } } /* * For server connections, we process as many as we can without * worrying about the time of day or anything :) */ if (length > 0 && IsServer(cptr)) return server_dopacket(cptr, readbuf, length); else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr))) return connect_dopacket(cptr, readbuf, length); else { /* * Before we even think of parsing what we just read, stick * it on the end of the receive queue and do it when its * turn comes around. */ if (length > 0 && dbuf_put(&(cli_recvQ(cptr)), readbuf, length) == 0) return exit_client(cptr, cptr, &me, "dbuf_put fail"); if (IsUser(cptr)) { if (DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD) && !IsOper(cptr)) return exit_client(cptr, cptr, &me, "Excess Flood"); } while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && (IsTrusted(cptr) || cli_since(cptr) - CurrentTime < 10)) { dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE); /* * Devious looking...whats it do ? well..if a client * sends a *long* message without any CR or LF, then * dbuf_getmsg fails and we pull it out using this * loop which just gets the next 512 bytes and then * deletes the rest of the buffer contents. * -avalon */ if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) SetFlag(cptr, FLAG_NONL); else { /* More than 512 bytes in the line - drop the input and yell * at the client. */ DBufClear(&(cli_recvQ(cptr))); send_reply(cptr, ERR_INPUTTOOLONG); } } else if (client_dopacket(cptr, dolen) == CPTR_KILLED) return CPTR_KILLED; /* * If it has become registered as a Server * then skip the per-message parsing below. */ if (IsHandshake(cptr) || IsServer(cptr)) { while (-1) { dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf)); if (dolen <= 0) return 1; else if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) SetFlag(cptr, FLAG_NONL); else DBufClear(&(cli_recvQ(cptr))); } else if ((IsServer(cptr) && server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) || (!IsServer(cptr) && connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED)) return CPTR_KILLED; } } } /* If there's still data to process, wait 2 seconds first */ if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && !t_onqueue(&(cli_proc(cptr)))) { Debug((DEBUG_LIST, "Adding client process timer for %C", cptr)); cli_freeflag(cptr) |= FREEFLAG_TIMER; timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr), TT_RELATIVE, 2); } } return 1; }
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; fstring desthost; struct in_addr dest_ip; const char *p; char *pserver; BOOL connected_ok = False; if (!(cli = cli_initialise())) return NULL; /* security = server just can't function with spnego */ cli->use_spnego = False; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { standard_sub_basic(current_user_info.smb_name, current_user_info.domain, desthost, sizeof(desthost)); strupper_m(desthost); if(!resolve_name( desthost, &dest_ip, 0x20)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyip(dest_ip)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ if (!grab_server_mutex(desthost)) { return NULL; } if (cli_connect(cli, desthost, &dest_ip)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } } if (!connected_ok) { release_server_mutex(); DEBUG(0,("password server not available\n")); cli_shutdown(cli); return NULL; } if (!attempt_netbios_session_request(&cli, global_myname(), desthost, &dest_ip)) { release_server_mutex(); DEBUG(1,("password server fails session request\n")); cli_shutdown(cli); return NULL; } if (strequal(desthost,myhostname())) { exit_server_cleanly("Password server loop!"); } DEBUG(3,("got session\n")); if (!cli_negprot(cli)) { DEBUG(1,("%s rejected the negprot\n",desthost)); release_server_mutex(); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { DEBUG(1,("%s isn't in user level security mode\n",desthost)); release_server_mutex(); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0, ""))) { DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, cli_errstr(cli))); release_server_mutex(); cli_shutdown(cli); return NULL; } release_server_mutex(); DEBUG(3,("password server OK\n")); return cli; }
/** Process events on a client socket. * @param ev Socket event structure that has a struct Connection as * its associated data. */ static void client_sock_callback(struct Event* ev) { struct Client* cptr; struct Connection* con; char *fmt = "%s"; char *fallback = 0; assert(0 != ev_socket(ev)); assert(0 != s_data(ev_socket(ev))); con = (struct Connection*) s_data(ev_socket(ev)); assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY); cptr = con_client(con); assert(0 == cptr || con == cli_connect(cptr)); switch (ev_type(ev)) { case ET_DESTROY: con_freeflag(con) &= ~FREEFLAG_SOCKET; if (!con_freeflag(con) && !cptr) free_connection(con); break; case ET_CONNECT: /* socket connection completed */ if (!completed_connection(cptr) || IsDead(cptr)) fallback = cli_info(cptr); break; case ET_ERROR: /* an error occurred */ fallback = cli_info(cptr); cli_error(cptr) = ev_data(ev); if (s_state(&(con_socket(con))) == SS_CONNECTING) { completed_connection(cptr); /* for some reason, the os_get_sockerr() in completed_connect() * can return 0 even when ev_data(ev) indicates a real error, so * re-assign the client error here. */ cli_error(cptr) = ev_data(ev); break; } /*FALLTHROUGH*/ case ET_EOF: /* end of file on socket */ Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr), cli_error(cptr))); SetFlag(cptr, FLAG_DEADSOCKET); if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) { exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)", cli_name(cptr), cli_serv(cptr)->last_error_msg); return; } else { fmt = "Read error: %s"; fallback = "EOF from client"; } break; case ET_WRITE: /* socket is writable */ ClrFlag(cptr, FLAG_BLOCKED); if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048) list_next_channels(cptr); Debug((DEBUG_SEND, "Sending queued data to %C", cptr)); send_queued(cptr); break; case ET_READ: /* socket is readable */ if (!IsDead(cptr)) { Debug((DEBUG_DEBUG, "Reading data from %C", cptr)); if (read_packet(cptr, 1) == 0) /* error while reading packet */ fallback = "EOF from client"; } break; default: assert(0 && "Unrecognized socket event in client_sock_callback()"); break; } assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr)); if (fallback) { const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback; if (!msg) msg = "Unknown error"; exit_client_msg(cptr, cptr, &me, fmt, msg); } }
static struct cli_state *do_connect( const char *server, const char *share, BOOL show_sessetup ) { struct cli_state *c = NULL; struct nmb_name called, calling; const char *server_n; struct in_addr ip; pstring servicename; char *sharename; fstring newserver, newshare; NTSTATUS status; /* make a copy so we don't modify the global string 'service' */ pstrcpy(servicename, share); sharename = servicename; if (*sharename == '\\') { server = sharename+2; sharename = strchr_m(server,'\\'); if (!sharename) return NULL; *sharename = 0; sharename++; } server_n = server; zero_ip(&ip); make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called , server, name_type); again: zero_ip(&ip); if (have_ip) ip = dest_ip; /* have to open a new connection */ if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) { d_printf("Connection to %s failed\n", server_n); return NULL; } status = cli_connect(c, server_n, &ip); if (!NT_STATUS_IS_OK(status)) { d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status)); return NULL; } c->protocol = max_protocol; c->use_kerberos = use_kerberos; cli_setup_signing_state(c, signing_state); if (!cli_session_request(c, &calling, &called, NULL)) { char *p; d_printf("session request to %s failed (%s)\n", called.name, cli_errstr(c)); cli_shutdown(c); c = NULL; if ((p=strchr_m(called.name, '.'))) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { d_printf("protocol negotiation failed\n"); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"", "", 0, "", 0, lp_workgroup()))) { d_printf("session setup failed: %s\n", cli_errstr(c)); if (NT_STATUS_V(cli_nt_error(c)) == NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)) d_printf("did you forget to run kinit?\n"); cli_shutdown(c); return NULL; } d_printf("Anonymous login successful\n"); } if ( show_sessetup ) { if (*c->server_domain) { DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); } else if (*c->server_os || *c->server_type){ DEBUG(0,("OS=[%s] Server=[%s]\n", c->server_os,c->server_type)); } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. check_dfs_proxy() will fail if it is a normal share. */ if ( (c->capabilities & CAP_DFS) && cli_check_msdfs_proxy( c, sharename, newserver, newshare ) ) { cli_shutdown(c); return do_connect( newserver, newshare, False ); } /* must be a normal share */ if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) { d_printf("tree connect failed: %s\n", cli_errstr(c)); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
/** Run the daemon. * @param[in] argc Number of arguments in \a argv. * @param[in] argv Arguments to program execution. */ int main(int argc, char **argv) { CurrentTime = time(NULL); thisServer.argc = argc; thisServer.argv = argv; thisServer.uid = getuid(); thisServer.euid = geteuid(); #ifdef MDEBUG mem_dbg_initialise(); #endif #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) set_core_limit(); #endif umask(077); /* better safe than sorry --SRB */ memset(&me, 0, sizeof(me)); memset(&me_con, 0, sizeof(me_con)); cli_connect(&me) = &me_con; cli_fd(&me) = -1; parse_command_line(argc, argv); if (chdir(dpath)) { fprintf(stderr, "Fail: Cannot chdir(%s): %s, check DPATH\n", dpath, strerror(errno)); return 2; } if (!set_userid_if_needed()) return 3; /* Check paths for accessibility */ if (!check_file_access(SPATH, 'S', X_OK) || !check_file_access(configfile, 'C', R_OK)) return 4; if (!init_connection_limits()) return 9; close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY | BOOT_CHKCONF))); /* daemon_init() must be before event_init() because kqueue() FDs * are, perversely, not inherited across fork(). */ daemon_init(thisServer.bootopt & BOOT_TTY); #ifdef DEBUGMODE /* Must reserve fd 2... */ if (debuglevel >= 0 && !(thisServer.bootopt & BOOT_TTY)) { int fd; if ((fd = open("/dev/null", O_WRONLY)) < 0) { fprintf(stderr, "Unable to open /dev/null (to reserve fd 2): %s\n", strerror(errno)); return 8; } if (fd != 2 && dup2(fd, 2) < 0) { fprintf(stderr, "Unable to reserve fd 2; dup2 said: %s\n", strerror(errno)); return 8; } } #endif event_init(MAXCONNECTIONS); setup_signals(); feature_init(); /* initialize features... */ log_init(*argv); set_nomem_handler(outofmemory); initload(); init_list(); init_hash(); init_class(); initwhowas(); initmsgtree(); initstats(); /* we need this for now, when we're modular this should be removed -- hikari */ ircd_crypt_init(); motd_init(); if (!init_conf()) { log_write(LS_SYSTEM, L_CRIT, 0, "Failed to read configuration file %s", configfile); return 7; } if (thisServer.bootopt & BOOT_CHKCONF) { if (dbg_client) conf_debug_iline(dbg_client); fprintf(stderr, "Configuration file %s checked okay.\n", configfile); return 0; } debug_init(thisServer.bootopt & BOOT_TTY); if (check_pid()) { Debug((DEBUG_FATAL, "Failed to acquire PID file lock after fork")); exit(2); } init_server_identity(); uping_init(); stats_init(); IPcheck_init(); timer_add(timer_init(&connect_timer), try_connections, 0, TT_RELATIVE, 1); timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1); timer_add(timer_init(&destruct_event_timer), exec_expired_destruct_events, 0, TT_PERIODIC, 60); timer_add(timer_init(&mute_timer), check_expired_mutes, 0, TT_PERIODIC, 30); CurrentTime = time(NULL); SetMe(&me); cli_magic(&me) = CLIENT_MAGIC; cli_from(&me) = &me; make_server(&me); cli_serv(&me)->timestamp = TStime(); /* Abuse own link timestamp as start TS */ cli_serv(&me)->prot = atoi(MAJOR_PROTOCOL); cli_serv(&me)->up = &me; cli_serv(&me)->down = NULL; cli_handler(&me) = SERVER_HANDLER; SetYXXCapacity(&me, MAXCLIENTS); cli_lasttime(&me) = cli_since(&me) = cli_firsttime(&me) = CurrentTime; hAddClient(&me); write_pidfile(); init_counters(); Debug((DEBUG_NOTICE, "Server ready...")); log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready"); event_loop(); return 0; }
void check() { if(cli_cont->stat != SC_CONN) cli_connect("127.0.0.1",9000); }
/** Read a 'packet' of data from a connection and process it. Read in * 8k chunks to give a better performance rating (for server * connections). Do some tricky stuff for client connections to make * sure they don't do any flooding >:-) -avalon * @param cptr Client from which to read data. * @param socket_ready If non-zero, more data can be read from the client's socket. * @return Positive number on success, zero on connection-fatal failure, negative * if user is killed. */ static int read_packet(struct Client *cptr, int socket_ready) { unsigned int dolen = 0; unsigned int length = 0; if (socket_ready && !(IsUser(cptr) && DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD))) { #if defined(USE_SSL) switch (client_recv(cptr, readbuf, sizeof(readbuf), &length)) { #else switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) { #endif case IO_SUCCESS: if (length) { cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); ClrFlag(cptr, FLAG_NONL); if (cli_lasttime(cptr) > cli_since(cptr)) cli_since(cptr) = cli_lasttime(cptr); } break; case IO_BLOCKED: break; case IO_FAILURE: cli_error(cptr) = errno; /* SetFlag(cptr, FLAG_DEADSOCKET); */ return 0; } } /* * For server connections, we process as many as we can without * worrying about the time of day or anything :) */ if (length > 0 && IsServer(cptr)) return server_dopacket(cptr, readbuf, length); else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr))) return connect_dopacket(cptr, readbuf, length); else { /* * Before we even think of parsing what we just read, stick * it on the end of the receive queue and do it when its * turn comes around. */ if (length > 0 && dbuf_put(cptr, &(cli_recvQ(cptr)), readbuf, length) == 0) return exit_client(cptr, cptr, &me, "dbuf_put fail"); if ((DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD)) && !IsChannelService(cptr)) return exit_client(cptr, cptr, &me, "Excess Flood"); while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && (IsTrusted(cptr) || IsChannelService(cptr) || cli_since(cptr) - CurrentTime < 10)) { dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE); /* * Devious looking...whats it do ? well..if a client * sends a *long* message without any CR or LF, then * dbuf_getmsg fails and we pull it out using this * loop which just gets the next 512 bytes and then * deletes the rest of the buffer contents. * -avalon */ if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) SetFlag(cptr, FLAG_NONL); else { /* More than 512 bytes in the line - drop the input and yell * at the client. */ DBufClear(&(cli_recvQ(cptr))); send_reply(cptr, ERR_INPUTTOOLONG); } } else if (client_dopacket(cptr, dolen) == CPTR_KILLED) return CPTR_KILLED; /* * If it has become registered as a Server * then skip the per-message parsing below. */ if (IsHandshake(cptr) || IsServer(cptr)) { while (-1) { dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf)); if (dolen <= 0) return 1; else if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) SetFlag(cptr, FLAG_NONL); else { DBufClear(&(cli_recvQ(cptr))); /* send_reply(cptr, ERR_INPUTTOOLONG); */ } } else if ((IsServer(cptr) && server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) || (!IsServer(cptr) && connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED)) return CPTR_KILLED; } } } /* If there's still data to process, wait 2 seconds first */ if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && !t_onqueue(&(cli_proc(cptr)))) { Debug((DEBUG_LIST, "Adding client process timer for %C", cptr)); cli_freeflag(cptr) |= FREEFLAG_TIMER; timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr), TT_RELATIVE, 2); } } return 1; } /** Start a connection to another server. * @param aconf Connect block data for target server. * @param by Client who requested the connection (if any). * @return Non-zero on success; zero on failure. */ int connect_server(struct ConfItem* aconf, struct Client* by) { struct Client* cptr = 0; assert(0 != aconf); if (aconf->dns_pending) { sendto_opmask(0, SNO_OLDSNO, "Server %s connect DNS pending", aconf->name); return 0; } Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name, ircd_ntoa(&aconf->address.addr))); if ((cptr = FindClient(aconf->name))) { if (IsServer(cptr) || IsMe(cptr)) { sendto_opmask(0, SNO_OLDSNO, "Server %s already present from %s", aconf->name, cli_name(cli_from(cptr))); if (by && IsUser(by) && !MyUser(by)) { sendcmdto_one(&me, CMD_NOTICE, by, "%C :Server %s already present " "from %s", by, aconf->name, cli_name(cli_from(cptr))); } return 0; } else if (IsHandshake(cptr) || IsConnecting(cptr)) { if (by && IsUser(by)) { sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connection to %s already in " "progress", by, cli_name(cptr)); } return 0; } } /* * If we don't know the IP# for this host and it is a hostname and * not a ip# string, then try and find the appropriate host record. */ if (!irc_in_addr_valid(&aconf->address.addr) && !ircd_aton(&aconf->address.addr, aconf->host)) { char buf[HOSTLEN + 1]; host_from_uh(buf, aconf->host, HOSTLEN); gethost_byname(buf, connect_dns_callback, aconf); aconf->dns_pending = 1; return 0; } cptr = make_client(NULL, STAT_UNKNOWN_SERVER); /* * Copy these in so we have something for error detection. */ ircd_strncpy(cli_name(cptr), aconf->name, HOSTLEN); ircd_strncpy(cli_sockhost(cptr), aconf->host, HOSTLEN); /* * Attach config entries to client here rather than in * completed_connection. This to avoid null pointer references */ attach_confs_byhost(cptr, aconf->host, CONF_SERVER); if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) { sendto_opmask(0, SNO_OLDSNO, "Host %s is not enabled for " "connecting: no Connect block", aconf->name); if (by && IsUser(by) && !MyUser(by)) { sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no " "Connect block", by, aconf->name); } det_confs_butmask(cptr, 0); free_client(cptr); return 0; } /* * attempt to connect to the server in the conf line */ if (!connect_inet(aconf, cptr)) { if (by && IsUser(by) && !MyUser(by)) { sendcmdto_one(&me, CMD_NOTICE, by, "%C :Couldn't connect to %s", by, cli_name(cptr)); } det_confs_butmask(cptr, 0); free_client(cptr); return 0; } /* * NOTE: if we're here we have a valid C:Line and the client should * have started the connection and stored the remote address/port and * ip address name in itself * * The socket has been connected or connect is in progress. */ make_server(cptr); if (by && IsUser(by)) { ircd_snprintf(0, cli_serv(cptr)->by, sizeof(cli_serv(cptr)->by), "%s%s", NumNick(by)); assert(0 == cli_serv(cptr)->user); cli_serv(cptr)->user = cli_user(by); cli_user(by)->refcnt++; } else { *(cli_serv(cptr))->by = '\0'; /* strcpy(cptr->serv->by, "Auto"); */ } cli_serv(cptr)->up = &me; SetConnecting(cptr); if (cli_fd(cptr) > HighestFd) HighestFd = cli_fd(cptr); LocalClientArray[cli_fd(cptr)] = cptr; Count_newunknown(UserStats); /* Actually we lie, the connect hasn't succeeded yet, but we have a valid * cptr, so we register it now. * Maybe these two calls should be merged. */ add_client_to_list(cptr); hAddClient(cptr); /* nextping = CurrentTime; */ return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ? completed_connection(cptr) : 1; } /** Find the real hostname for the host running the server (or one which * matches the server's name) and its primary IP#. Hostname is stored * in the client structure passed as a pointer. */ void init_server_identity(void) { const struct LocalConf* conf = conf_get_local(); assert(0 != conf); ircd_strncpy(cli_name(&me), conf->name, HOSTLEN); SetYXXServerName(&me, conf->numeric); } /** Process events on a client socket. * @param ev Socket event structure that has a struct Connection as * its associated data. */ static void client_sock_callback(struct Event* ev) { struct Client* cptr; struct Connection* con; char *fmt = "%s"; char *fallback = 0; assert(0 != ev_socket(ev)); assert(0 != s_data(ev_socket(ev))); con = (struct Connection*) s_data(ev_socket(ev)); assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY); cptr = con_client(con); assert(0 == cptr || con == cli_connect(cptr)); switch (ev_type(ev)) { case ET_DESTROY: con_freeflag(con) &= ~FREEFLAG_SOCKET; if (!con_freeflag(con) && !cptr) free_connection(con); #if defined(USE_SSL) ssl_free(ev_socket(ev)); #endif break; case ET_CONNECT: /* socket connection completed */ if (!completed_connection(cptr) || IsDead(cptr)) fallback = cli_info(cptr); break; case ET_ERROR: /* an error occurred */ fallback = cli_info(cptr); cli_error(cptr) = ev_data(ev); /* If the OS told us we have a bad file descriptor, we should * record that for future reference. */ if (cli_error(cptr) == EBADF) cli_fd(cptr) = -1; if (s_state(&(con_socket(con))) == SS_CONNECTING) { completed_connection(cptr); /* for some reason, the os_get_sockerr() in completed_connection() * can return 0 even when ev_data(ev) indicates a real error, so * re-assign the client error here. */ cli_error(cptr) = ev_data(ev); break; } /*FALLTHROUGH*/ case ET_EOF: /* end of file on socket */ Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr), cli_error(cptr))); SetFlag(cptr, FLAG_DEADSOCKET); if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) { exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)", cli_name(cptr), cli_serv(cptr)->last_error_msg); return; } else { fmt = "Read error: %s"; fallback = "EOF from client"; } break; case ET_WRITE: /* socket is writable */ ClrFlag(cptr, FLAG_BLOCKED); if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048) list_next_channels(cptr); Debug((DEBUG_SEND, "Sending queued data to %C", cptr)); send_queued(cptr); break; case ET_READ: /* socket is readable */ if (!IsDead(cptr)) { Debug((DEBUG_DEBUG, "Reading data from %C", cptr)); if (read_packet(cptr, 1) == 0) /* error while reading packet */ fallback = "EOF from client"; } break; default: assert(0 && "Unrecognized socket event in client_sock_callback()"); break; } assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr)); if (fallback) { const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback; if (!msg) msg = "Unknown error"; exit_client_msg(cptr, cptr, &me, fmt, msg); } } /** Process a timer on client socket. * @param ev Timer event that has a struct Connection as its * associated data. */ static void client_timer_callback(struct Event* ev) { struct Client* cptr; struct Connection* con; assert(0 != ev_timer(ev)); assert(0 != t_data(ev_timer(ev))); assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev)); con = (struct Connection*) t_data(ev_timer(ev)); assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY); cptr = con_client(con); assert(0 == cptr || con == cli_connect(cptr)); if (ev_type(ev)== ET_DESTROY) { con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */ if (!con_freeflag(con) && !cptr) free_connection(con); /* client is being destroyed */ } else { Debug((DEBUG_LIST, "Client process timer for %C expired; processing", cptr)); read_packet(cptr, 0); /* read_packet will re-add timer if needed */ } assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr)); }
void add_connection(struct Listener* listener, int fd, void *ssl) { #else void add_connection(struct Listener* listener, int fd) { #endif struct irc_sockaddr addr; struct Client *new_client; time_t next_target = 0; #if defined(USE_SSL) char *sslfp; #endif const char* const throttle_message = "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n"; /* 12345678901234567890123456789012345679012345678901234567890123456 */ const char* const register_message = "ERROR :Unable to complete your registration\r\n"; assert(0 != listener); /* * Removed preliminary access check. Full check is performed in m_server and * m_user instead. Also connection time out help to get rid of unwanted * connections. */ if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, NULL); #else close(fd); #endif return; } /* * Disable IP (*not* TCP) options. In particular, this makes it impossible * to use source routing to connect to the server. If we didn't do this * (and if intermediate networks didn't drop source-routed packets), an * attacker could successfully IP spoof us...and even return the anti-spoof * ping, because the options would cause the packet to be routed back to * the spoofer's machine. When we disable the IP options, we delete the * source route, and the normal routing takes over. */ os_disable_options(fd); if (listener_server(listener)) { new_client = make_client(0, STAT_UNKNOWN_SERVER); } else { /* * Add this local client to the IPcheck registry. * * If they're throttled, murder them, but tell them why first. */ if (!IPcheck_local_connect(&addr.addr, &next_target)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, throttle_message); #else write(fd, throttle_message, strlen(throttle_message)); close(fd); #endif return; } new_client = make_client(0, STAT_UNKNOWN_USER); SetIPChecked(new_client); } /* * Copy ascii address to 'sockhost' just in case. Then we have something * valid to put into error messages... */ ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr); strcpy(cli_sockhost(new_client), cli_sock_ip(new_client)); memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client))); if (next_target) cli_nexttarget(new_client) = next_target; cli_fd(new_client) = fd; if (!socket_add(&(cli_socket(new_client)), client_sock_callback, (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, register_message); #else write(fd, register_message, strlen(register_message)); close(fd); #endif cli_fd(new_client) = -1; return; } #if defined(USE_SSL) if (ssl) { cli_socket(new_client).s_ssl = ssl; sslfp = ssl_get_fingerprint(ssl); if (sslfp) ircd_strncpy(cli_sslclifp(new_client), sslfp, BUFSIZE+1); } #endif cli_freeflag(new_client) |= FREEFLAG_SOCKET; cli_listener(new_client) = listener; ++listener->ref_count; Count_newunknown(UserStats); /* if we've made it this far we can put the client on the auth query pile */ start_auth(new_client); } /** Determines whether to tell the events engine we're interested in * writable events. * @param cptr Client for which to decide this. */ void update_write(struct Client* cptr) { /* If there are messages that need to be sent along, or if the client * is in the middle of a /list, then we need to tell the engine that * we're interested in writable events--otherwise, we need to drop * that interest. */ socket_events(&(cli_socket(cptr)), ((MsgQLength(&cli_sendQ(cptr)) || cli_listing(cptr)) ? SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE); }
/** Attempt to send a sequence of bytes to the connection. * As a side effect, updates \a cptr's FLAG_BLOCKED setting * and sendB/sendK fields. * @param cptr Client that should receive data. * @param buf Message buffer to send to client. * @return Negative on connection-fatal error; otherwise * number of bytes sent. */ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) { unsigned int bytes_written = 0; unsigned int bytes_count = 0; assert(0 != cptr); #if defined(USE_SSL) switch (client_sendv(cptr, buf, &bytes_count, &bytes_written)) { #else switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { #endif case IO_SUCCESS: ClrFlag(cptr, FLAG_BLOCKED); cli_sendB(cptr) += bytes_written; cli_sendB(&me) += bytes_written; /* A partial write implies that future writes will block. */ if (bytes_written < bytes_count) SetFlag(cptr, FLAG_BLOCKED); break; case IO_BLOCKED: SetFlag(cptr, FLAG_BLOCKED); break; case IO_FAILURE: cli_error(cptr) = errno; SetFlag(cptr, FLAG_DEADSOCKET); break; } return bytes_written; } /** Complete non-blocking connect()-sequence. Check access and * terminate connection, if trouble detected. * @param cptr Client to which we have connected, with all ConfItem structs attached. * @return Zero on failure (caller should exit_client()), non-zero on success. */ static int completed_connection(struct Client* cptr) { struct ConfItem *aconf; time_t newts; struct Client *acptr; int i; #if defined(USE_SSL) char *sslfp; int r; #endif assert(0 != cptr); /* * get the socket status from the fd first to check if * connection actually succeeded */ if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) { const char* msg = strerror(cli_error(cptr)); if (!msg) msg = "Unknown error"; sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: %s", cli_name(cptr), msg); return 0; } if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) { sendto_opmask(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr)); return 0; } #if defined(USE_SSL) if (aconf->flags & CONF_SSL) { r = ssl_connect(&(cli_socket(cptr))); if (r == -1) { sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: SSL error", cli_name(cptr)); return 0; } else if (r == 0) return 1; sslfp = ssl_get_fingerprint(cli_socket(cptr).s_ssl); if (sslfp) ircd_strncpy(cli_sslclifp(cptr), sslfp, BUFSIZE+1); SetSSL(cptr); } #endif if (s_state(&(cli_socket(cptr))) == SS_CONNECTING) socket_state(&(cli_socket(cptr)), SS_CONNECTED); if (!EmptyString(aconf->passwd)) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); /* * Create a unique timestamp */ newts = TStime(); for (i = HighestFd; i > -1; --i) { if ((acptr = LocalClientArray[i]) && (IsServer(acptr) || IsHandshake(acptr))) { if (cli_serv(acptr)->timestamp >= newts) newts = cli_serv(acptr)->timestamp + 1; } } assert(0 != cli_serv(cptr)); cli_serv(cptr)->timestamp = newts; SetHandshake(cptr); /* * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); /* TODO: NEGOCIACION envia_config_req(cptr); */ sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); #if defined(DDB) ddb_burst(cptr); #endif return (IsDead(cptr)) ? 0 : 1; } /** Close the physical connection. Side effects: MyConnect(cptr) * becomes false and cptr->from becomes NULL. * @param cptr Client to disconnect. */ void close_connection(struct Client *cptr) { struct ConfItem* aconf; if (IsServer(cptr)) { ServerStats->is_sv++; ServerStats->is_sbs += cli_sendB(cptr); ServerStats->is_sbr += cli_receiveB(cptr); ServerStats->is_sti += CurrentTime - cli_firsttime(cptr); /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * Reschedule a faster reconnect, if this was a automatically * connected configuration entry. (Note that if we have had * a rehash in between, the status has been changed to * CONF_ILLEGAL). But only do this if it was a "good" link. */ aconf->hold = CurrentTime; aconf->hold += ((aconf->hold - cli_since(cptr) > feature_int(FEAT_HANGONGOODLINK)) ? feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf)); /* if (nextconnect > aconf->hold) */ /* nextconnect = aconf->hold; */ } } else if (IsUser(cptr)) { ServerStats->is_cl++; ServerStats->is_cbs += cli_sendB(cptr); ServerStats->is_cbr += cli_receiveB(cptr); ServerStats->is_cti += CurrentTime - cli_firsttime(cptr); } else ServerStats->is_ni++; #if defined(USE_ZLIB) /* * Siempre es una conexion nuestra */ if (cli_connect(cptr)->zlib_negociation & ZLIB_IN) { inflateEnd(cli_connect(cptr)->comp_in); MyFree(cli_connect(cptr)->comp_in); } if (cli_connect(cptr)->zlib_negociation & ZLIB_OUT) { deflateEnd(cli_connect(cptr)->comp_out); MyFree(cli_connect(cptr)->comp_out); } #endif if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; cli_freeflag(cptr) &= ~FREEFLAG_SOCKET; } SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); DBufClear(&(cli_recvQ(cptr))); memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr))); set_snomask(cptr, 0, SNO_SET); det_confs_butmask(cptr, 0); if (cli_listener(cptr)) { release_listener(cli_listener(cptr)); cli_listener(cptr) = 0; } for ( ; HighestFd > 0; --HighestFd) { if (LocalClientArray[HighestFd]) break; } } /** Close all unregistered connections. * @param source Oper who requested the close. * @return Number of closed connections. */ int net_close_unregistered_connections(struct Client* source) { int i; struct Client* cptr; int count = 0; assert(0 != source); for (i = HighestFd; i > 0; --i) { if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) { send_reply(source, RPL_CLOSING, get_client_name(source, HIDE_IP)); exit_client(source, cptr, &me, "Oper Closing"); ++count; } } return count; }
/** Set up address and port and make a connection. * @param aconf Provides the connection information. * @param cptr Client structure for the peer. * @return Non-zero on success; zero on failure. */ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) { const struct irc_sockaddr *local; IOResult result; int family = 0; assert(0 != aconf); assert(0 != cptr); /* * Might as well get sockhost from here, the connection is attempted * with it so if it fails its useless. */ if (irc_in_addr_valid(&aconf->origin.addr)) local = &aconf->origin; else if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; family = AF_INET; } else local = &VirtualHost_v6; cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family); if (cli_fd(cptr) < 0) return 0; /* * save connection info in client */ memcpy(&cli_ip(cptr), &aconf->address.addr, sizeof(cli_ip(cptr))); ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr)); /* * we want a big buffer for server connections */ if (!os_set_sockbufs(cli_fd(cptr), feature_int(FEAT_SOCKSENDBUF), feature_int(FEAT_SOCKRECVBUF))) { cli_error(cptr) = errno; report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } /* * Set the TOS bits - this is nonfatal if it doesn't stick. */ if (!os_set_tos(cli_fd(cptr), feature_int(FEAT_TOS_SERVER))) { report_error(TOS_ERROR_MSG, cli_name(cptr), errno); } if ((result = os_connect_nonb(cli_fd(cptr), &aconf->address)) == IO_FAILURE) { cli_error(cptr) = errno; report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } if (!socket_add(&(cli_socket(cptr)), client_sock_callback, (void*) cli_connect(cptr), (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING, SOCK_EVENT_READABLE, cli_fd(cptr))) { cli_error(cptr) = ENFILE; report_error(REGISTER_ERROR_MSG, cli_name(cptr), ENFILE); close(cli_fd(cptr)); cli_fd(cptr) = -1; return 0; } cli_freeflag(cptr) |= FREEFLAG_SOCKET; return 1; }
/***************************************************** return a connection to a server *******************************************************/ static struct cli_state *connect_one(char *share, int snum) { struct cli_state *c; struct nmb_name called, calling; char *server_n; fstring server; struct in_addr ip; fstring myname; static int count; fstrcpy(server,share+2); share = strchr_m(server,'\\'); if (!share) return NULL; *share = 0; share++; server_n = server; zero_ip(&ip); slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++); make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , server, 0x20); again: zero_ip(&ip); /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } c->use_kerberos = use_kerberos; if (!cli_session_request(c, &calling, &called)) { DEBUG(0,("session request to %s failed\n", called.name)); cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { DEBUG(0,("protocol negotiation failed\n")); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c))); return NULL; } /* * These next two lines are needed to emulate * old client behaviour for people who have * scripts based on client output. * QUESTION ? Do we want to have a 'client compatibility * mode to turn these on/off ? JRA. */ if (*c->server_domain || *c->server_os || *c->server_type) DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", password[snum], strlen(password[snum])+1)) { DEBUG(0,("tree connect failed: %s\n", cli_errstr(c))); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); c->use_oplocks = use_oplocks; return c; }
static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c; struct nmb_name called, calling; const char *server_n = server; struct sockaddr_storage ss; int tried_reverse = 0; int port_try_first; int port_try_next; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32 fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; zero_sockaddr(&ss); ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, srv->cli->desthost, srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tcon_andx(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: zero_sockaddr(&ss); /* have to open a new connection */ if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } if (smbc_getOptionUseKerberos(context)) { c->use_kerberos = True; } if (smbc_getOptionFallbackAfterKerberos(context)) { c->fallback_after_kerberos = True; } if (smbc_getOptionUseCCache(context)) { c->use_ccache = True; } c->timeout = smbc_getTimeout(context); /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work */ if (share == NULL || *share == '\0' || is_ipc) { port_try_first = 139; port_try_next = 445; } else { port_try_first = 445; port_try_next = 139; } c->port = port_try_first; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } } if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ /* Only try this if server is an IP address ... */ if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct sockaddr_storage rem_ss; if (!interpret_string_addr(&rem_ss, server, NI_NUMERICHOST)) { DEBUG(4, ("Could not convert IP address " "%s to struct sockaddr_storage\n", server)); errno = ETIMEDOUT; return NULL; } tried_reverse++; /* Yuck */ if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { make_nmb_name(&called, remote_name, 0x20); goto again; } } } errno = ETIMEDOUT; return NULL; } DEBUG(4,(" session request ok\n")); status = cli_negprot(c); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password); /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } status = cli_init_creds(c, username_used, *pp_workgroup, *pp_password); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tcon_andx(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive(c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
/***************************************************** return a connection to a server *******************************************************/ struct cli_state *connect_one(char *share) { struct cli_state *c; struct nmb_name called, calling; char *server_n; char *server; struct in_addr ip; extern struct in_addr ipzero; server = share+2; share = strchr(server,'\\'); if (!share) return NULL; *share = 0; share++; server_n = server; ip = ipzero; make_nmb_name(&calling, "masktest", 0x0, ""); make_nmb_name(&called , server, 0x20, ""); again: ip = ipzero; /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) || !cli_connect(c, server_n, &ip)) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } if (!cli_session_request(c, &calling, &called)) { DEBUG(0,("session request to %s failed\n", called.name)); cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20, ""); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { DEBUG(0,("protocol negotiation failed\n")); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c))); return NULL; } /* * These next two lines are needed to emulate * old client behaviour for people who have * scripts based on client output. * QUESTION ? Do we want to have a 'client compatibility * mode to turn these on/off ? JRA. */ if (*c->server_domain || *c->server_os || *c->server_type) DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", password, strlen(password)+1)) { DEBUG(0,("tree connect failed: %s\n", cli_errstr(c))); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
static void sync_child(char *name, int nm_type, char *workgroup, struct in_addr ip, bool local, bool servers, char *fname) { fstring unix_workgroup; struct cli_state *cli; uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; struct nmb_name called, calling; struct sockaddr_storage ss; NTSTATUS status; /* W2K DMB's return empty browse lists on port 445. Use 139. * Patch from Andy Levine [email protected]. */ cli = cli_initialise(); if (!cli) { return; } cli_set_port(cli, 139); in_addr_to_sockaddr_storage(&ss, ip); status = cli_connect(cli, name, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return; } make_nmb_name(&calling, get_local_machine_name(), 0x0); make_nmb_name(&called , name, nm_type); if (!cli_session_request(cli, &calling, &called)) { cli_shutdown(cli); return; } status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0, workgroup))) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, "IPC$", "IPC", "", 1))) { cli_shutdown(cli); return; } /* All the cli_XX functions take UNIX character set. */ fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup); /* Fetch a workgroup list. */ cli_NetServerEnum(cli, unix_workgroup, local_type|SV_TYPE_DOMAIN_ENUM, callback, NULL); /* Now fetch a server list. */ if (servers) { fstrcpy(unix_workgroup, workgroup); cli_NetServerEnum(cli, unix_workgroup, local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL, callback, NULL); } cli_shutdown(cli); }
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char **err_str) { struct nmb_name calling, called; struct cli_state *cli; struct rpc_pipe_client *pipe_hnd; struct sockaddr_storage ss; NTSTATUS result; bool pass_must_change = False; *err_str = NULL; if(!resolve_name( remote_machine, &ss, 0x20)) { asprintf(err_str, "Unable to find an IP address for machine " "%s.\n", remote_machine); return NT_STATUS_UNSUCCESSFUL; } cli = cli_initialise(); if (!cli) { return NT_STATUS_NO_MEMORY; } result = cli_connect(cli, remote_machine, &ss); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", remote_machine, nt_errstr(result)); cli_shutdown(cli); return result; } make_nmb_name(&calling, global_myname() , 0x0); make_nmb_name(&called , remote_machine, 0x20); if (!cli_session_request(cli, &calling, &called)) { asprintf(err_str, "machine %s rejected the session setup. " "Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } cli->protocol = PROTOCOL_NT1; if (!cli_negprot(cli)) { asprintf(err_str, "machine %s rejected the negotiate " "protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ result = cli_session_setup(cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, ""); if (!NT_STATUS_IS_OK(result)) { /* Password must change or Password expired are the only valid * error conditions here from where we can proceed, the rest like * account locked out or logon failure will lead to errors later * anyway */ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) && !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) { asprintf(err_str, "Could not connect to machine %s: " "%s\n", remote_machine, cli_errstr(cli)); cli_shutdown(cli); return result; } pass_must_change = True; /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ result = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "machine %s rejected the session " "setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ); cli_shutdown(cli); return result; } cli_init_creds(cli, "", "", NULL); } else { cli_init_creds(cli, user_name, "", old_passwd); } if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) { asprintf(err_str, "machine %s rejected the tconX on the IPC$ " "share. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Try not to give the password away too easily */ if (!pass_must_change) { pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY, "", /* what domain... ? */ user_name, old_passwd, &result); } else { /* * If the user password must be changed the ntlmssp bind will * fail the same way as the session setup above did. The * difference ist that with a pipe bind we don't get a good * error message, the result will be that the rpc call below * will just fail. So we do it anonymously, there's no other * way. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); } if (!pipe_hnd) { if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { asprintf(err_str, "machine %s rejected the " "password change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but for reasons such as wrong password, too short etc ... */ asprintf(err_str, "machine %s rejected the password change: " "Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* OK, that failed, so try again... */ cli_rpc_pipe_close(pipe_hnd); /* Try anonymous NTLMSSP... */ cli_init_creds(cli, "", "", NULL); result = NT_STATUS_UNSUCCESSFUL; /* OK, this is ugly, but... try an anonymous pipe. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); if ( pipe_hnd && (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but again it was due to things like new password too short */ asprintf(err_str, "machine %s rejected the " "(anonymous) password change: Error was : " "%s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* We have failed to change the user's password, and we think the server just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(cli); return NT_STATUS_OK; } asprintf(err_str, "machine %s rejected the password " "change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } } }
/**************************************************************************** support for server level security ****************************************************************************/ struct cli_state *server_cryptkey(void) { fstring desthost; struct in_addr dest_ip; extern fstring local_machine; char *p; if (!cli_initialise(&cli)) return NULL; for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) { fstrcpy(desthost,p); standard_sub_basic(desthost); strupper(desthost); if(!resolve_name( desthost, &dest_ip)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",p)); continue; } if (ismyip(dest_ip)) { DEBUG(1,("Password server loop - disabling password server %s\n",p)); continue; } if (cli_connect(&cli, desthost, &dest_ip)) { DEBUG(3,("connected to password server %s\n",p)); break; } } if (!p) { DEBUG(1,("password server not available\n")); cli_shutdown(&cli); return NULL; } if (!cli_session_request(&cli, desthost, 0x20, local_machine)) { DEBUG(1,("%s rejected the session\n",desthost)); cli_shutdown(&cli); return NULL; } DEBUG(3,("got session\n")); if (!cli_negprot(&cli)) { DEBUG(1,("%s rejected the negprot\n",desthost)); cli_shutdown(&cli); return NULL; } if (cli.protocol < PROTOCOL_LANMAN2 || !(cli.sec_mode & 1)) { DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(&cli); return NULL; } DEBUG(3,("password server OK\n")); return &cli; }
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; char *desthost = NULL; struct sockaddr_storage dest_ss; const char *p; char *pserver = NULL; bool connected_ok = False; struct named_mutex *mutex = NULL; NTSTATUS status; if (!(cli = cli_initialise())) return NULL; /* security = server just can't function with spnego */ cli->use_spnego = False; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) { desthost = talloc_sub_basic(mem_ctx, current_user_info.smb_name, current_user_info.domain, desthost); if (!desthost) { return NULL; } strupper_m(desthost); if(!resolve_name( desthost, &dest_ss, 0x20, false)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyaddr((struct sockaddr *)&dest_ss)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ mutex = grab_named_mutex(talloc_tos(), desthost, 10); if (mutex == NULL) { cli_shutdown(cli); return NULL; } status = cli_connect(cli, desthost, &dest_ss); if (NT_STATUS_IS_OK(status)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", desthost, nt_errstr(status) )); TALLOC_FREE(mutex); } if (!connected_ok) { DEBUG(0,("password server not available\n")); cli_shutdown(cli); return NULL; } if (!attempt_netbios_session_request(&cli, global_myname(), desthost, &dest_ss)) { TALLOC_FREE(mutex); DEBUG(1,("password server fails session request\n")); cli_shutdown(cli); return NULL; } if (strequal(desthost,myhostname())) { exit_server_cleanly("Password server loop!"); } DEBUG(3,("got session\n")); status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(1, ("%s rejected the negprot: %s\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { TALLOC_FREE(mutex); DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ status = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } TALLOC_FREE(mutex); DEBUG(3,("password server OK\n")); return cli; }
static struct cli_state *do_connect( const char *server, const char *share, BOOL show_sessetup ) { struct cli_state *c; struct nmb_name called, calling; const char *server_n; struct in_addr ip; pstring servicename; char *sharename; /* make a copy so we don't modify the global string 'service' */ pstrcpy(servicename, share); sharename = servicename; if (*sharename == '\\') { server = sharename+2; sharename = strchr_m(server,'\\'); if (!sharename) return NULL; *sharename = 0; sharename++; } server_n = server; zero_ip(&ip); make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called , server, name_type); again: zero_ip(&ip); if (have_ip) ip = dest_ip; /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) || !cli_connect(c, server_n, &ip)) { d_printf("Connection to %s failed\n", server_n); return NULL; } c->protocol = max_protocol; c->use_kerberos = use_kerberos; cli_setup_signing_state(c, signing_state); if (!cli_session_request(c, &calling, &called)) { char *p; d_printf("session request to %s failed (%s)\n", called.name, cli_errstr(c)); cli_shutdown(c); if ((p=strchr_m(called.name, '.'))) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { d_printf("protocol negotiation failed\n"); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"", "", 0, "", 0, lp_workgroup())) { d_printf("session setup failed: %s\n", cli_errstr(c)); if (NT_STATUS_V(cli_nt_error(c)) == NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)) d_printf("did you forget to run kinit?\n"); cli_shutdown(c); return NULL; } d_printf("Anonymous login successful\n"); } if ( show_sessetup ) { if (*c->server_domain) { DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); } else if (*c->server_os || *c->server_type){ DEBUG(0,("OS=[%s] Server=[%s]\n", c->server_os,c->server_type)); } } DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) { d_printf("tree connect failed: %s\n", cli_errstr(c)); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
NTSTATUS cli_full_connection(struct cli_state **output_cli, const char *my_name, const char *dest_host, struct in_addr *dest_ip, int port, const char *service, const char *service_type, const char *user, const char *domain, const char *password, int pass_len) { struct ntuser_creds creds; NTSTATUS nt_status; struct nmb_name calling; struct nmb_name called; struct cli_state *cli; struct in_addr ip; if (!output_cli) DEBUG(0, ("output_cli is NULL!?!")); *output_cli = NULL; make_nmb_name(&calling, my_name, 0x0); make_nmb_name(&called , dest_host, 0x20); again: if (!(cli = cli_initialise(NULL))) return NT_STATUS_NO_MEMORY; if (cli_set_port(cli, port) != port) { cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } ip = *dest_ip; DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service)); if (!cli_connect(cli, dest_host, &ip)) { DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n", nmb_namestr(&called), inet_ntoa(*dest_ip))); cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } if (!cli_session_request(cli, &calling, &called)) { char *p; DEBUG(1,("session request to %s failed (%s)\n", called.name, cli_errstr(cli))); cli_shutdown(cli); if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NT_STATUS_UNSUCCESSFUL; } if (!cli_negprot(cli)) { DEBUG(1,("failed negprot\n")); nt_status = NT_STATUS_UNSUCCESSFUL; cli_shutdown(cli); return nt_status; } if (!cli_session_setup(cli, user, password, pass_len, password, pass_len, domain)) { DEBUG(1,("failed session setup\n")); nt_status = cli_nt_error(cli); cli_shutdown(cli); if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL; return nt_status; } if (service) { if (!cli_send_tconX(cli, service, service_type, password, pass_len)) { DEBUG(1,("failed tcon_X\n")); nt_status = cli_nt_error(cli); cli_shutdown(cli); if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL; return nt_status; } } init_creds(&creds, user, domain, password, pass_len); cli_init_creds(cli, &creds); *output_cli = cli; return NT_STATUS_OK; }
/************************************************************* change a password on a remote machine using IPC calls *************************************************************/ BOOL remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char *err_str, size_t err_str_len) { struct nmb_name calling, called; struct cli_state cli; struct in_addr ip; *err_str = '\0'; if(!resolve_name( remote_machine, &ip, 0x20)) { slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n", remote_machine ); return False; } ZERO_STRUCT(cli); if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) { slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); return False; } make_nmb_name(&calling, global_myname() , 0x0); make_nmb_name(&called , remote_machine, 0x20); if (!cli_session_request(&cli, &calling, &called)) { slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } cli.protocol = PROTOCOL_NT1; if (!cli_negprot(&cli)) { slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } cli_shutdown(&cli); return True; }
/** Close the physical connection. Side effects: MyConnect(cptr) * becomes false and cptr->from becomes NULL. * @param cptr Client to disconnect. */ void close_connection(struct Client *cptr) { struct ConfItem* aconf; if (IsServer(cptr)) { ServerStats->is_sv++; ServerStats->is_sbs += cli_sendB(cptr); ServerStats->is_sbr += cli_receiveB(cptr); ServerStats->is_sti += CurrentTime - cli_firsttime(cptr); /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * Reschedule a faster reconnect, if this was a automatically * connected configuration entry. (Note that if we have had * a rehash in between, the status has been changed to * CONF_ILLEGAL). But only do this if it was a "good" link. */ aconf->hold = CurrentTime; aconf->hold += ((aconf->hold - cli_since(cptr) > feature_int(FEAT_HANGONGOODLINK)) ? feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf)); /* if (nextconnect > aconf->hold) */ /* nextconnect = aconf->hold; */ } } else if (IsUser(cptr)) { ServerStats->is_cl++; ServerStats->is_cbs += cli_sendB(cptr); ServerStats->is_cbr += cli_receiveB(cptr); ServerStats->is_cti += CurrentTime - cli_firsttime(cptr); } else ServerStats->is_ni++; if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; } SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); DBufClear(&(cli_recvQ(cptr))); memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr))); set_snomask(cptr, 0, SNO_SET); det_confs_butmask(cptr, 0); if (cli_listener(cptr)) { release_listener(cli_listener(cptr)); cli_listener(cptr) = 0; } for ( ; HighestFd > 0; --HighestFd) { if (LocalClientArray[HighestFd]) break; } }