JHT ==> Upgraded Samba to Windows NT Server version 4.1
[kai/samba.git] / source3 / smbd / ipc.c
index 3b2c55dc46b2121518adf9f8bb07ec4e0f25efbb..920284fc9f964cf5ba7ca74024e488d9d4837088 100644 (file)
@@ -24,8 +24,6 @@
    */
 
 #include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
 
 #ifdef CHECK_TYPES
 #undef CHECK_TYPES
@@ -61,8 +59,21 @@ extern fstring local_machine;
 #define SNLEN 15               /* service name length */
 #define QNLEN 12               /* queue name maximum length */
 
+#define MAJOR_VERSION 4
+#define MINOR_VERSION 1
+
 extern int Client;
 
+static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
+                           int mdrcnt,int mprcnt,
+                           char **rdata,char **rparam,
+                           int *rdata_len,int *rparam_len);
+static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
+                        int mdrcnt,int mprcnt,
+                        char **rdata,char **rparam,
+                        int *rdata_len,int *rparam_len);
+
+
 static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
 {
   pstring buf;
@@ -189,12 +200,6 @@ static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
     }
 }
 
-
-
-/****************************************************************************
-  get a print queue
-  ****************************************************************************/
-
 struct pack_desc {
   char* format;            /* formatstring for structure */
   char* subformat;  /* subformat for structure */
@@ -418,6 +423,11 @@ static void PACKS(struct pack_desc* desc,char *t,char *v)
   PACK(desc,t,v);
 }
 
+
+/****************************************************************************
+  get a print queue
+  ****************************************************************************/
+
 static void PackDriverData(struct pack_desc* desc)
 {
   char drivdata[4+4+32];
@@ -545,7 +555,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
     PACKI(desc,"W",0);         /* uUntiltime */
     PACKI(desc,"W",5);         /* pad1 */
     PACKS(desc,"z","");                /* pszSepFile */
-    PACKS(desc,"z","lpd");     /* pszPrProc */
+    PACKS(desc,"z","WinPrint");        /* pszPrProc */
     PACKS(desc,"z","");                /* pszParms */
     if (!status || !status->message[0]) {
       PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
@@ -556,7 +566,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
     }
     PACKI(desc,(uLevel == 3 ? "W" : "N"),count);       /* cJobs */
     PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
-    PACKS(desc,"z","NULL");    /* pszDriverName */
+    PACKS(desc,"z",lp_printerdriver(snum));            /* pszDriverName */
     PackDriverData(desc);      /* pDriverData */
   }
   if (uLevel == 2 || uLevel == 4) {
@@ -593,6 +603,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
   cbBuf = SVAL(p,2);
   str3 = p + 4;
  
+  /* remove any trailing username */
   if ((p = strchr(QueueName,'%'))) *p = 0;
  
   DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
@@ -662,7 +673,7 @@ static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
 
   DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
  
-  if (prefix_ok(param_format,"WrLeh")) return False;
+  if (!prefix_ok(param_format,"WrLeh")) return False;
   if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
     return False;
   queuecnt = 0;
@@ -737,58 +748,23 @@ static BOOL check_server_info(int uLevel, char* id)
   return True;
 }
 
-/* used for server information: client, nameserv and ipc */
 struct srv_info_struct
 {
   fstring name;
   uint32 type;
   fstring comment;
-  fstring domain; /* used ONLY in ipc.c NOT namework.c */
-  BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
+  fstring domain;
+  BOOL server_added;
 };
 
