From 748d65a4ac898708dc7d2fd6f2bdee41489fee86 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 20 Aug 1996 15:45:16 +0000 Subject: [PATCH] - fix a bug in NetServerEnum where counted and total were not counted correctly if there were multiple instances of a name. This led to the infamous "not enough memory" error when browsing (but this isn't the only cause of that message) - fix a triple-chaining bug which affected OpenX following a TconX - fix a serious nmbd bug that meant nmdb would answer packets that it wasn't supposed to, causing havoc with browse lists. - never time out SELF packets. This is an interim fix until I find out why nmbd thought they should be timed out. (This used to be commit 2960c3908c2c3b01a1f2b77def60350018d298e1) --- source3/include/includes.h | 2 + source3/include/proto.h | 1 - source3/namedbname.c | 24 ++++++------ source3/nameelect.c | 3 +- source3/namelogon.c | 5 --- source3/namepacket.c | 30 +++++++++++++- source3/namework.c | 80 -------------------------------------- source3/smbd/ipc.c | 14 ++++--- source3/smbd/reply.c | 45 ++++++++++++++++++++- source3/smbd/server.c | 45 +++------------------ 10 files changed, 101 insertions(+), 148 deletions(-) diff --git a/source3/include/includes.h b/source3/include/includes.h index c7acbddc2b3..5d5fd7fd55c 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -227,11 +227,13 @@ Here come some platform specific sections #endif #endif #ifdef SHADOW_PWD +#if _LINUX_C_LIB_VERSION_MAJOR < 5 #ifndef crypt #define crypt pw_encrypt #endif #endif #endif +#endif #ifdef SUNOS4 #define SIGNAL_CAST (void (*)(int)) diff --git a/source3/include/proto.h b/source3/include/proto.h index 9ddf7cb1fd8..f257ac0048f 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -679,7 +679,6 @@ int reply_coreplus(char *outbuf); int reply_lanman1(char *outbuf); int reply_lanman2(char *outbuf); int reply_nt1(char *outbuf); -void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev); void close_cnum(int cnum, int uid); BOOL yield_connection(int cnum,char *name,int max_connections); BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear); diff --git a/source3/namedbname.c b/source3/namedbname.c index 746353dd976..58b62bd0cbc 100644 --- a/source3/namedbname.c +++ b/source3/namedbname.c @@ -238,9 +238,9 @@ void dump_names(void) for (i = 0; i < n->num_ips; i++) { - DEBUG(3,("%15s NB=%2x ", - inet_ntoa(n->ip_flgs[i].ip), - n->ip_flgs[i].nb_flags)); + DEBUG(3,("%15s NB=%2x source=%d", + inet_ntoa(n->ip_flgs[i].ip), + n->ip_flgs[i].nb_flags,n->source)); } DEBUG(3,("\n")); @@ -486,13 +486,17 @@ void expire_names(time_t t) for (d = subnetlist; d; d = d->next) { for (n = d->namelist; n; n = next) + { + next = n->next; + if (n->death_time && n->death_time < t) { - if (n->death_time && n->death_time < t) - { + if (n->source == SELF) { + DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name))); + n->death_time += 300; + continue; + } DEBUG(3,("Removing dead name %s\n", namestr(&n->name))); - next = n->next; - if (n->prev) n->prev->next = n->next; if (n->next) n->next->prev = n->prev; @@ -501,11 +505,7 @@ void expire_names(time_t t) free(n->ip_flgs); free(n); } - else - { - next = n->next; - } - } + } } } diff --git a/source3/nameelect.c b/source3/nameelect.c index 2edc484ba0c..ef3935b1fdf 100644 --- a/source3/nameelect.c +++ b/source3/nameelect.c @@ -564,8 +564,7 @@ void process_election(struct packet_struct *p,char *buf) for (work = d->workgrouplist; work; work = work->next) { - if (listening_name(work, &dgram->dest_name) && - strequal(work->work_group, lp_workgroup())) + if (strequal(work->work_group, lp_workgroup())) { if (win_election(work, version,criterion,timeup,name)) { diff --git a/source3/namelogon.c b/source3/namelogon.c index c10049135c4..aacf32c2804 100644 --- a/source3/namelogon.c +++ b/source3/namelogon.c @@ -64,11 +64,6 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) DEBUG(3,("No domain logons\n")); return; } - if (!listening_name(work, &dgram->dest_name)) - { - DEBUG(4,("Not listening to that domain\n")); - return; - } code = SVAL(buf,0); switch (code) { diff --git a/source3/namepacket.c b/source3/namepacket.c index 4be5a959526..02f4958520c 100644 --- a/source3/namepacket.c +++ b/source3/namepacket.c @@ -162,7 +162,10 @@ void initiate_netbios_packet(uint16 *id, p.timestamp = time(NULL); p.packet_type = NMB_PACKET; - if (!send_packet(&p)) *id = 0xffff; + if (!send_packet(&p)) { + DEBUG(3,("send_packet to %s %d failed\n",inet_ntoa(p.ip),p.port)); + *id = 0xffff; + } return; } @@ -296,6 +299,26 @@ void queue_packet(struct packet_struct *packet) packet->prev = p; } +/**************************************************************************** + determine if a packet is for us. Note that to have any chance of + being efficient we need to drop as many packets as possible at this + stage as subsequent processing is expensive. + + We also must make absolutely sure we don't tread on another machines + property by answering a packet that is not for us. + ****************************************************************************/ +static BOOL listening(struct packet_struct *p,struct nmb_name *n) +{ + struct subnet_record *d; + struct name_record *n1; + + d = find_subnet(p->ip); + + n1 = find_name_search(&d,n,FIND_LOCAL|FIND_WINS|FIND_SELF,p->ip); + + return (n1 != NULL); +} + /**************************************************************************** process udp 138 datagrams @@ -307,6 +330,11 @@ static void process_dgram(struct packet_struct *p) int len; struct dgram_packet *dgram = &p->packet.dgram; + /* if we aren't listening to the destination name then ignore the packet */ + if (!listening(p,&dgram->dest_name)) + return; + + if (dgram->header.msg_type != 0x10 && dgram->header.msg_type != 0x11 && dgram->header.msg_type != 0x12) { diff --git a/source3/namework.c b/source3/namework.c index 108048d5001..90ab2fb1fb6 100644 --- a/source3/namework.c +++ b/source3/namework.c @@ -165,22 +165,6 @@ BOOL same_context(struct dgram_packet *dgram) } -/******************************************************************* - am I listening on a name. XXXX check the type of name as well. - ******************************************************************/ -BOOL listening_name(struct work_record *work, struct nmb_name *n) -{ - if (strequal(n->name,myname) || - strequal(n->name,work->work_group) || - strequal(n->name,MSBROWSE)) - { - return(True); - } - - return(False); -} - - /******************************************************************* process a domain announcement frame @@ -667,70 +651,6 @@ static void process_announce_request(struct packet_struct *p,char *buf) } -/**************************************************************************** -depending on what announce has been made, we are only going to -accept certain types of name announce. XXXX untested code - -check listening name type -****************************************************************************/ -BOOL listening_type(struct packet_struct *p, int command) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int type = dgram->dest_name.name_type; - - switch (command) - { - case ANN_HostAnnouncement: - { - if (type != 0x0 || type != 0x20) return (False); - break; - } - - case ANN_AnnouncementRequest: - { - return (True); - break; - } - - case ANN_Election: - { - return (True); - break; - } - - case ANN_GetBackupListReq: - { - return (True); - break; - } - - case ANN_GetBackupListResp: - { - return (True); - break; - } - - case ANN_DomainAnnouncement: - { - if (type != 0x1b || type != 0x1c) return (False); - break; - } - - case ANN_MasterAnnouncement: - { - if (type != 0x1d) return (False); - break; - } - - case ANN_LocalMasterAnnouncement: - { - if (type != 0x1c || type != 0x1d) return (False); - break; - } - } - return (True); /* we're not dealing with unknown packet types */ -} - /**************************************************************************** process a browse frame diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 78a98077694..9da7c993dd1 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -963,7 +963,7 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, int f_len, s_len; struct srv_info_struct *servers=NULL; int counted=0,total=0; - int i; + int i,missed; fstring domain; BOOL domain_request; BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY; @@ -991,6 +991,7 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, total = get_server_info(servertype,&servers,domain); data_len = fixed_len = string_len = 0; + missed = 0; qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); @@ -1006,12 +1007,13 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", s->name, s->type, s->comment, s->domain)); - if (data_len <= buf_len) - { + if (data_len <= buf_len) { counted++; fixed_len += f_len; string_len += s_len; - } + } else { + missed++; + } } } @@ -1044,12 +1046,12 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, SSVAL(*rparam,0,NERR_Success); SSVAL(*rparam,2,0); SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,total); + SSVAL(*rparam,6,counted+missed); if (servers) free(servers); DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", - domain,uLevel,counted,total)); + domain,uLevel,counted,counted+missed)); return(True); } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index a84a9af0c17..7241aadac08 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -130,6 +130,44 @@ static int connection_error(char *inbuf,char *outbuf,int connection_num) } + +/**************************************************************************** + parse a share descriptor string +****************************************************************************/ +static void parse_connect(char *p,char *service,char *user, + char *password,int *pwlen,char *dev) +{ + char *p2; + + DEBUG(4,("parsing connect string %s\n",p)); + + p2 = strrchr(p,'\\'); + if (p2 == NULL) + strcpy(service,p); + else + strcpy(service,p2+1); + + p += strlen(p) + 2; + + strcpy(password,p); + *pwlen = strlen(password); + + p += strlen(p) + 2; + + strcpy(dev,p); + + *user = 0; + p = strchr(service,'%'); + if (p != NULL) + { + *p = 0; + strcpy(user,p+1); + } +} + + + + /**************************************************************************** reply to a tcon ****************************************************************************/ @@ -149,7 +187,7 @@ int reply_tcon(char *inbuf,char *outbuf) vuid = valid_uid(uid); - parse_connect(inbuf,service,user,password,&pwlen,dev); + parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev); connection_num = make_connection(service,user,password,pwlen,dev,vuid); @@ -1210,6 +1248,11 @@ int reply_unlink(char *inbuf,char *outbuf) if (check_name(directory,cnum)) dirptr = OpenDir(directory); + /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then + the pattern matches against the long name, otherwise the short name + We don't implement this yet XXXX + */ + if (dirptr) { error = ERRbadfile; diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 1fb6358794a..683d63e7aaa 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2563,41 +2563,6 @@ static int reply_negprot(char *inbuf,char *outbuf) } -/**************************************************************************** - parse a connect packet -****************************************************************************/ -void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev) -{ - char *p = smb_buf(buf) + 1; - char *p2; - - DEBUG(4,("parsing connect string %s\n",p)); - - p2 = strrchr(p,'\\'); - if (p2 == NULL) - strcpy(service,p); - else - strcpy(service,p2+1); - - p += strlen(p) + 2; - - strcpy(password,p); - *pwlen = strlen(password); - - p += strlen(p) + 2; - - strcpy(dev,p); - - *user = 0; - p = strchr(service,'%'); - if (p != NULL) - { - *p = 0; - strcpy(user,p+1); - } -} - - /**************************************************************************** close all open files for a connection ****************************************************************************/ @@ -3261,14 +3226,14 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct; /* remember the original command type */ - smb_com1 = CVAL(orig_outbuf,smb_com); + smb_com1 = CVAL(orig_inbuf,smb_com); /* save the data which will be overwritten by the new headers */ memcpy(inbuf_saved,inbuf2,smb_wct); memcpy(outbuf_saved,outbuf2,smb_wct); - /* give the new packet the same header as the first part of the SMB */ - memmove(inbuf2,orig_inbuf,smb_wct); + /* give the new packet the same header as the last part of the SMB */ + memmove(inbuf2,inbuf,smb_wct); /* create the in buffer */ CVAL(inbuf2,smb_com) = smb_com2; @@ -3297,8 +3262,8 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, bufsize-chain_size); - /* copy the new reply header over the old one, but preserve - the smb_com field */ + /* copy the new reply and request headers over the old ones, but + preserve the smb_com field */ memmove(orig_outbuf,outbuf2,smb_wct); CVAL(orig_outbuf,smb_com) = smb_com1; -- 2.34.1