1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

1) updated ipc.c NetUserGetInfo - load \\%L\%U instead of \\%L\HOMES

because the share must be browseable by a w95 client

2) send_mailslot_reply - unique or group datagram argument added.

3) netlogon.c - rewrote response packet to do the right thing for w95.

4) server.c reply_nt1() - added OEMDomainstring to the end.

5) (deep breath) reworked the nmbd-browsing code a little bit.
   i discovered two months ago that becoming a primary domain controller
   (and domain master browser) is done independently of becoming a
   backup domain controller (logon server) is done independently of
   becoming a local master browser.

   therefore, three sets of state-machines (instead of just one) are in
   place - each of which is responsible for taking samba through the
   required stages to become:  a logon server; a domain master browser;
   and a local master browser.

   each of these three things can occur independently on each interface,
   _including_ the wins pseudo-interface.  the only slight caveat is that
   the wins pseudo-interface, by virtue of _not_ being a broadcast
   interface, does _not_ register as a local master browser with the wins
   server, as this doesn't make sense.

lkcl
This commit is contained in:
Samba Release Account 0001-01-01 00:00:00 +00:00
parent ebaff730c9
commit 88c6a00c3c
13 changed files with 832 additions and 386 deletions

View File

@ -73,7 +73,8 @@
/* server type identifiers */ /* server type identifiers */
#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER) #define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_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 */ /* microsoft browser NetBIOS name */
#define MSBROWSE "\001\002__MSBROWSE__\002" #define MSBROWSE "\001\002__MSBROWSE__\002"
@ -85,16 +86,27 @@
enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL}; 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 node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET}; enum packet_type {NMB_PACKET, DGRAM_PACKET};
enum master_state enum master_state
{ {
MST_NONE, MST_POTENTIAL,
MST_WON, MST_BACK,
MST_MSB, MST_MSB,
MST_BROWSER, MST_BROWSER
MST_DOMAIN_NONE, };
MST_DOMAIN_MEM,
MST_DOMAIN_TST, enum domain_state
MST_DOMAIN {
DOMAIN_NONE,
DOMAIN_WAIT,
DOMAIN_MST
};
enum logon_state
{
LOGON_NONE,
LOGON_WAIT,
LOGON_SRV
}; };
enum state_type enum state_type
@ -179,8 +191,14 @@ struct work_record
struct server_record *serverlist; struct server_record *serverlist;
/* stage of development from non-master to master browser / domain master */ /* stage of development from non-local-master up to local-master browser */
enum master_state state; 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 */ /* work group info */
fstring work_group; fstring work_group;
@ -367,6 +385,9 @@ struct packet_struct
/* broadcast packet announcement intervals, in minutes */ /* 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, /* search for master browsers of workgroups samba knows about,
except default */ except default */
#define CHECK_TIME_MST_BROWSE 5 #define CHECK_TIME_MST_BROWSE 5

View File

@ -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_unregister_work(struct subnet_record *d, char *name, int name_type);
void name_register_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); 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_local_master(struct subnet_record *d, struct work_record *work);
void become_nonmaster(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); int remove_type);
void run_elections(time_t t); void run_elections(time_t t);
void process_election(struct packet_struct *p,char *buf); 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 queue_packet(struct packet_struct *packet);
void run_packet_queue(); void run_packet_queue();
void listen_for_packets(BOOL run_election); 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, char *dstname,int src_type,int dest_type,
struct in_addr dest_ip,struct in_addr src_ip); 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 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_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 add_my_names(void);
void remove_my_names(); void remove_my_names();
void refresh_my_names(time_t t); void refresh_my_names(time_t t);

View File

@ -797,6 +797,21 @@ char *Strstr(char *s, char *p);
/* what server type are we currently */ /* 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 /* protocol types. It assumes that higher protocols include lower protocols
as subsets */ as subsets */
enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1}; enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1};

View File