-/*******************************************************************
-  filter out unwanted server info 
-  ******************************************************************/
-static BOOL filter_server_info(struct srv_info_struct *server, 
-                              char *domain)
-{
-  if (*domain)
-    return(strequal(domain, server->domain));
-  
-  return (True); /* be indiscriminate: get all servers! */
-}
-
-/*******************************************************************
-  find server in the files saved by nmbd. Return True if we find it.
-  ******************************************************************/
-static BOOL find_server(struct srv_info_struct *servers, int num_servers,
-                char *domain, char *name)
-{
-  int count;
-
-  if (!servers || num_servers == 0) return (False);
-
-  for (count = 0; count < num_servers; count++)        {
-    struct srv_info_struct *s;
-
-    s = &servers[count];
-
-    if (strequal(name, s->name)) {
-      StrnCpy(domain, s->domain, sizeof(pstring)-1);
-      return (True);
-    }
-  }
-  return (False);
-}
-
 
 /*******************************************************************
   get server info lists from the files saved by nmbd. Return the
   number of entries
   ******************************************************************/
 static int get_server_info(uint32 servertype, 
-                          struct srv_info_struct **servers)
+                          struct srv_info_struct **servers,
+                          char *domain)
 {
   FILE *f;
   pstring fname;
@@ -807,18 +783,23 @@ static int get_server_info(uint32 servertype,
     DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
     return(0);
   }
+
+  /* request for everything is code for request all servers */
   if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
 
+  DEBUG(4,("Servertype search: %8x\n",servertype));
+
   while (!feof(f))
   {
     fstring stype;
     struct srv_info_struct *s;
     char *ptr = line;
+    BOOL ok = True;
     *ptr = 0;
 
     fgets(line,sizeof(line)-1,f);
     if (!*line) continue;
-
+    
     if (count == alloced) {
       alloced += 10;
       (*servers) = (struct srv_info_struct *)
@@ -827,36 +808,58 @@ static int get_server_info(uint32 servertype,
       bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
     }
     s = &(*servers)[count];
-
-    s->server_added = True;
-
+    
     if (!next_token(&ptr,s->name   , NULL)) continue;
     if (!next_token(&ptr,stype     , NULL)) continue;
     if (!next_token(&ptr,s->comment, NULL)) continue;
     if (!next_token(&ptr,s->domain , NULL)) {
-      /* this allows us to cop with an old nmbd */
-      strcpy(s->domain,my_workgroup()); 
+      /* this allows us to cope with an old nmbd */
+      strcpy(s->domain,lp_workgroup()); 
     }
-
-    if (sscanf(stype,"%X",&s->type) != 1) continue;
-
+    
+    if (sscanf(stype,"%X",&s->type) != 1) { 
+      DEBUG(4,("r:host file ")); 
+      ok = False; 
+    }
+    
     /* doesn't match up: don't want it */
-    if (!(servertype & s->type)) continue;
-
-    /* server entry is a domain, we haven't asked for domains: don't want it */
-    if ((s->type&SV_TYPE_DOMAIN_ENUM) && !(servertype&SV_TYPE_DOMAIN_ENUM))
-      continue;
-
-    DEBUG(4,("Server %20s %8x %25s %15s\n",
-            s->name, stype, s->comment, s->domain));
-
-    count++;
+    if (!(servertype & s->type)) { 
+      DEBUG(4,("r:serv type ")); 
+      ok = False; 
+    }
+    
+    if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
+       (s->type & SV_TYPE_DOMAIN_ENUM))
+      {
+       DEBUG(4,("s: dom mismatch "));
+       ok = False;
+      }
+    
+    if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
+      {
+       ok = False;
+      }
+    
+    if (ok)
+      {
+       DEBUG(4,("**SV** %20s %8x %25s %15s\n",
+                s->name, s->type, s->comment, s->domain));
+       
+       s->server_added = True;
+       count++;
+      }
+    else
+      {
+       DEBUG(4,("%20s %8x %25s %15s\n",
+                s->name, s->type, s->comment, s->domain));
+      }
   }
-
+  
   fclose(f);
   return(count);
 }
 
+
 /*******************************************************************
   fill in a server info structure
   ******************************************************************/
@@ -936,6 +939,11 @@ static int fill_srv_info(struct srv_info_struct *service,
 }
 
 
