diff options
-rw-r--r-- | source3/include/nameserv.h | 41 | ||||
-rw-r--r-- | source3/include/proto.h | 14 | ||||
-rw-r--r-- | source3/include/smb.h | 15 | ||||
-rw-r--r-- | source3/nameannounce.c | 8 | ||||
-rw-r--r-- | source3/namedbwork.c | 4 | ||||
-rw-r--r-- | source3/nameelect.c | 379 | ||||
-rw-r--r-- | source3/namelogon.c | 77 | ||||
-rw-r--r-- | source3/namepacket.c | 5 | ||||
-rw-r--r-- | source3/nameserv.c | 61 | ||||
-rw-r--r-- | source3/namework.c | 8 | ||||
-rw-r--r-- | source3/nmbd/nmbd.c | 3 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 472 | ||||
-rw-r--r-- | source3/smbd/server.c | 57 |
13 files changed, 795 insertions, 349 deletions
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h index 7302f09e5d..75461ce5e6 100644 --- a/source3/include/nameserv.h +++ b/source3/include/nameserv.h @@ -73,7 +73,8 @@ /* server type identifiers */ #define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER) #define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER) -#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL) +#define AM_DOMMST(work) (work->ServerType & SV_TYPE_DOMAIN_MASTER) +#define AM_DOMMEM(work) (work->ServerType & SV_TYPE_DOMAIN_MEMBER) /* microsoft browser NetBIOS name */ #define MSBROWSE "\001\002__MSBROWSE__\002" @@ -85,16 +86,27 @@ enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL}; enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3}; enum packet_type {NMB_PACKET, DGRAM_PACKET}; + enum master_state { - MST_NONE, - MST_WON, + MST_POTENTIAL, + MST_BACK, MST_MSB, - MST_BROWSER, - MST_DOMAIN_NONE, - MST_DOMAIN_MEM, - MST_DOMAIN_TST, - MST_DOMAIN + MST_BROWSER +}; + +enum domain_state +{ + DOMAIN_NONE, + DOMAIN_WAIT, + DOMAIN_MST +}; + +enum logon_state +{ + LOGON_NONE, + LOGON_WAIT, + LOGON_SRV }; enum state_type @@ -179,8 +191,14 @@ struct work_record struct server_record *serverlist; - /* stage of development from non-master to master browser / domain master */ - enum master_state state; + /* stage of development from non-local-master up to local-master browser */ + enum master_state mst_state; + + /* stage of development from non-domain-master to domain master browser */ + enum domain_state dom_state; + + /* stage of development from non-logon-server to logon server */ + enum logon_state log_state; /* work group info */ fstring work_group; @@ -367,6 +385,9 @@ struct packet_struct /* broadcast packet announcement intervals, in minutes */ +/* attempt to add domain logon and domain master names */ +#define CHECK_TIME_ADD_DOM_NAMES 5 + /* search for master browsers of workgroups samba knows about, except default */ #define CHECK_TIME_MST_BROWSE 5 diff --git a/source3/include/proto.h b/source3/include/proto.h index 2cd8cfe2a8..bbfcad78f9 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -411,8 +411,14 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, void name_unregister_work(struct subnet_record *d, char *name, int name_type); void name_register_work(struct subnet_record *d, char *name, int name_type, int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast); -void become_master(struct subnet_record *d, struct work_record *work); -void become_nonmaster(struct subnet_record *d, struct work_record *work, +void become_local_master(struct subnet_record *d, struct work_record *work); +void become_domain_master(struct subnet_record *d, struct work_record *work); +void become_logon_server(struct subnet_record *d, struct work_record *work); +void unbecome_local_master(struct subnet_record *d, struct work_record *work, + int remove_type); +void unbecome_domain_master(struct subnet_record *d, struct work_record *work, + int remove_type); +void unbecome_logon_server(struct subnet_record *d, struct work_record *work, int remove_type); void run_elections(time_t t); void process_election(struct packet_struct *p,char *buf); @@ -436,7 +442,8 @@ void reply_netbios_packet(struct packet_struct *p1,int trn_id, void queue_packet(struct packet_struct *packet); void run_packet_queue(); void listen_for_packets(BOOL run_election); -BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, +BOOL send_mailslot_reply(BOOL unique, char *mailslot,int fd, + char *buf,int len,char *srcname, char *dstname,int src_type,int dest_type, struct in_addr dest_ip,struct in_addr src_ip); @@ -469,6 +476,7 @@ struct response_record *queue_netbios_packet(struct subnet_record *d, void remove_name_entry(struct subnet_record *d, char *name,int type); void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags); +void add_domain_names(time_t t); void add_my_names(void); void remove_my_names(); void refresh_my_names(time_t t); diff --git a/source3/include/smb.h b/source3/include/smb.h index eea5b5bc8c..e9d74befc2 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -797,6 +797,21 @@ char *Strstr(char *s, char *p); /* what server type are we currently */ +/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */ + +#define CAP_RAW_MODE 0x0001 +#define CAP_MPX_MODE 0x0002 +#define CAP_UNICODE 0x0004 +#define CAP_LARGE_FILES 0x0008 +#define CAP_NT_SMBS 0x0010 +#define CAP_RPC_REMOTE_APIS 0x0020 +#define CAP_STATUS32 0x0040 +#define CAP_LEVEL_II_OPLOCKS 0x0080 +#define CAP_LOCK_AND_READ 0x0100 +#define CAP_NT_FIND 0x0200 +#define CAP_DFS 0x1000 +#define CAP_LARGE_READX 0x4000 + /* protocol types. It assumes that higher protocols include lower protocols as subsets */ enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1}; diff --git a/source3/nameannounce.c b/source3/nameannounce.c index 1dadc0132c..990be00602 100644 --- a/source3/nameannounce.c +++ b/source3/nameannounce.c @@ -79,7 +79,8 @@ void announce_request(struct work_record *work, struct in_addr ip) of 0x1e, then we could get the master browser to announce to us instead of the members of the workgroup. wha-hey! */ - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False, BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip)); } @@ -106,7 +107,8 @@ void do_announce_request(char *info, char *to_name, int announce_type, strupper(p); p = skip_string(p,1); - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), myname,to_name,from,to,dest_ip,*iface_ip(dest_ip)); } @@ -172,7 +174,7 @@ void do_announce_host(int command, debug_browse_data(outbuf, PTR_DIFF(p,outbuf)); /* send the announcement */ - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf, PTR_DIFF(p,outbuf), from_name, to_name, from_type, to_type, diff --git a/source3/namedbwork.c b/source3/namedbwork.c index 04f2103254..0cfc47c41a 100644 --- a/source3/namedbwork.c +++ b/source3/namedbwork.c @@ -91,7 +91,9 @@ static struct work_record *make_workgroup(char *name) work->ElectionCount = 0; work->needelection = False; work->needannounce = True; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; + work->dom_state = DOMAIN_NONE; + work->log_state = LOGON_NONE; /* make sure all token representations of workgroups are unique */ diff --git a/source3/nameelect.c b/source3/nameelect.c index 9a15c0b112..9254e44712 100644 --- a/source3/nameelect.c +++ b/source3/nameelect.c @@ -51,6 +51,7 @@ extern struct subnet_record *subnetlist; extern uint16 nb_type; /* samba's NetBIOS name type */ + /******************************************************************* occasionally check to see if the master browser is around ******************************************************************/ @@ -167,7 +168,8 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, strupper(p); p = skip_string(p,1); - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip)); } @@ -183,26 +185,39 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion, void name_unregister_work(struct subnet_record *d, char *name, int name_type) { struct work_record *work; + int remove_type_local = 0; + int remove_type_domain = 0; + int remove_type_logon = 0; remove_netbios_name(d,name,name_type,SELF,ipzero); if (!(work = find_workgroupstruct(d, name, False))) return; - if (ms_browser_name(name, name_type) || - (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 && - (name_type == 0x1d || name_type == 0x1b))) + /* work out what to unbecome, from the name type being removed */ + + if (ms_browser_name(name, name_type)) + { + remove_type_local |= SV_TYPE_MASTER_BROWSER; + } + if (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1d) + { + remove_type_local |= SV_TYPE_MASTER_BROWSER; + } + if (AM_DOMMST(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1b) { - int remove_type = 0; - - if (ms_browser_name(name, name_type)) - remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER; - if (name_type == 0x1d) - remove_type = SV_TYPE_MASTER_BROWSER; - if (name_type == 0x1b) - remove_type = SV_TYPE_DOMAIN_MASTER; - - become_nonmaster(d, work, remove_type); + remove_type_domain |= SV_TYPE_DOMAIN_MASTER; } + if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) == 0 && + name_type == 0x1c) + { + remove_type_logon|= SV_TYPE_DOMAIN_MEMBER; + } + + if (remove_type_local ) unbecome_local_master (d, work, remove_type_local ); + if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain); + if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon ); } @@ -227,12 +242,28 @@ void name_register_work(struct subnet_record *d, char *name, int name_type, if (work) { - if (work->state != MST_NONE) + if (work->mst_state != MST_POTENTIAL) { - /* samba is in the process of working towards master browser-ness. + /* samba is working towards local master browser-ness. initiate the next stage. */ - become_master(d, work); + become_local_master(d, work); + return; + } + if (work->dom_state != DOMAIN_NONE) + { + /* samba is working towards domain master browser-ness. + initiate the next stage. + */ + become_domain_master(d, work); + return; + } + if (work->log_state != LOGON_NONE) + { + /* samba is working towards domain master browser-ness. + initiate the next stage. + */ + become_logon_server(d, work); return; } } @@ -241,29 +272,28 @@ void name_register_work(struct subnet_record *d, char *name, int name_type, /******************************************************************* - become the master browser. + become the local master browser. this is done in stages. note that this could take a while, particularly on a broadcast subnet, as we have to wait for the implicit registration of each name to be accepted. - as each name is successfully registered, become_master() is + as each name is successfully registered, become_local_master() is called again, in order to initiate the next stage. see dead_netbios_entry() - deals with implicit name registration and response_name_reg() - deals with explicit registration with a WINS server. - stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1. - stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d) - stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b) - stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...) + stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1. + stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d) + stage 3: was MST_MSB - go to MST_BROWSER and stay there XXXX note: this code still does not cope with the distinction between different types of nodes, particularly between M and P nodes. that comes later. ******************************************************************/ -void become_master(struct subnet_record *d, struct work_record *work) +void become_local_master(struct subnet_record *d, struct work_record *work) { /* domain type must be limited to domain enum + server type. it must not have SV_TYPE_SERVER or anything else with SERVER in it, else @@ -272,17 +302,17 @@ void become_master(struct subnet_record *d, struct work_record *work) */ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT; - if (!work) return; + if (!work || !d) return; DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n", - work->work_group,inet_ntoa(d->bcast_ip),work->state)); + work->work_group,inet_ntoa(d->bcast_ip),work->mst_state)); - switch (work->state) + switch (work->mst_state) { - case MST_NONE: /* while we were nothing but a server... */ + case MST_POTENTIAL: /* while we were nothing but a server... */ { DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n")); - work->state = MST_WON; /* ... an election win was successful */ + work->mst_state = MST_BACK; /* ... an election win was successful */ work->ElectionCriterion |= 0x5; @@ -294,12 +324,13 @@ void become_master(struct subnet_record *d, struct work_record *work) add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } - case MST_WON: /* while nothing had happened except we won an election... */ + + case MST_BACK: /* while nothing had happened except we won an election... */ { DEBUG(3,("go to second stage: register as master browser\n")); - work->state = MST_MSB; /* ... registering MSBROWSE was successful */ + work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */ /* add server entry on successful registration of MSBROWSE */ add_server_entry(d,work,work->work_group,domain_type,0,myname,True); @@ -308,12 +339,13 @@ void become_master(struct subnet_record *d, struct work_record *work) add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE); /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } + case MST_MSB: /* while we were still only registered MSBROWSE state... */ { DEBUG(3,("2nd stage complete: registered as master browser\n")); - work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ + work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ /* update our server status */ work->ServerType |= SV_TYPE_MASTER_BROWSER; @@ -322,31 +354,70 @@ void become_master(struct subnet_record *d, struct work_record *work) if (work->serverlist == NULL) /* no servers! */ { /* ask all servers on our local net to announce to us */ + /* XXXX OOPS! add_server_entry will always add one entry - our own. */ announce_request(work, d->bcast_ip); } break; - } + } - case MST_BROWSER: - { + case MST_BROWSER: + { /* don't have to do anything: just report success */ DEBUG(3,("3rd stage: become master browser!\n")); break; - } + } + } +} - case MST_DOMAIN_NONE: - { + +/******************************************************************* + become the domain master browser. + + this is done in stages. note that this could take a while, + particularly on a broadcast subnet, as we have to wait for + the implicit registration of each name to be accepted. + + as each name is successfully registered, become_domain_master() is + called again, in order to initiate the next stage. see + dead_netbios_entry() - deals with implicit name registration + and response_name_reg() - deals with explicit registration + with a WINS server. + + stage 1: was DOMAIN_NONE - go to DOMAIN_MST + + XXXX note: this code still does not cope with the distinction + between different types of nodes, particularly between M and P + nodes. that comes later. + + ******************************************************************/ +void become_domain_master(struct subnet_record *d, struct work_record *work) +{ + /* domain type must be limited to domain enum + server type. it must + not have SV_TYPE_SERVER or anything else with SERVER in it, else + clients get confused and start thinking this entry is a server + not a workgroup + */ + + if (!work || !d) return; + + DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n", + work->work_group,inet_ntoa(d->bcast_ip),work->dom_state)); + + switch (work->dom_state) + { + case DOMAIN_NONE: /* while we were nothing but a server... */ + { if (lp_domain_master()) { - work->state = MST_DOMAIN_MEM; /* ... become domain member */ - DEBUG(3,("domain first stage: register as domain member\n")); + DEBUG(3,("go to first stage: register <1b> name\n")); + work->dom_state = DOMAIN_WAIT; - /* add domain member name */ - add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP); + /* XXXX the 0x1b is domain master browser name */ + add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP); - /* DON'T do anything else after calling add_my_name_entry() */ - return; + /* DON'T do anything else after calling add_my_name_entry() */ + break; } else { @@ -354,26 +425,23 @@ void become_master(struct subnet_record *d, struct work_record *work) } break; - } + } - case MST_DOMAIN_MEM: + case DOMAIN_WAIT: { if (lp_domain_master()) { - work->state = MST_DOMAIN_TST; /* ... possibly become domain master */ - DEBUG(3,("domain second stage: register as domain master\n")); - - if (lp_domain_logons()) - { - work->ServerType |= SV_TYPE_DOMAIN_MEMBER; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); - } + work->dom_state = DOMAIN_MST; /* ... become domain master */ + DEBUG(3,("domain first stage: register as domain member\n")); + + /* update our server status */ + work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER; + add_server_entry(d,work,myname,work->ServerType,0, + lp_serverstring(),True); - /* add domain master name */ - add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE ); + DEBUG(4,("samba is now a domain master\n")); - /* DON'T do anything else after calling add_my_name_entry() */ - return; + break; } else { @@ -381,108 +449,173 @@ void become_master(struct subnet_record *d, struct work_record *work) } break; + } + + case DOMAIN_MST: + { + /* don't have to do anything: just report success */ + DEBUG(3,("domain second stage: there isn't one!\n")); + break; } + } +} + - case MST_DOMAIN_TST: /* while we were still a master browser... */ +/******************************************************************* + become a logon server. + ******************************************************************/ +void become_logon_server(struct subnet_record *d, struct work_record *work) +{ + if (!work || !d) return; + + DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n", + work->work_group,inet_ntoa(d->bcast_ip),work->log_state)); + + switch (work->log_state) + { + case LOGON_NONE: /* while we were nothing but a server... */ { - /* update our server status */ - if (lp_domain_master()) + if (lp_domain_logons()) { - struct subnet_record *d1; - uint32 update_type = 0; - - DEBUG(3,("domain third stage: samba is now a domain master.\n")); - work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */ + DEBUG(3,("go to first stage: register <1c> name\n")); + work->log_state = LOGON_WAIT; - update_type |= DFLT_SERVER_TYPE | SV_TYPE_DOMAIN_MASTER | - SV_TYPE_POTENTIAL_BROWSER; + /* XXXX the 0x1c is apparently something to do with domain logons */ + add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP); - work->ServerType |= update_type; - add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); + /* DON'T do anything else after calling add_my_name_entry() */ + break; + } + { + DEBUG(4,("samba not configured as a logon master.\n")); + } + + break; + } - for (d1 = subnetlist; d1; d1 = d1->next) - { - struct work_record *w; - if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue; + case LOGON_WAIT: + { + if (lp_domain_logons()) + { + work->log_state = LOGON_SRV; /* ... become logon server */ + DEBUG(3,("logon second stage: register \n")); + + /* update our server status */ + work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER; + add_server_entry(d,work,myname,work->ServerType,0, + lp_serverstring(),True); - for (w = d1->workgrouplist; w; w = w->next) - { - struct server_record *s = find_server(w, myname); - if (strequal(w->work_group, work->work_group)) - { - w->ServerType |= update_type; - } - if (s) - { - s->serv.type |= update_type; - DEBUG(4,("found server %s on %s: update to %8x\n", - s->serv.name, inet_ntoa(d1->bcast_ip), - s->serv.type)); - } - } - } + /* DON'T do anything else after calling add_my_name_entry() */ + break; + } + else + { + DEBUG(4,("samba not configured as a logon server.\n")); } break; - } + } - case MST_DOMAIN: - { - /* don't have to do anything: just report success */ - DEBUG(3,("fifth stage: there isn't one yet!\n")); + case LOGON_SRV: + { + DEBUG(3,("logon third stage: there isn't one!\n")); break; - } + } + } } /******************************************************************* - unbecome the master browser. initates removal of necessary netbios + unbecome the local master browser. initates removal of necessary netbios names, and tells the world that we are no longer a master browser. + + XXXX this _should_ be used to demote to a backup master browser, without + going straight to non-master browser. another time. + ******************************************************************/ -void become_nonmaster(struct subnet_record *d, struct work_record *work, +void unbecome_local_master(struct subnet_record *d, struct work_record *work, int remove_type) { int new_server_type = work->ServerType; - DEBUG(2,("Becoming non-master for %s\n",work->work_group)); - - /* can only remove master or domain types with this function */ - remove_type &= SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER; - - /* unbecome a master browser; unbecome a domain master, too :-( */ - if (remove_type & SV_TYPE_MASTER_BROWSER) - remove_type |= SV_TYPE_DOMAIN_MASTER; + /* can only remove master types with this function */ + remove_type &= SV_TYPE_MASTER_BROWSER; new_server_type &= ~remove_type; - if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER))) + if (remove_type) { + DEBUG(2,("Becoming local non-master for %s\n",work->work_group)); + /* no longer a master browser of any sort */ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER; work->ElectionCriterion &= ~0x4; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; /* announce ourselves as no longer active as a master browser. */ announce_server(d, work, work->work_group, myname, 0, 0); remove_name_entry(d,MSBROWSE ,0x01); + remove_name_entry(d,work->work_group,0x1d); } +} + + +/******************************************************************* + unbecome the domain master browser. initates removal of necessary netbios + names, and tells the world that we are no longer a domain browser. + ******************************************************************/ +void unbecome_domain_master(struct subnet_record *d, struct work_record *work, + int remove_type) +{ + int new_server_type = work->ServerType; + + DEBUG(2,("Becoming domain non-master for %s\n",work->work_group)); - work->ServerType = new_server_type; + /* can only remove master or domain types with this function */ + remove_type &= SV_TYPE_DOMAIN_MASTER; - if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER)) + new_server_type &= ~remove_type; + + if (remove_type) { - if (work->state == MST_DOMAIN) - work->state = MST_BROWSER; + /* no longer a domain master browser of any sort */ + + work->dom_state = DOMAIN_NONE; + + /* announce ourselves as no longer active as a master browser. */ + announce_server(d, work, work->work_group, myname, 0, 0); remove_name_entry(d,work->work_group,0x1b); } +} + + +/******************************************************************* + unbecome the logon server. initates removal of necessary netbios + names, and tells the world that we are no longer a logon server. + ******************************************************************/ +void unbecome_logon_server(struct subnet_record *d, struct work_record *work, + int remove_type) +{ + int new_server_type = work->ServerType; + + DEBUG(2,("Becoming logon non-server for %s\n",work->work_group)); + + /* can only remove master or domain types with this function */ + remove_type &= SV_TYPE_DOMAIN_MEMBER; - if (!(work->ServerType & SV_TYPE_MASTER_BROWSER)) + new_server_type &= ~remove_type; + + if (remove_type) { - if (work->state >= MST_BROWSER) - work->state = MST_NONE; - remove_name_entry(d,work->work_group,0x1d); + /* no longer a master browser of any sort */ + + work->log_state = LOGON_NONE; + + /* announce ourselves as no longer active as a master browser. */ + announce_server(d, work, work->work_group, myname, 0, 0); + remove_name_entry(d,work->work_group,0x1c); } } @@ -518,9 +651,9 @@ void run_elections(time_t t) work->work_group,inet_ntoa(d->bcast_ip))); work->RunningElection = False; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; - become_master(d, work); + become_local_master(d, work); } } } @@ -598,7 +731,7 @@ void process_election(struct packet_struct *p,char *buf) if (!work->RunningElection) { work->needelection = True; work->ElectionCount=0; - work->state = MST_NONE; + work->mst_state = MST_POTENTIAL; } } else { work->needelection = False; @@ -608,9 +741,7 @@ void process_election(struct packet_struct *p,char *buf) DEBUG(3,(">>> Lost election on %s %s <<<\n", work->work_group,inet_ntoa(d->bcast_ip))); if (AM_MASTER(work)) - become_nonmaster(d, work, - SV_TYPE_MASTER_BROWSER| - SV_TYPE_DOMAIN_MASTER); + unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER); } } } diff --git a/source3/namelogon.c b/source3/namelogon.c index aacf32c280..3fab49cedd 100644 --- a/source3/namelogon.c +++ b/source3/namelogon.c @@ -54,86 +54,101 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len) pstring outbuf; int code,reply_code; struct work_record *work; + char unknown_byte = 0; + uint16 request_count = 0; + uint16 token = 0; if (!d) return; - if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) - return; + if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) return; - if (!lp_domain_logons()) { + if (!lp_domain_logons()) + { DEBUG(3,("No domain logons\n")); return; } code = SVAL(buf,0); - switch (code) { + switch (code) + { case 0: { char *machine = buf+2; char *user = skip_string(machine,1); + char *tmp; logname = skip_string(user,1); - reply_code = 6; + tmp = skip_string(logname,1); + unknown_byte = CVAL(tmp,0); + request_count = SVAL(tmp,1); + token = SVAL(tmp,3); + + reply_code = 0x6; strcpy(reply_name,myname); strupper(reply_name); add_slashes = True; - DEBUG(3,("Domain login request from %s(%s) user=%s\n", - machine,inet_ntoa(p->ip),user)); - } + DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n", + machine,inet_ntoa(p->ip),user,token)); break; + } case 7: { char *machine = buf+2; logname = skip_string(machine,1); - reply_code = 7; + token = SVAL(skip_string(logname,1),0); + strcpy(reply_name,lp_domain_controller()); - if (!*reply_name) { + if (!*reply_name) + { + /* oo! no domain controller. must be us, then */ strcpy(reply_name,myname); reply_code = 0xC; } - strupper(reply_name); - DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%2x\n", - machine,inet_ntoa(p->ip), reply_name, reply_code)); + else + { + /* refer logon request to the domain controller */ + reply_code = 0x7; } + + strupper(reply_name); + DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%x token=%x\n", + machine,inet_ntoa(p->ip), reply_name, reply_code,token)); break; + } default: + { DEBUG(3,("Unknown domain request %d\n",code)); return; } + } bzero(outbuf,sizeof(outbuf)); q = outbuf; SSVAL(q,0,reply_code); q += 2; - if (add_slashes) { + + if (token == 0xffff || /* LM 2.0 or later */ + token == 0xfffe) /* WfWg networking */ + { + if (add_slashes) + { strcpy(q,"\\\\"); q += 2; } - StrnCpy(q,reply_name,16); + strcpy(q, reply_name); + strupper(q); q = skip_string(q,1); - if (reply_code == 0xC) - { - if ( PTR_DIFF (q,outbuf) & 1 ) + if (token == 0xffff) /* LM 2.0 or later */ { - q++; - } - - PutUniCode(q,reply_name); - q += 2*(strlen(reply_name) + 1); - - PutUniCode(q,lp_workgroup()); - q += 2*(strlen(lp_workgroup()) + 1); - - SIVAL(q,0,1); - q += 4; - SSVAL(q,0,0xFFFF); + SSVAL(q,0,token); q += 2; } + } SSVAL(q,0,0xFFFF); q += 2; - send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), + send_mailslot_reply(True, logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), myname,&dgram->source_name.name[0],0x20,0,p->ip, *iface_ip(p->ip)); } diff --git a/source3/namepacket.c b/source3/namepacket.c index e62f3f00b0..e31d423784 100644 --- a/source3/namepacket.c +++ b/source3/namepacket.c @@ -559,7 +559,7 @@ void listen_for_packets(BOOL run_election) Note that this currently sends all answers to port 138. thats the wrong things to do! I should send to the requestors port. XXX **************************************************************************/ -BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, +BOOL send_mailslot_reply(BOOL unique, char *mailslot,int fd,char *buf,int len,char *srcname, char *dstname,int src_type,int dest_type, struct in_addr dest_ip,struct in_addr src_ip) { @@ -576,7 +576,8 @@ BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, update_name_trn_id(); - dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */ + /* DIRECT GROUP or UNIQUE datagram */ + dgram->header.msg_type = unique ? 0x10 : 0x11; dgram->header.flags.node_type = M_NODE; dgram->header.flags.first = True; dgram->header.flags.more = False; diff --git a/source3/nameserv.c b/source3/nameserv.c index 7353251940..7f1c0fadee 100644 --- a/source3/nameserv.c +++ b/source3/nameserv.c @@ -156,6 +156,51 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) /**************************************************************************** + add the domain logon server and domain master browser names + + this code was written so that several samba servers can co-operate in + sharing the task of (one server) being a domain master, and of being + domain logon servers. + + **************************************************************************/ +void add_domain_names(time_t t) +{ + static time_t lastrun = 0; + struct subnet_record *d; + + if (lastrun != 0 && t < lastrun + CHECK_TIME_ADD_DOM_NAMES * 60) return; + lastrun = t; + + for (d = subnetlist; d; d = d->next) + { + struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False); + struct nmb_name n; + + if (lp_domain_logons() && work && work->log_state == LOGON_NONE) + { + make_nmb_name(&n,lp_workgroup(),0x1c,scope); + if (!find_name(d->namelist, &n, FIND_SELF)) + { + DEBUG(0,("%s attempting to become logon server for %s %s\n", + timestring(), lp_workgroup(), inet_ntoa(d->bcast_ip))); + become_logon_server(d, work); + } + } + if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE) + { + make_nmb_name(&n,lp_workgroup(),0x1b,scope); + if (!find_name(d->namelist, &n, FIND_SELF)) + { + DEBUG(1,("%s attempting to become logon server for %s %s\n", + timestring(), lp_workgroup(), inet_ntoa(d->bcast_ip))); + become_domain_master(d, work); + } + } + } +} + + +/**************************************************************************** add the magic samba names, useful for finding samba servers **************************************************************************/ void add_my_names(void) @@ -170,6 +215,7 @@ void add_my_names(void) for (d = subnetlist; d; d = d->next) { BOOL wins = lp_wins_support() && ip_equal(d->bcast_ip,ipgrp); + struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False); add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE); add_my_name_entry(d, myname,0x03,nb_type|NB_ACTIVE); @@ -183,18 +229,13 @@ void add_my_names(void) add_netbios_entry(d,"__SAMBA__",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins); - if (lp_domain_logons()) { - /* XXXX the 0x1c is apparently something to do with domain logons */ - add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP); + if (lp_domain_logons() && work && work->log_state == LOGON_NONE) + { + become_logon_server(d, work); } - } - if (lp_domain_master() && (d = find_subnet(ipgrp))) - { - struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True); - if (work && work->state == MST_NONE) + if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE) { - work->state = MST_DOMAIN_NONE; - become_master(d, work); + become_domain_master(d, work); } } } diff --git a/source3/namework.c b/source3/namework.c index f4a9113cea..20c1050597 100644 --- a/source3/namework.c +++ b/source3/namework.c @@ -79,7 +79,8 @@ void reset_server(char *name, int state, struct in_addr ip) DEBUG(2,("sending reset to %s %s of state %d\n", name,inet_ntoa(ip),state)); - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), myname,name,0x20,0x1d,ip,*iface_ip(ip)); } @@ -488,7 +489,8 @@ static void send_backup_list(char *work_name, struct nmb_name *src_name, int len = PTR_DIFF(p, outbuf); debug_browse_data(outbuf, len); } - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM, + outbuf,PTR_DIFF(p,outbuf), myname,theirname,0x0,0x0,ip,*iface_ip(ip)); } @@ -570,7 +572,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf) { if (AM_MASTER(work)) { - become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER); + unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER); } } } diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index 58953bcd9d..e45facdc2e 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -300,9 +300,7 @@ static void process(void) run_elections(t); announce_host(t); - announce_master(t); - announce_remote(t); query_refresh_names(t); @@ -314,6 +312,7 @@ static void process(void) write_browse_list(t); do_browser_lists(t); check_master_browser(t); + add_domain_names(t); } } diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index ccb2f3dd52..9f8369912c 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -1,3 +1,4 @@ + /* Unix SMB/Netbios implementation. Version 1.9. @@ -1672,7 +1673,8 @@ static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data, if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { for (i=0;i<count;i++) - if (strequal(servers[i].name,local_machine)) { + if (strequal(servers[i].name,local_machine)) + { servertype = servers[i].type; strcpy(comment,servers[i].comment); } @@ -1742,8 +1744,10 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data, p = *rdata; p2 = p + 22; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); + + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ strcpy(p2,local_machine); + strupper(p2); p2 = skip_string(p2,1); p += 4; @@ -1752,21 +1756,22 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data, p2 = skip_string(p2,1); p += 4; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ strcpy(p2,lp_workgroup()); + strupper(p2); p2 = skip_string(p2,1); p += 4; - SCVAL(p,0,MAJOR_VERSION); - SCVAL(p,1,MINOR_VERSION); + SCVAL(p,0,MAJOR_VERSION); /* system version - e.g 4 in 4.1 */ + SCVAL(p,1,MINOR_VERSION); /* system version - e.g .1 in 4.1 */ p += 2; SIVAL(p,0,PTR_DIFF(p2,*rdata)); - strcpy(p2,lp_workgroup()); /* login domain?? */ + strcpy(p2,lp_workgroup()); /* don't know. login domain?? */ p2 = skip_string(p2,1); p += 4; - SIVAL(p,0,PTR_DIFF(p2,*rdata)); + SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ strcpy(p2,""); p2 = skip_string(p2,1); p += 4; @@ -1778,166 +1783,338 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data, return(True); } - /**************************************************************************** get info about a user + + struct user_info_11 { + char usri11_name[21]; 0-20 + char usri11_pad; 21 + char *usri11_comment; 22-25 + char *usri11_usr_comment; 26-29 + unsigned short usri11_priv; 30-31 + unsigned long usri11_auth_flags; 32-35 + long usri11_password_age; 36-39 + char *usri11_homedir; 40-43 + char *usri11_parms; 44-47 + long usri11_last_logon; 48-51 + long usri11_last_logoff; 52-55 + unsigned short usri11_bad_pw_count; 56-57 + unsigned short usri11_num_logons; 58-59 + char *usri11_logon_server; 60-63 + unsigned short usri11_country_code; 64-65 + char *usri11_workstations; 66-69 + unsigned long usri11_max_storage; 70-73 + unsigned short usri11_units_per_week; 74-75 + unsigned char *usri11_logon_hours; 76-79 + unsigned short usri11_code_page; 80-81 + }; + +where: + + usri11_name specifies the user name for which information is retireved + + usri11_pad aligns the next data structure element to a word boundary + + usri11_comment is a null terminated ASCII comment + + usri11_user_comment is a null terminated ASCII comment about the user + + usri11_priv specifies the level of the privilege assigned to the user. + The possible values are: + +Name Value Description +USER_PRIV_GUEST 0 Guest privilege +USER_PRIV_USER 1 User privilege +USER_PRV_ADMIN 2 Administrator privilege + + usri11_auth_flags specifies the account operator privileges. The + possible values are: + +Name Value Description +AF_OP_PRINT 0 Print operator + + +Leach, Naik [Page 28]
+ + +INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 + + +AF_OP_COMM 1 Communications operator +AF_OP_SERVER 2 Server operator +AF_OP_ACCOUNTS 3 Accounts operator + + + usri11_password_age specifies how many seconds have elapsed since the + password was last changed. + + usri11_home_dir points to a null terminated ASCII string that contains + the path name of the user's home directory. + + usri11_parms points to a null terminated ASCII string that is set + aside for use by applications. + + usri11_last_logon specifies the time when the user last logged on. + This value is stored as the number of seconds elapsed since + 00:00:00, January 1, 1970. + + usri11_last_logoff specifies the time when the user last logged off. + This value is stored as the number of seconds elapsed since + 00:00:00, January 1, 1970. A value of 0 means the last logoff + time is unknown. + + usri11_bad_pw_count specifies the number of incorrect passwords + entered since the last successful logon. + + usri11_log1_num_logons specifies the number of times this user has + logged on. A value of -1 means the number of logons is unknown. + + usri11_logon_server points to a null terminated ASCII string that + contains the name of the server to which logon requests are sent. + A null string indicates logon requests should be sent to the + domain controller. + + usri11_country_code specifies the country code for the user's language + of choice. + + usri11_workstations points to a null terminated ASCII string that + contains the names of workstations the user may log on from. + There may be up to 8 workstations, with the names separated by + commas. A null strings indicates there are no restrictions. + + usri11_max_storage specifies the maximum amount of disk space the user + can occupy. A value of 0xffffffff indicates there are no + restrictions. + + usri11_units_per_week specifies the equal number of time units into + which a week is divided. This value must be equal to 168. + + usri11_logon_hours points to a 21 byte (168 bits) string that + specifies the time during which the user can log on. Each bit + represents one unique hour in a week. The first bit (bit 0, word + 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is + + + +Leach, Naik [Page 29]
+ + +INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 + + + Sunday, 1:00 to 1:59 and so on. A null pointer indicates there + are no restrictions. + + usri11_code_page specifies the code page for the user's language of + choice + +All of the pointers in this data structure need to be treated +specially. The pointer is a 32 bit pointer. The higher 16 bits need +to be ignored. The converter word returned in the parameters section +needs to be subtracted from the lower 16 bits to calculate an offset +into the return buffer where this ASCII string resides. + +There is no auxiliary data in the response. + ****************************************************************************/ +#define usri11_name 0 +#define usri11_pad 21 +#define usri11_comment 22 +#define usri11_usr_comment 26 +#define usri11_full_name 30 +#define usri11_priv 34 +#define usri11_auth_flags 36 +#define usri11_password_age 40 +#define usri11_homedir 44 +#define usri11_parms 48 +#define usri11_last_logon 52 +#define usri11_last_logoff 56 +#define usri11_bad_pw_count 60 +#define usri11_num_logons 62 +#define usri11_logon_server 64 +#define usri11_country_code 68 +#define usri11_workstations 70 +#define usri11_max_storage 74 +#define usri11_units_per_week 78 +#define usri11_logon_hours 80 +#define usri11_code_page 84 +#define usri11_end 86 + #define USER_PRIV_GUEST 0 #define USER_PRIV_USER 1 #define USER_PRIV_ADMIN 2 +#define AF_OP_PRINT 0 +#define AF_OP_COMM 1 +#define AF_OP_SERVER 2 +#define AF_OP_ACCOUNTS 3 + static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data, int mdrcnt,int mprcnt, char **rdata,char **rparam, int *rdata_len,int *rparam_len) { - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; + char *str1 = param+2; + char *str2 = skip_string(str1,1); + char *UserName = skip_string(str2,1); + char *p = skip_string(UserName,1); + int uLevel = SVAL(p,0); + char *p2; + + *rparam_len = 6; + *rparam = REALLOC(*rparam,*rparam_len); + + /* check it's a supported varient */ + if (strcmp(str1,"zWrLh") != 0) return False; + switch( uLevel ) + { + case 0: p2 = "B21"; break; + case 1: p2 = "B21BB16DWzzWz"; break; + case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; + case 10: p2 = "B21Bzzz"; break; + case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break; + default: return False; + } - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); + if (strcmp(p2,str2) != 0) return False; - /* check it's a supported varient */ - if (strcmp(str1,"zWrLh") != 0) return False; - switch( uLevel ) { - case 0: p2 = "B21"; break; - case 1: p2 = "B21BB16DWzzWz"; break; - case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; - case 10: p2 = "B21Bzzz"; break; - case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break; - default: return False; - } - if (strcmp(p2,str2) != 0) return False; + *rdata_len = mdrcnt + 1024; + *rdata = REALLOC(*rdata,*rdata_len); - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); + SSVAL(*rparam,0,NERR_Success); + SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ + p = *rdata; + p2 = p + usri11_end; - p = *rdata; - p2 = p + 86; + memset(p,0,21); + strcpy(p+usri11_name,UserName); /* 21 bytes - user name */ - memset(p,0,21); - strcpy(p,UserName); - if (uLevel > 0) { - SCVAL(p,21,0); - *p2 = 0; - if (uLevel >= 10) { - SIVAL(p,22,PTR_DIFF(p2,p)); /* comment */ - strcpy(p2,"<Comment>"); - p2 = skip_string(p2,1); - SIVAL(p,26,PTR_DIFF(p2,p)); /* user_comment */ - strcpy(p2,"<UserComment>"); - p2 = skip_string(p2,1); - SIVAL(p,30,PTR_DIFF(p2,p)); /* full name */ - strcpy(p2,"<FullName>"); - p2 = skip_string(p2,1); - } - if (uLevel == 11) { /* modelled after NTAS 3.51 reply */ - SSVAL(p,34, - Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,36,0); /* auth flags */ - SIVALS(p,40,-1); /* password age */ - SIVAL(p,44,PTR_DIFF(p2,p)); /* home dir */ - if (*lp_logon_path()) - { - strcpy(p2,lp_logon_path()); - } - else - { - strcpy(p2,"\\\\%L\\HOMES"); - standard_sub_basic(p2); - } - p2 = skip_string(p2,1); - SIVAL(p,48,PTR_DIFF(p2,p)); /* parms */ - strcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,52,0); /* last logon */ - SIVAL(p,56,0); /* last logoff */ - SSVALS(p,60,-1); /* bad pw counts */ - SSVALS(p,62,-1); /* num logons */ - SIVAL(p,64,PTR_DIFF(p2,p)); /* logon server */ - strcpy(p2,"\\\\*"); - p2 = skip_string(p2,1); - SSVAL(p,68,0); /* country code */ - - SIVAL(p,70,PTR_DIFF(p2,p)); /* workstations */ - strcpy(p2,""); - p2 = skip_string(p2,1); - - SIVALS(p,74,-1); /* max storage */ - SSVAL(p,78,168); /* units per week */ - SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */ - memset(p2,-1,21); - SCVAL(p2,21,0); /* fix zero termination */ - p2 = skip_string(p2,1); - - SSVAL(p,84,0); /* code page */ - } - if (uLevel == 1 || uLevel == 2) { - memset(p+22,' ',16); /* password */ - SIVALS(p,38,-1); /* password age */ - SSVAL(p,42, - Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - if (*lp_logon_path()) - { - strcpy(p2,lp_logon_path()); - } - else - { - strcpy(p2,"\\\\%L\\HOMES"); - standard_sub_basic(p2); - } - p2 = skip_string(p2,1); - SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ - *p2++ = 0; - SSVAL(p,52,0); /* flags */ - SIVAL(p,54,0); /* script_path */ - if (uLevel == 2) { - SIVAL(p,60,0); /* auth_flags */ - SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */ - strcpy(p2,"<Full Name>"); - p2 = skip_string(p2,1); - SIVAL(p,68,0); /* urs_comment */ - SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */ - strcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,76,0); /* workstations */ - SIVAL(p,80,0); /* last_logon */ - SIVAL(p,84,0); /* last_logoff */ - SIVALS(p,88,-1); /* acct_expires */ - SIVALS(p,92,-1); /* max_storage */ - SSVAL(p,96,168); /* units_per_week */ - SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */ - memset(p2,-1,21); - p2 += 21; - SSVALS(p,102,-1); /* bad_pw_count */ - SSVALS(p,104,-1); /* num_logons */ - SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ - strcpy(p2,"\\\\%L"); - standard_sub_basic(p2); - p2 = skip_string(p2,1); - SSVAL(p,110,49); /* country_code */ - SSVAL(p,112,860); /* code page */ - } - } - } + if (uLevel > 0) + { + SCVAL(p,usri11_pad,0); /* padding - 1 byte */ + *p2 = 0; + } + if (uLevel >= 10) + { + SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */ + strcpy(p2,"Comment"); + p2 = skip_string(p2,1); + + SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */ + strcpy(p2,"UserComment"); + p2 = skip_string(p2,1); + + /* EEK! the cifsrap.txt doesn't have this in!!!! */ + SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */ +#if 0 + strcpy(p2,"FullName"); +#endif + strcpy(p2,UserName); /* suggest copying the user name, for now... */ + p2 = skip_string(p2,1); + } + if (uLevel == 11) /* modelled after NTAS 3.51 reply */ + { + SSVAL(p,usri11_priv,Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); + SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ + SIVALS(p,usri11_password_age,0xffffffff); /* password age */ + SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ + if (*lp_logon_path()) + { + strcpy(p2,lp_logon_path()); + } + else + { + strcpy(p2,"\\\\%L\\%U"); + } + standard_sub_basic(p2); + p2 = skip_string(p2,1); + SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ + strcpy(p2,""); + p2 = skip_string(p2,1); + SIVAL(p,usri11_last_logon,0); /* last logon */ + SIVAL(p,usri11_last_logoff,0); /* last logoff */ + SSVALS(p,usri11_bad_pw_count,0xffffffff); /* bad pw counts */ + SSVALS(p,usri11_num_logons,0xffffffff); /* num logons */ + SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */ + strcpy(p2,"\\\\*"); + p2 = skip_string(p2,1); + SSVAL(p,usri11_country_code,0); /* country code */ + + SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */ + strcpy(p2,""); + p2 = skip_string(p2,1); + + SIVALS(p,usri11_max_storage,0xffffffff); /* max storage */ + SSVAL(p,usri11_units_per_week,168); /* units per week */ + SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */ + + /* a simple way to get logon hours at all times. */ + memset(p2,0xff,21); + SCVAL(p2,21,0); /* fix zero termination */ + p2 = skip_string(p2,1); + + SSVAL(p,usri11_code_page,0); /* code page */ + } + if (uLevel == 1 || uLevel == 2) + { + memset(p+22,' ',16); /* password */ + SIVALS(p,38,-1); /* password age */ + SSVAL(p,42, + Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); + SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ + if (*lp_logon_path()) + { + strcpy(p2,lp_logon_path()); + } + else + { + strcpy(p2,"\\\\%L\\%U"); + } + standard_sub_basic(p2); + p2 = skip_string(p2,1); + SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ + *p2++ = 0; + SSVAL(p,52,0); /* flags */ + SIVAL(p,54,0); /* script_path */ + if (uLevel == 2) + { + SIVAL(p,60,0); /* auth_flags */ + SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */ + strcpy(p2,"<Full Name>"); + p2 = skip_string(p2,1); + SIVAL(p,68,0); /* urs_comment */ + SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */ + strcpy(p2,""); + p2 = skip_string(p2,1); + SIVAL(p,76,0); /* workstations */ + SIVAL(p,80,0); /* last_logon */ + SIVAL(p,84,0); /* last_logoff */ + SIVALS(p,88,-1); /* acct_expires */ + SIVALS(p,92,-1); /* max_storage */ + SSVAL(p,96,168); /* units_per_week */ + SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */ + memset(p2,-1,21); + p2 += 21; + SSVALS(p,102,-1); /* bad_pw_count */ + SSVALS(p,104,-1); /* num_logons */ + SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ + strcpy(p2,"\\\\%L"); + standard_sub_basic(p2); + p2 = skip_string(p2,1); + SSVAL(p,110,49); /* country_code */ + SSVAL(p,112,860); /* code page */ + } + } - *rdata_len = PTR_DIFF(p2,*rdata); + *rdata_len = PTR_DIFF(p2,*rdata); - SSVAL(*rparam,4,*rdata_len); /* is this right?? */ + SSVAL(*rparam,4,*rdata_len); /* is this right?? */ - return(True); + return(True); } - /******************************************************************* get groups that a user is a member of ******************************************************************/ @@ -2016,9 +2193,8 @@ static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data, desc.subformat = NULL; desc.format = str2; - - - if (init_package(&desc,1,0)) { + if (init_package(&desc,1,0)) + { PACKI(&desc,"W",0); /* code */ PACKS(&desc,"B21",name); /* eff. name */ PACKS(&desc,"B",""); /* pad */ @@ -2027,7 +2203,7 @@ static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data, PACKI(&desc,"D",0); /* auth flags XXX */ PACKI(&desc,"W",0); /* num logons */ PACKI(&desc,"W",0); /* bad pw count */ - PACKI(&desc,"D",-1); /* last logon */ + PACKI(&desc,"D",0); /* last logon */ PACKI(&desc,"D",-1); /* last logoff */ PACKI(&desc,"D",-1); /* logoff time */ PACKI(&desc,"D",-1); /* kickoff time */ @@ -2043,7 +2219,7 @@ static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data, } PACKS(&desc,"z",lp_workgroup());/* domain */ PACKS(&desc,"z",lp_logon_script()); /* script path */ - PACKI(&desc,"D",0); /* reserved */ + PACKI(&desc,"D",0x00000000); /* reserved */ } *rdata_len = desc.usedlen; diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 1abcb8089f..57611553cc 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2659,32 +2659,67 @@ int reply_lanman2(char *outbuf) return (smb_len(outbuf)+4); } + /**************************************************************************** reply for the nt protocol ****************************************************************************/ int reply_nt1(char *outbuf) { - int capabilities=0x300; /* has dual names + lock_and_read */ + /* dual names + lock_and_read + nt SMBs + remote API calls */ + int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ; +/* + other valid capabilities which we may support at some time... + CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; + CAP_LARGE_FILES|CAP_LARGE_READX| + CAP_STATUS32|CAP_LEVEL_II_OPLOCKS; + */ + int secword=0; BOOL doencrypt = SMBENCRYPT(); time_t t = time(NULL); + int data_len; + int encrypt_len; + char challenge_len = 8; + + if (lp_readraw() && lp_writeraw()) + { + capabilities |= CAP_RAW_MODE; + } if (lp_security()>=SEC_USER) secword |= 1; if (doencrypt) secword |= 2; - set_message(outbuf,17,doencrypt?8:0,True); + /* decide where (if) to put the encryption challenge, and + follow it with the OEM'd domain name + */ + encrypt_len = doencrypt?challenge_len:0; +#if UNICODE + data_len = encrypt_len + 2*(strlen(lp_workgroup())+1); +#else + data_len = encrypt_len + strlen(lp_workgroup()) + 1; +#endif + + set_message(outbuf,17,data_len,True); + +#if UNICODE + /* put the OEM'd domain name */ + PutUniCode(smb_buf(outbuf)+encrypt_len,lp_workgroup()); +#else + strcpy(smb_buf(outbuf)+encrypt_len, lp_workgroup()); +#endif + CVAL(outbuf,smb_vwv1) = secword; #ifdef SMB_PASSWD /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) { + if (doencrypt) + { generate_next_challenge(smb_buf(outbuf)); + /* Tell the nt machine how long the challenge is. */ - SSVALS(outbuf,smb_vwv16+1,8); + SSVALS(outbuf,smb_vwv16+1,challenge_len); } #endif - SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */ - Protocol = PROTOCOL_NT1; if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { @@ -2694,21 +2729,19 @@ int reply_nt1(char *outbuf) #endif } - if (lp_readraw() && lp_writeraw()) - capabilities |= 1; - SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ - SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */ - SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */ + SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */ + SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */ + SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ put_long_date(outbuf+smb_vwv11+1,t); SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60); + SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */ return (smb_len(outbuf)+4); } - /* these are the protocol lists used for auto architecture detection: WinNT 3.51: |