@ -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 of 0x1e, then we could get the master browser to announce to
us instead of the members of the workgroup. wha-hey! */ 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)); 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); strupper(p);
p = skip_string(p,1); 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)); 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)); debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
/* send the announcement */ /* send the announcement */
send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf,
PTR_DIFF(p,outbuf), PTR_DIFF(p,outbuf),
from_name, to_name, from_name, to_name,
from_type, to_type, from_type, to_type,

View File

@ -91,7 +91,9 @@ static struct work_record *make_workgroup(char *name)
work->ElectionCount = 0; work->ElectionCount = 0;
work->needelection = False; work->needelection = False;
work->needannounce = True; 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 */ /* make sure all token representations of workgroups are unique */

View File

@ -51,6 +51,7 @@ extern struct subnet_record *subnetlist;
extern uint16 nb_type; /* samba's NetBIOS name type */ extern uint16 nb_type; /* samba's NetBIOS name type */
/******************************************************************* /*******************************************************************
occasionally check to see if the master browser is around 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); strupper(p);
p = skip_string(p,1); 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)); 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) void name_unregister_work(struct subnet_record *d, char *name, int name_type)
{ {
struct work_record *work; 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); remove_netbios_name(d,name,name_type,SELF,ipzero);
if (!(work = find_workgroupstruct(d, name, False))) return; if (!(work = find_workgroupstruct(d, name, False))) return;
if (ms_browser_name(name, name_type) || /* work out what to unbecome, from the name type being removed */
(AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
(name_type == 0x1d || name_type == 0x1b))) if (ms_browser_name(name, name_type))
{ {
int remove_type = 0; remove_type_local |= SV_TYPE_MASTER_BROWSER;
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);
} }
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)
{
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)
{ {
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. 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; 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, this is done in stages. note that this could take a while,
particularly on a broadcast subnet, as we have to wait for particularly on a broadcast subnet, as we have to wait for
the implicit registration of each name to be accepted. 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 called again, in order to initiate the next stage. see
dead_netbios_entry() - deals with implicit name registration dead_netbios_entry() - deals with implicit name registration
and response_name_reg() - deals with explicit registration and response_name_reg() - deals with explicit registration
with a WINS server. with a WINS server.
stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1. stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d) stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b) stage 3: was MST_MSB - go to MST_BROWSER and stay there
stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
XXXX note: this code still does not cope with the distinction XXXX note: this code still does not cope with the distinction
between different types of nodes, particularly between M and P between different types of nodes, particularly between M and P
nodes. that comes later. 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 /* 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 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; 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", 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")); 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; 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); add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
/* DON'T do anything else after calling add_my_name_entry() */ /* 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")); 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 on successful registration of MSBROWSE */
add_server_entry(d,work,work->work_group,domain_type,0,myname,True); 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); add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
/* DON'T do anything else after calling add_my_name_entry() */ /* DON'T do anything else after calling add_my_name_entry() */
return; break;
} }
case MST_MSB: /* while we were still only registered MSBROWSE state... */ case MST_MSB: /* while we were still only registered MSBROWSE state... */
{ {
DEBUG(3,("2nd stage complete: registered as master browser\n")); 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 */ /* update our server status */
work->ServerType |= SV_TYPE_MASTER_BROWSER; work->ServerType |= SV_TYPE_MASTER_BROWSER;
@ -322,114 +354,17 @@ void become_master(struct subnet_record *d, struct work_record *work)
if (work->serverlist == NULL) /* no servers! */ if (work->serverlist == NULL) /* no servers! */
{ {
/* ask all servers on our local net to announce to us */ /* 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); announce_request(work, d->bcast_ip);
} }
break; break;
} }
case MST_BROWSER: case MST_BROWSER:
{ {
/* don't have to do anything: just report success */ /* don't have to do anything: just report success */
DEBUG(3,("3rd stage: become master browser!\n")); DEBUG(3,("3rd stage: become master browser!\n"));
break;
}
case MST_DOMAIN_NONE:
{
if (lp_domain_master())
{
work->state = MST_DOMAIN_MEM; /* ... become domain member */
DEBUG(3,("domain first stage: register as domain member\n"));
/* add domain member name */
add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
/* DON'T do anything else after calling add_my_name_entry() */
return;
}
else
{
DEBUG(4,("samba not configured as a domain master.\n"));
}
break;
}
case MST_DOMAIN_MEM:
{
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);
}
/* add domain master name */
add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE );
/* DON'T do anything else after calling add_my_name_entry() */
return;
}
else
{
DEBUG(4,("samba not configured as a domain master.\n"));
}
break;
}
case MST_DOMAIN_TST: /* while we were still a master browser... */
{
/* update our server status */
if (lp_domain_master())
{
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 */
update_type |= DFLT_SERVER_TYPE | SV_TYPE_DOMAIN_MASTER |
SV_TYPE_POTENTIAL_BROWSER;
work->ServerType |= update_type;
add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
for (d1 = subnetlist; d1; d1 = d1->next)
{
struct work_record *w;
if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue;
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));
}
}
}
}
break;
}
case MST_DOMAIN:
{
/* don't have to do anything: just report success */
DEBUG(3,("fifth stage: there isn't one yet!\n"));
break; break;
} }
} }
@ -437,52 +372,250 @@ void become_master(struct subnet_record *d, struct work_record *work)
/******************************************************************* /*******************************************************************
unbecome the master browser. initates removal of necessary netbios become the domain master browser.
names, and tells the world that we are no longer a 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_nonmaster(struct subnet_record *d, struct work_record *work, 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())
{
DEBUG(3,("go to first stage: register <1b> name\n"));
work->dom_state = DOMAIN_WAIT;
/* 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() */
break;
}
else
{
DEBUG(4,("samba not configured as a domain master.\n"));
}
break;
}
case DOMAIN_WAIT:
{
if (lp_domain_master())
{
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);
DEBUG(4,("samba is now a domain master\n"));
break;
}
else
{
DEBUG(4,("samba not configured as a domain master.\n"));
}
break;
}
case DOMAIN_MST:
{
/* don't have to do anything: just report success */
DEBUG(3,("domain second stage: there isn't one!\n"));
break;
}
}
}
/*******************************************************************
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... */
{
if (lp_domain_logons())
{
DEBUG(3,("go to first stage: register <1c> name\n"));
work->log_state = LOGON_WAIT;
/* 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);
/* DON'T do anything else after calling add_my_name_entry() */
break;
}
{
DEBUG(4,("samba not configured as a logon master.\n"));
}
break;
}
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);
/* 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 LOGON_SRV:
{
DEBUG(3,("logon third stage: there isn't one!\n"));
break;
}
}
}
/*******************************************************************
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 unbecome_local_master(struct subnet_record *d, struct work_record *work,
int remove_type) int remove_type)
{ {
int new_server_type = work->ServerType; int new_server_type = work->ServerType;
DEBUG(2,("Becoming non-master for %s\n",work->work_group)); /* can only remove master types with this function */
remove_type &= SV_TYPE_MASTER_BROWSER;
/* 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;
new_server_type &= ~remove_type; 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 */ /* no longer a master browser of any sort */
work->ServerType |= SV_TYPE_POTENTIAL_BROWSER; work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
work->ElectionCriterion &= ~0x4; work->ElectionCriterion &= ~0x4;
work->state = MST_NONE; work->mst_state = MST_POTENTIAL;
/* announce ourselves as no longer active as a master browser. */ /* announce ourselves as no longer active as a master browser. */
announce_server(d, work, work->work_group, myname, 0, 0); announce_server(d, work, work->work_group, myname, 0, 0);
remove_name_entry(d,MSBROWSE ,0x01); remove_name_entry(d,MSBROWSE ,0x01);
remove_name_entry(d,work->work_group,0x1d);
} }
}
work->ServerType = new_server_type;
if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER)) /*******************************************************************
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));
/* can only remove master or domain types with this function */
remove_type &= SV_TYPE_DOMAIN_MASTER;
new_server_type &= ~remove_type;
if (remove_type)
{ {
if (work->state == MST_DOMAIN) /* no longer a domain master browser of any sort */
work->state = MST_BROWSER;
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); remove_name_entry(d,work->work_group,0x1b);
} }
}
if (!(work->ServerType & SV_TYPE_MASTER_BROWSER))
/*******************************************************************
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;
new_server_type &= ~remove_type;
if (remove_type)
{ {
if (work->state >= MST_BROWSER) /* no longer a master browser of any sort */
work->state = MST_NONE;
remove_name_entry(d,work->work_group,0x1d); 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->work_group,inet_ntoa(d->bcast_ip)));
work->RunningElection = False; 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) { if (!work->RunningElection) {
work->needelection = True; work->needelection = True;
work->ElectionCount=0; work->ElectionCount=0;
work->state = MST_NONE; work->mst_state = MST_POTENTIAL;
} }
} else { } else {
work->needelection = False; work->needelection = False;
@ -608,9 +741,7 @@ void process_election(struct packet_struct *p,char *buf)
DEBUG(3,(">>> Lost election on %s %s <<<\n", DEBUG(3,(">>> Lost election on %s %s <<<\n",
work->work_group,inet_ntoa(d->bcast_ip))); work->work_group,inet_ntoa(d->bcast_ip)));
if (AM_MASTER(work)) if (AM_MASTER(work))
become_nonmaster(d, work, unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
SV_TYPE_MASTER_BROWSER|
SV_TYPE_DOMAIN_MASTER);
} }
} }
} }