+static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+{
+  return(strcmp(s1->name,s2->name));
+}
+
 /****************************************************************************
   view list of servers available (or possibly domains). The info is
   extracted from lists saved by nmbd on the local host
@@ -955,60 +963,59 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
   int f_len, s_len;
   struct srv_info_struct *servers=NULL;
   int counted=0,total=0;
-  int i;
+  int i,missed;
   fstring domain;
-  BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) &&
-                       !(servertype == SV_TYPE_ALL);
+  BOOL domain_request;
+  BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY;
+
+  if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
+
+  domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
 
-  domain[0] = 0;
   p += 8;
 
   if (!prefix_ok(str1,"WrLehD")) return False;
   if (!check_server_info(uLevel,str2)) return False;
   
-  DEBUG(4, ("server request level: %s\n", str2));
+  DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+  DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+  DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
 
-  if (strcmp(str1, "WrLehDO") == 0)
-  {
-    /* asking for servers. we will have to work out which workgroup was
-       requested, as we maintain lists for multiple workgroups */
-  }
-  else if (strcmp(str1, "WrLehDz") == 0)
-  {
-    /* asking for a specific workgroup */
+  if (strcmp(str1, "WrLehDz") == 0) {
     StrnCpy(domain, p, sizeof(fstring)-1);
+  } else {
+    StrnCpy(domain, lp_workgroup(), sizeof(fstring)-1);    
   }
 
   if (lp_browse_list())
-  {
-    total = get_server_info(servertype,&servers);
-  }
-
-  if (!domain[0] && !domain_request) {
-    extern fstring remote_machine;
-    /* must be a server request with an assumed domain. find a domain */
-    
-    if (find_server(servers, total, domain, remote_machine)) {
-      DEBUG(4, ("No domain specified: using %s for %s\n",
-               domain, remote_machine));
-    } else {
-      /* default to soemthing sensible */
-      strcpy(domain,my_workgroup());
-    }
-  }
+    total = get_server_info(servertype,&servers,domain);
 
   data_len = fixed_len = string_len = 0;
+  missed = 0;
 
-  for (i=0;i<total;i++)
-    if (filter_server_info(&servers[i],domain)) {
-      data_len += fill_srv_info(&servers[i],uLevel,0,&f_len,0,&s_len,0);
-      if (data_len <= buf_len)
-       {
+  qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+
+  {
+    char *lastname=NULL;
+
+    for (i=0;i<total;i++)
+    {
+      struct srv_info_struct *s = &servers[i];
+      if (lastname && strequal(lastname,s->name)) continue;
+      lastname = s->name;
+      data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+      DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+              s->name, s->type, s->comment, s->domain));
+      
+      if (data_len <= buf_len) {
          counted++;
          fixed_len += f_len;
          string_len += s_len;
-       }
+      } else {
+       missed++;
+      }
     }
+  }
 
   *rdata_len = fixed_len + string_len;
   *rdata = REALLOC(*rdata,*rdata_len);
@@ -1020,13 +1027,18 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
   s_len = string_len;
 
   {
+    char *lastname=NULL;
     int count2 = counted;
-    for (i = 0; i < total && count2;i++) {
-      if (filter_server_info(&servers[i],domain)) {
-       fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata);
+    for (i = 0; i < total && count2;i++)
+      {
+       struct srv_info_struct *s = &servers[i];
+       if (lastname && strequal(lastname,s->name)) continue;
+       lastname = s->name;
+       fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+                s->name, s->type, s->comment, s->domain));
        count2--;
       }
-    }
   }
   
   *rparam_len = 8;
@@ -1034,12 +1046,12 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
   SSVAL(*rparam,0,NERR_Success);
   SSVAL(*rparam,2,0);
   SSVAL(*rparam,4,counted);
-  SSVAL(*rparam,6,total);
+  SSVAL(*rparam,6,counted+missed);
 
   if (servers) free(servers);
 
   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
-          domain,uLevel,counted,total));
+          domain,uLevel,counted,counted+missed));
 
   return(True);
 }
@@ -1332,14 +1344,16 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
 
   *rdata_len = 0;
 
-  SSVAL(*rparam,0,NERR_Success);
+  SSVAL(*rparam,0,NERR_badpass);
   SSVAL(*rparam,2,0);          /* converter word */
 
   DEBUG(3,("Set password for <%s>\n",user));
 
-  if (!password_ok(user,pass1,strlen(pass1),NULL,False) || 
-      !chgpasswd(user,pass1,pass2))
-    SSVAL(*rparam,0,NERR_badpass);
+  if (password_ok(user,pass1,strlen(pass1),NULL,False) &&
+      chgpasswd(user,pass1,pass2))
+  {
+    SSVAL(*rparam,0,NERR_Success);
+  }
 
   bzero(pass1,sizeof(fstring));
   bzero(pass2,sizeof(fstring));         
@@ -1652,12 +1666,11 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
       struct srv_info_struct *servers=NULL;
       int i,count;
       pstring comment;
-      uint32 servertype=SV_TYPE_SERVER_UNIX|SV_TYPE_WORKSTATION|
-       SV_TYPE_SERVER|SV_TYPE_TIME_SOURCE;
+      uint32 servertype=DFLT_SERVER_TYPE;
 
       strcpy(comment,lp_serverstring());
 
-      if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) {
+      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)) {
            servertype = servers[i].type;
@@ -1666,9 +1679,10 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
       }
       if (servers) free(servers);
 
-      SCVAL(p,0,2);            /* version_major */
-      SCVAL(p,1,0);            /* version_minor */
+      SCVAL(p,0,MAJOR_VERSION);
+      SCVAL(p,1,MINOR_VERSION);
       SIVAL(p,2,servertype);
+
       if (mdrcnt == struct_len) {
        SIVAL(p,6,0);
       } else {
@@ -1739,16 +1753,16 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
   p += 4;
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata));
-  strcpy(p2,my_workgroup());
+  strcpy(p2,lp_workgroup());
   p2 = skip_string(p2,1);
   p += 4;
 
-  SCVAL(p,0,2); /* major version?? */
-  SCVAL(p,1,1); /* minor version?? */
+  SCVAL(p,0,MAJOR_VERSION); 
+  SCVAL(p,1,MINOR_VERSION); 
   p += 2;
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata));
-  strcpy(p2,my_workgroup());   /* login domain?? */
+  strcpy(p2,lp_workgroup());   /* login domain?? */
   p2 = skip_string(p2,1);
   p += 4;
 
@@ -1826,7 +1840,8 @@ static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
       p2 = skip_string(p2,1);
     }
     if (uLevel == 11) {         /* modelled after NTAS 3.51 reply */
-      SSVAL(p,34,USER_PRIV_USER); /* user privilege */
+      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 */
@@ -1861,7 +1876,8 @@ static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
     if (uLevel == 1 || uLevel == 2) {
       memset(p+22,' ',16);     /* password */
       SIVALS(p,38,-1);         /* password age */
-      SSVAL(p,42,USER_PRIV_ADMIN); /* user privilege */
+      SSVAL(p,42,
+           Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
       SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
       strcpy(p2,"\\\\%L\\HOMES");
       standard_sub_basic(p2);
@@ -2011,7 +2027,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
       strupper(mypath);
       PACKS(&desc,"z",mypath); /* computer */
     }
-    PACKS(&desc,"z",my_workgroup());/* domain */
+    PACKS(&desc,"z",lp_workgroup());/* domain */
     PACKS(&desc,"z",lp_logon_script());                /* script path */
     PACKI(&desc,"D",0);                /* reserved */
   }
@@ -2497,6 +2513,92 @@ static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
   return(True);
 }
 