View File

@ -54,86 +54,101 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len)
pstring outbuf; pstring outbuf;
int code,reply_code; int code,reply_code;
struct work_record *work; struct work_record *work;
char unknown_byte = 0;
uint16 request_count = 0;
uint16 token = 0;
if (!d) return; if (!d) return;
if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) return;
return;
if (!lp_domain_logons()) { if (!lp_domain_logons())
{
DEBUG(3,("No domain logons\n")); DEBUG(3,("No domain logons\n"));
return; return;
} }
code = SVAL(buf,0); code = SVAL(buf,0);
switch (code) { switch (code)
{
case 0: case 0:
{ {
char *machine = buf+2; char *machine = buf+2;
char *user = skip_string(machine,1); char *user = skip_string(machine,1);
char *tmp;
logname = skip_string(user,1); 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); strcpy(reply_name,myname);
strupper(reply_name); strupper(reply_name);
add_slashes = True; add_slashes = True;
DEBUG(3,("Domain login request from %s(%s) user=%s\n", DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n",
machine,inet_ntoa(p->ip),user)); machine,inet_ntoa(p->ip),user,token));
}
break; break;
}
case 7: case 7:
{ {
char *machine = buf+2; char *machine = buf+2;
logname = skip_string(machine,1); logname = skip_string(machine,1);
reply_code = 7; token = SVAL(skip_string(logname,1),0);
strcpy(reply_name,lp_domain_controller()); strcpy(reply_name,lp_domain_controller());
if (!*reply_name) { if (!*reply_name)
{
/* oo! no domain controller. must be us, then */
strcpy(reply_name,myname); strcpy(reply_name,myname);
reply_code = 0xC; reply_code = 0xC;
} }
strupper(reply_name); else
DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%2x\n", {
machine,inet_ntoa(p->ip), reply_name, reply_code)); /* 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; break;
}
default: default:
{
DEBUG(3,("Unknown domain request %d\n",code)); DEBUG(3,("Unknown domain request %d\n",code));
return; return;
} }
}
bzero(outbuf,sizeof(outbuf)); bzero(outbuf,sizeof(outbuf));
q = outbuf; q = outbuf;
SSVAL(q,0,reply_code); SSVAL(q,0,reply_code);
q += 2; q += 2;
if (add_slashes) {
if (token == 0xffff || /* LM 2.0 or later */
token == 0xfffe) /* WfWg networking */
{
if (add_slashes)
{
strcpy(q,"\\\\"); strcpy(q,"\\\\");
q += 2; q += 2;
} }
StrnCpy(q,reply_name,16); strcpy(q, reply_name);
strupper(q);
q = skip_string(q,1); q = skip_string(q,1);
if (reply_code == 0xC) if (token == 0xffff) /* LM 2.0 or later */
{
if ( PTR_DIFF (q,outbuf) & 1 )
{ {
q++; SSVAL(q,0,token);
}
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);
q += 2; q += 2;
} }
}
SSVAL(q,0,0xFFFF); SSVAL(q,0,0xFFFF);
q += 2; 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, myname,&dgram->source_name.name[0],0x20,0,p->ip,
*iface_ip(p->ip)); *iface_ip(p->ip));
} }

View File

@ -559,7 +559,7 @@ void listen_for_packets(BOOL run_election)
Note that this currently sends all answers to port 138. thats the Note that this currently sends all answers to port 138. thats the
wrong things to do! I should send to the requestors port. XXX 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, char *dstname,int src_type,int dest_type,
struct in_addr dest_ip,struct in_addr src_ip) 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(); 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.node_type = M_NODE;
dgram->header.flags.first = True; dgram->header.flags.first = True;
dgram->header.flags.more = False; dgram->header.flags.more = False;

View File

@ -155,6 +155,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 add the magic samba names, useful for finding samba servers
**************************************************************************/ **************************************************************************/
@ -170,6 +215,7 @@ void add_my_names(void)
for (d = subnetlist; d; d = d->next) for (d = subnetlist; d; d = d->next)
{ {
BOOL wins = lp_wins_support() && ip_equal(d->bcast_ip,ipgrp); 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,0x20,nb_type|NB_ACTIVE);
add_my_name_entry(d, myname,0x03,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__",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); add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,d->myip,False,wins);
if (lp_domain_logons()) { if (lp_domain_logons() && work && work->log_state == LOGON_NONE)
/* 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_master() && (d = find_subnet(ipgrp)))
{
struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True);
if (work && work->state == MST_NONE)
{ {
work->state = MST_DOMAIN_NONE; become_logon_server(d, work);
become_master(d, work); }
if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE)
{
become_domain_master(d, work);
} }
} }
} }

View File

@ -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", DEBUG(2,("sending reset to %s %s of state %d\n",
name,inet_ntoa(ip),state)); 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)); 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); int len = PTR_DIFF(p, outbuf);
debug_browse_data(outbuf, len); 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)); 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)) 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);
} }
} }
} }

View File

@ -300,9 +300,7 @@ static void process(void)
run_elections(t); run_elections(t);
announce_host(t); announce_host(t);
announce_master(t); announce_master(t);
announce_remote(t); announce_remote(t);
query_refresh_names(t); query_refresh_names(t);
@ -314,6 +312,7 @@ static void process(void)
write_browse_list(t); write_browse_list(t);
do_browser_lists(t); do_browser_lists(t);
check_master_browser(t); check_master_browser(t);
add_domain_names(t);
} }
} }

View File

@ -1,3 +1,4 @@
/* /*
Unix SMB/Netbios implementation. Unix SMB/Netbios implementation.
Version 1.9. 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) { if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
for (i=0;i<count;i++) for (i=0;i<count;i++)
if (strequal(servers[i].name,local_machine)) { if (strequal(servers[i].name,local_machine))
{
servertype = servers[i].type; servertype = servers[i].type;
strcpy(comment,servers[i].comment); strcpy(comment,servers[i].comment);
} }
@ -1742,8 +1744,10 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
p = *rdata; p = *rdata;
p2 = p + 22; p2 = p + 22;
SIVAL(p,0,PTR_DIFF(p2,*rdata));
SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
strcpy(p2,local_machine); strcpy(p2,local_machine);
strupper(p2);
p2 = skip_string(p2,1); p2 = skip_string(p2,1);
p += 4; p += 4;
@ -1752,21 +1756,22 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
p2 = skip_string(p2,1); p2 = skip_string(p2,1);
p += 4; p += 4;
SIVAL(p,0,PTR_DIFF(p2,*rdata)); SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
strcpy(p2,lp_workgroup()); strcpy(p2,lp_workgroup());
strupper(p2);
p2 = skip_string(p2,1); p2 = skip_string(p2,1);
p += 4; p += 4;
SCVAL(p,0,MAJOR_VERSION); SCVAL(p,0,MAJOR_VERSION); /* system version - e.g 4 in 4.1 */
SCVAL(p,1,MINOR_VERSION); SCVAL(p,1,MINOR_VERSION); /* system version - e.g .1 in 4.1 */
p += 2; p += 2;
SIVAL(p,0,PTR_DIFF(p2,*rdata)); 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); p2 = skip_string(p2,1);
p += 4; p += 4;
SIVAL(p,0,PTR_DIFF(p2,*rdata)); SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
strcpy(p2,""); strcpy(p2,"");
p2 = skip_string(p2,1); p2 = skip_string(p2,1);
p += 4; p += 4;
@ -1778,166 +1783,338 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
return(True); return(True);
} }
/**************************************************************************** /****************************************************************************
get info about a user 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_GUEST 0
#define USER_PRIV_USER 1 #define USER_PRIV_USER 1
#define USER_PRIV_ADMIN 2 #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, static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt, int mdrcnt,int mprcnt,
char **rdata,char **rparam, char **rdata,char **rparam,
int *rdata_len,int *rparam_len) int *rdata_len,int *rparam_len)
{ {
char *str1 = param+2; char *str1 = param+2;
char *str2 = skip_string(str1,1); char *str2 = skip_string(str1,1);
char *UserName = skip_string(str2,1); char *UserName = skip_string(str2,1);
char *p = skip_string(UserName,1); char *p = skip_string(UserName,1);
int uLevel = SVAL(p,0); int uLevel = SVAL(p,0);
char *p2; char *p2;
*rparam_len = 6; *rparam_len = 6;
*rparam = REALLOC(*rparam,*rparam_len); *rparam = REALLOC(*rparam,*rparam_len);
/* check it's a supported varient */ /* check it's a supported varient */
if (strcmp(str1,"zWrLh") != 0) return False; if (strcmp(str1,"zWrLh") != 0) return False;
switch( uLevel ) { switch( uLevel )
case 0: p2 = "B21"; break; {
case 1: p2 = "B21BB16DWzzWz"; break; case 0: p2 = "B21"; break;
case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; case 1: p2 = "B21BB16DWzzWz"; break;
case 10: p2 = "B21Bzzz"; break; case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break; case 10: p2 = "B21Bzzz"; break;
default: return False; case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
} default: return False;
if (strcmp(p2,str2) != 0) return False; }
*rdata_len = mdrcnt + 1024; if (strcmp(p2,str2) != 0) return False;
*rdata = REALLOC(*rdata,*rdata_len);
SSVAL(*rparam,0,NERR_Success); *rdata_len = mdrcnt + 1024;
SSVAL(*rparam,2,0); /* converter word */ *rdata = REALLOC(*rdata,*rdata_len);
p = *rdata; SSVAL(*rparam,0,NERR_Success);
p2 = p + 86; SSVAL(*rparam,2,0); /* converter word */
memset(p,0,21); p = *rdata;
strcpy(p,UserName); p2 = p + usri11_end;
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 */ memset(p,0,21);
strcpy(p2,""); strcpy(p+usri11_name,UserName); /* 21 bytes - user name */
p2 = skip_string(p2,1);
SIVALS(p,74,-1); /* max storage */ if (uLevel > 0)
SSVAL(p,78,168); /* units per week */ {
SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */ SCVAL(p,usri11_pad,0); /* padding - 1 byte */
memset(p2,-1,21); *p2 = 0;
SCVAL(p2,21,0); /* fix zero termination */ }
p2 = skip_string(p2,1); if (uLevel >= 10)
{
SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
strcpy(p2,"Comment");
p2 = skip_string(p2,1);
SSVAL(p,84,0); /* code page */ SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
} strcpy(p2,"UserComment");
if (uLevel == 1 || uLevel == 2) { p2 = skip_string(p2,1);
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 */
}
}
}
*rdata_len = PTR_DIFF(p2,*rdata); /* 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 */
SSVAL(*rparam,4,*rdata_len); /* is this right?? */ SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
strcpy(p2,"");
p2 = skip_string(p2,1);
return(True); 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);
SSVAL(*rparam,4,*rdata_len); /* is this right?? */
return(True);
} }
/******************************************************************* /*******************************************************************
get groups that a user is a member of 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.subformat = NULL;
desc.format = str2; desc.format = str2;
if (init_package(&desc,1,0))
{
if (init_package(&desc,1,0)) {
PACKI(&desc,"W",0); /* code */ PACKI(&desc,"W",0); /* code */
PACKS(&desc,"B21",name); /* eff. name */ PACKS(&desc,"B21",name); /* eff. name */
PACKS(&desc,"B",""); /* pad */ 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,"D",0); /* auth flags XXX */
PACKI(&desc,"W",0); /* num logons */ PACKI(&desc,"W",0); /* num logons */
PACKI(&desc,"W",0); /* bad pw count */ 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); /* last logoff */
PACKI(&desc,"D",-1); /* logoff time */ PACKI(&desc,"D",-1); /* logoff time */
PACKI(&desc,"D",-1); /* kickoff 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_workgroup());/* domain */
PACKS(&desc,"z",lp_logon_script()); /* script path */ PACKS(&desc,"z",lp_logon_script()); /* script path */
PACKI(&desc,"D",0); /* reserved */ PACKI(&desc,"D",0x00000000); /* reserved */
} }
*rdata_len = desc.usedlen; *rdata_len = desc.usedlen;