+
+struct
+{
+  char * name;
+  char * pipename;
+  int subcommand;
+  BOOL (*fn) ();
+} api_fd_commands [] =
+  {
+    { "SetNmdPpHndState",      "lsarpc",       1,      api_LsarpcSNPHS },
+    { "TransactNmPipe",        "lsarpc",       0x26,   api_LsarpcTNP },
+    { NULL,            NULL,           -1,     api_Unsupported }
+  };
+
+/****************************************************************************
+  handle remote api calls delivered to a named pipe already opened.
+  ****************************************************************************/
+static int api_fd_reply(int cnum,int uid,char *outbuf,
+                       uint16 *setup,char *data,char *params,
+                       int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+{
+  char *rdata = NULL;
+  char *rparam = NULL;
+  int rdata_len = 0;
+  int rparam_len = 0;
+  BOOL reply=False;
+  int i;
+  int fd;
+  int subcommand;
+  
+  /* First find out the name of this file. */
+  if (suwcnt != 2)
+    {
+      DEBUG(0,("Unexpected named pipe transaction.\n"));
+      return(-1);
+    }
+  
+  /* Get the file handle and hence the file name. */
+  fd = setup[1];
+  subcommand = setup[0];
+  
+  DEBUG(3,("Got API command %d on pipe %s ",subcommand,Files[fd].name));
+  DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
+          tdscnt,tpscnt,mdrcnt,mprcnt));
+  
+  for (i=0;api_fd_commands[i].name;i++)
+    if (strequal(api_fd_commands[i].pipename, Files[fd].name) &&
+       api_fd_commands[i].subcommand == subcommand &&
+       api_fd_commands[i].fn)
+      {
+       DEBUG(3,("Doing %s\n",api_fd_commands[i].name));
+       break;
+      }
+  
+  rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
+  rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
+  
+  reply = api_fd_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
+                               &rdata,&rparam,&rdata_len,&rparam_len);
+  
+  if (rdata_len > mdrcnt ||
+      rparam_len > mprcnt)
+    {
+      reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
+                          &rdata,&rparam,&rdata_len,&rparam_len);
+    }
+  
+  
+  /* if we get False back then it's actually unsupported */
+  if (!reply)
+    api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
+                   &rdata,&rparam,&rdata_len,&rparam_len);
+  
+  /* now send the reply */
+  send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
+  
+  if (rdata)
+    free(rdata);
+  if (rparam)
+    free(rparam);
+  
+  return(-1);
+}
+
+
+
 /****************************************************************************
   the buffer was too small
   ****************************************************************************/
@@ -2647,6 +2749,10 @@ static int named_pipe(int cnum,int uid, char *outbuf,char *name,
   if (strequal(name,"LANMAN"))
     return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
 
+if (strlen(name) < 1)
+  return(api_fd_reply(cnum,uid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt));
+
+
   DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
           name,(int)setup[0],(int)setup[1]));
   
@@ -2716,12 +2822,9 @@ int reply_trans(char *inbuf,char *outbuf)
   while (pscnt < tpscnt || dscnt < tdscnt)
     {
       int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
-      receive_smb(Client,inbuf, 0);
-      show_msg(inbuf);
-         
-      /* Ensure this is still a trans packet (sanity check) */
-      if(CVAL(inbuf, smb_com) != SMBtrans)
+      
+      if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT*1000) ||
+         CVAL(inbuf, smb_com) != SMBtrans)
        {
          DEBUG(2,("Invalid secondary trans2 packet\n"));
          if (params) free(params);
@@ -2729,6 +2832,8 @@ int reply_trans(char *inbuf,char *outbuf)
          if (setup) free(setup);
          return(ERROR(ERRSRV,ERRerror));
        }
+
+      show_msg(inbuf);
       
       tpscnt = SVAL(inbuf,smb_vwv0);
       tdscnt = SVAL(inbuf,smb_vwv1);