View File

@ -2659,32 +2659,67 @@ int reply_lanman2(char *outbuf)
return (smb_len(outbuf)+4); return (smb_len(outbuf)+4);
} }
/**************************************************************************** /****************************************************************************
reply for the nt protocol reply for the nt protocol
****************************************************************************/ ****************************************************************************/
int reply_nt1(char *outbuf) 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; int secword=0;
BOOL doencrypt = SMBENCRYPT(); BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL); 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 (lp_security()>=SEC_USER) secword |= 1;
if (doencrypt) secword |= 2; 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; CVAL(outbuf,smb_vwv1) = secword;
#ifdef SMB_PASSWD #ifdef SMB_PASSWD
/* Create a token value and add it to the outgoing packet. */ /* Create a token value and add it to the outgoing packet. */
if (doencrypt) { if (doencrypt)
{
generate_next_challenge(smb_buf(outbuf)); generate_next_challenge(smb_buf(outbuf));
/* Tell the nt machine how long the challenge is. */ /* Tell the nt machine how long the challenge is. */
SSVALS(outbuf,smb_vwv16+1,8); SSVALS(outbuf,smb_vwv16+1,challenge_len);
} }
#endif #endif
SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
Protocol = PROTOCOL_NT1; Protocol = PROTOCOL_NT1;
if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
@ -2694,21 +2729,19 @@ int reply_nt1(char *outbuf)
#endif #endif
} }
if (lp_readraw() && lp_writeraw())
capabilities |= 1;
SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */ SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */ SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */
SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
put_long_date(outbuf+smb_vwv11+1,t); put_long_date(outbuf+smb_vwv11+1,t);
SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60); SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */
return (smb_len(outbuf)+4); return (smb_len(outbuf)+4);
} }
/* these are the protocol lists used for auto architecture detection: /* these are the protocol lists used for auto architecture detection:
WinNT 3.51: WinNT 3.51: