split socket util functions into util_sock.c. util.c NOT committed
authorLuke Leighton <lkcl@samba.org>
Mon, 9 Nov 1998 16:40:38 +0000 (16:40 +0000)
committerLuke Leighton <lkcl@samba.org>
Mon, 9 Nov 1998 16:40:38 +0000 (16:40 +0000)
and util_sock.c NOT included in Makefile.in.

registry commands added to rpcclient.

waiting for 2_0_0 split before committing modified files.  these files
are new modules, and are not referenced in the Makefile.in
(This used to be commit 373f60256fc6dc800f73d88ea9a302933a4a3246)

source3/lib/util_sock.c [new file with mode: 0644]
source3/rpc_client/cli_reg.c [new file with mode: 0644]
source3/rpc_parse/parse_sec.c [new file with mode: 0644]
source3/rpcclient/cmd_reg.c [new file with mode: 0644]

diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
new file mode 100644 (file)
index 0000000..47c94f2
--- /dev/null
@@ -0,0 +1,851 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Samba utility functions
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_SSL
+#include <ssl.h>
+#undef Realloc  /* SSLeay defines this and samba has a function of this name */
+extern SSL  *ssl;
+extern int  sslFd;
+#endif  /* WITH_SSL */
+
+extern int DEBUGLEVEL;
+
+BOOL passive = False;
+
+/* the client file descriptor */
+int Client = -1;
+
+/* the last IP received from */
+struct in_addr lastip;
+
+/* the last port received from */
+int lastport=0;
+
+
+int smb_read_error = 0;
+
+
+/****************************************************************************
+determine if a file descriptor is in fact a socket
+****************************************************************************/
+BOOL is_a_socket(int fd)
+{
+  int v,l;
+  l = sizeof(int);
+  return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+struct
+{
+  char *name;
+  int level;
+  int option;
+  int value;
+  int opttype;
+} socket_options[] = {
+  {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
+  {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
+  {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
+#ifdef TCP_NODELAY
+  {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
+#endif
+#ifdef IPTOS_LOWDELAY
+  {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+  {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
+#endif
+#ifdef SO_SNDBUF
+  {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+  {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+  {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+  {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+  {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+  {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
+#endif
+  {NULL,0,0,0,0}};
+
+       
+
+/****************************************************************************
+set user socket options
+****************************************************************************/
+void set_socket_options(int fd, char *options)
+{
+  fstring tok;
+
+  while (next_token(&options,tok," \t,", sizeof(tok)))
+    {
+      int ret=0,i;
+      int value = 1;
+      char *p;
+      BOOL got_value = False;
+
+      if ((p = strchr(tok,'=')))
+       {
+         *p = 0;
+         value = atoi(p+1);
+         got_value = True;
+       }
+
+      for (i=0;socket_options[i].name;i++)
+       if (strequal(socket_options[i].name,tok))
+         break;
+
+      if (!socket_options[i].name)
+       {
+         DEBUG(0,("Unknown socket option %s\n",tok));
+         continue;
+       }
+
+      switch (socket_options[i].opttype)
+       {
+       case OPT_BOOL:
+       case OPT_INT:
+         ret = setsockopt(fd,socket_options[i].level,
+                          socket_options[i].option,(char *)&value,sizeof(int));
+         break;
+
+       case OPT_ON:
+         if (got_value)
+           DEBUG(0,("syntax error - %s does not take a value\n",tok));
+
+         {
+           int on = socket_options[i].value;
+           ret = setsockopt(fd,socket_options[i].level,
+                            socket_options[i].option,(char *)&on,sizeof(int));
+         }
+         break;          
+       }
+      
+      if (ret != 0)
+       DEBUG(0,("Failed to set socket option %s\n",tok));
+    }
+}
+
+
+
+/****************************************************************************
+  close the socket communication
+****************************************************************************/
+void close_sockets(void )
+{
+#ifdef WITH_SSL
+  sslutil_disconnect(Client);
+#endif /* WITH_SSL */
+
+  close(Client);
+  Client = 0;
+}
+
+
+
+/****************************************************************************
+write to a socket
+****************************************************************************/
+ssize_t write_socket(int fd,char *buf,size_t len)
+{
+  ssize_t ret=0;
+
+  if (passive)
+    return(len);
+  DEBUG(6,("write_socket(%d,%d)\n",fd,len));
+  ret = write_data(fd,buf,len);
+      
+  DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret));
+  if(ret <= 0)
+    DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", 
+       len, fd, strerror(errno) ));
+
+  return(ret);
+}
+
+/****************************************************************************
+read from a socket
+****************************************************************************/
+ssize_t read_udp_socket(int fd,char *buf,size_t len)
+{
+  ssize_t ret;
+  struct sockaddr_in sock;
+  int socklen;
+  
+  socklen = sizeof(sock);
+  bzero((char *)&sock,socklen);
+  bzero((char *)&lastip,sizeof(lastip));
+  ret = (ssize_t)recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
+  if (ret <= 0) {
+    DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
+    return(0);
+  }
+
+  lastip = sock.sin_addr;
+  lastport = ntohs(sock.sin_port);
+
+  DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n",
+             inet_ntoa(lastip), lastport, ret));
+
+  return(ret);
+}
+
+/****************************************************************************
+read data from a device with a timout in msec.
+mincount = if timeout, minimum to read before returning
+maxcount = number to be read.
+time_out = timeout in milliseconds
+****************************************************************************/
+
+ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
+{
+  fd_set fds;
+  int selrtn;
+  ssize_t readret;
+  size_t nread = 0;
+  struct timeval timeout;
+
+  /* just checking .... */
+  if (maxcnt <= 0) return(0);
+
+  smb_read_error = 0;
+
+  /* Blocking read */
+  if (time_out <= 0) {
+    if (mincnt == 0) mincnt = maxcnt;
+
+    while (nread < mincnt) {
+#ifdef WITH_SSL
+      if(fd == sslFd){
+        readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+      }else{
+        readret = read(fd, buf + nread, maxcnt - nread);
+      }
+#else /* WITH_SSL */
+      readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
+      if (readret == 0) {
+        smb_read_error = READ_EOF;
+        return -1;
+      }
+
+      if (readret == -1) {
+        smb_read_error = READ_ERROR;
+        return -1;
+      }
+      nread += readret;
+    }
+    return((ssize_t)nread);
+  }
+  
+  /* Most difficult - timeout read */
+  /* If this is ever called on a disk file and 
+     mincnt is greater then the filesize then
+     system performance will suffer severely as 
+     select always returns true on disk files */
+
+  /* Set initial timeout */
+  timeout.tv_sec = (time_t)(time_out / 1000);
+  timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+  for (nread=0; nread < mincnt; ) 
+  {      
+    FD_ZERO(&fds);
+    FD_SET(fd,&fds);
+      
+    selrtn = sys_select(fd+1,&fds,&timeout);
+
+    /* Check if error */
+    if(selrtn == -1) {
+      /* something is wrong. Maybe the socket is dead? */
+      smb_read_error = READ_ERROR;
+      return -1;
+    }
+      
+    /* Did we timeout ? */
+    if (selrtn == 0) {
+      smb_read_error = READ_TIMEOUT;
+      return -1;
+    }
+      
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+    }else{
+      readret = read(fd, buf + nread, maxcnt - nread);
+    }
+#else /* WITH_SSL */
+    readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
+    if (readret == 0) {
+      /* we got EOF on the file descriptor */
+      smb_read_error = READ_EOF;
+      return -1;
+    }
+
+    if (readret == -1) {
+      /* the descriptor is probably dead */
+      smb_read_error = READ_ERROR;
+      return -1;
+    }
+      
+    nread += readret;
+  }
+
+  /* Return the number we got */
+  return((ssize_t)nread);
+}
+
+
+/****************************************************************************
+send a keepalive packet (rfc1002)
+****************************************************************************/
+BOOL send_keepalive(int client)
+{
+  unsigned char buf[4];
+
+  buf[0] = 0x85;
+  buf[1] = buf[2] = buf[3] = 0;
+
+  return(write_data(client,(char *)buf,4) == 4);
+}
+
+
+
+/****************************************************************************
+  read data from the client, reading exactly N bytes. 
+****************************************************************************/
+ssize_t read_data(int fd,char *buffer,size_t N)
+{
+  ssize_t  ret;
+  size_t total=0;  
+  smb_read_error = 0;
+
+  while (total < N)
+  {
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      ret = SSL_read(ssl, buffer + total, N - total);
+    }else{
+      ret = read(fd,buffer + total,N - total);
+    }
+#else /* WITH_SSL */
+    ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+    if (ret == 0)
+    {
+      smb_read_error = READ_EOF;
+      return 0;
+    }
+    if (ret == -1)
+    {
+      smb_read_error = READ_ERROR;
+      return -1;
+    }
+    total += ret;
+  }
+  return (ssize_t)total;
+}
+
+
+/****************************************************************************
+  write data to a fd 
+****************************************************************************/
+ssize_t write_data(int fd,char *buffer,size_t N)
+{
+  size_t total=0;
+  ssize_t ret;
+
+  while (total < N)
+  {
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      ret = SSL_write(ssl,buffer + total,N - total);
+    }else{
+      ret = write(fd,buffer + total,N - total);
+    }
+#else /* WITH_SSL */
+    ret = write(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+    if (ret == -1) return -1;
+    if (ret == 0) return total;
+
+    total += ret;
+  }
+  return (ssize_t)total;
+}
+
+
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer
+This version of the function will return a length of zero on receiving
+a keepalive packet.
+timeout is in milliseconds.
+****************************************************************************/
+static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout)
+{
+  ssize_t len=0;
+  int msg_type;
+  BOOL ok = False;
+
+  while (!ok)
+  {
+    if (timeout > 0)
+      ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4);
+    else 
+      ok = (read_data(fd,inbuf,4) == 4);
+
+    if (!ok)
+      return(-1);
+
+    len = smb_len(inbuf);
+    msg_type = CVAL(inbuf,0);
+
+    if (msg_type == 0x85) 
+      DEBUG(5,("Got keepalive packet\n"));
+  }
+
+  DEBUG(10,("got smb length of %d\n",len));
+
+  return(len);
+}
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer. This version of the function will
+never return a session keepalive (length of zero).
+timeout is in milliseconds.
+****************************************************************************/
+ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout)
+{
+  ssize_t len;
+
+  for(;;)
+  {
+    len = read_smb_length_return_keepalive(fd, inbuf, timeout);
+
+    if(len < 0)
+      return len;
+
+    /* Ignore session keepalives. */
+    if(CVAL(inbuf,0) != 0x85)
+      break;
+  }
+
+  return len;
+}
+
+/****************************************************************************
+  read an smb from a fd. Note that the buffer *MUST* be of size
+  BUFFER_SIZE+SAFETY_MARGIN.
+  The timeout is in milliseconds. 
+  This function will return on a
+  receipt of a session keepalive packet.
+****************************************************************************/
+BOOL receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+  ssize_t len,ret;
+
+  smb_read_error = 0;
+
+  bzero(buffer,smb_size + 100);
+
+  len = read_smb_length_return_keepalive(fd,buffer,timeout);
+  if (len < 0)
+  {
+    DEBUG(10,("receive_smb: length < 0!\n"));
+    return(False);
+  }
+
+  if (len > BUFFER_SIZE) {
+    DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
+    if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
+    {
+       exit(1);
+    }
+  }
+
+  if(len > 0) {
+    ret = read_data(fd,buffer+4,len);
+    if (ret != len) {
+      smb_read_error = READ_ERROR;
+      return False;
+    }
+  }
+  return(True);
+}
+
+/****************************************************************************
+  read an smb from a fd ignoring all keepalive packets. Note that the buffer 
+  *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+  The timeout is in milliseconds
+
+  This is exactly the same as receive_smb except that it never returns
+  a session keepalive packet (just as receive_smb used to do).
+  receive_smb was changed to return keepalives as the oplock processing means this call
+  should never go into a blocking read.
+****************************************************************************/
+
+BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+  BOOL ret;
+
+  for(;;)
+  {
+    ret = receive_smb(fd, buffer, timeout);
+
+    if (!ret)
+    {
+      DEBUG(10,("client_receive_smb failed\n"));
+      show_msg(buffer);
+      return ret;
+    }
+
+    /* Ignore session keepalive packets. */
+    if(CVAL(buffer,0) != 0x85)
+      break;
+  }
+  show_msg(buffer);
+  return ret;
+}
+
+/****************************************************************************
+  send an smb to a fd 
+****************************************************************************/
+BOOL send_smb(int fd,char *buffer)
+{
+  size_t len;
+  size_t nwritten=0;
+  ssize_t ret;
+  len = smb_len(buffer) + 4;
+
+  while (nwritten < len)
+  {
+    ret = write_socket(fd,buffer+nwritten,len - nwritten);
+    if (ret <= 0)
+    {
+      DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret));
+      close_sockets();
+      exit(1);
+    }
+    nwritten += ret;
+  }
+
+  return True;
+}
+
+
+
+/****************************************************************************
+send a single packet to a port on another machine
+****************************************************************************/
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+{
+  BOOL ret;
+  int out_fd;
+  struct sockaddr_in sock_out;
+
+  if (passive)
+    return(True);
+
+  /* create a socket to write to */
+  out_fd = socket(AF_INET, type, 0);
+  if (out_fd == -1) 
+    {
+      DEBUG(0,("socket failed"));
+      return False;
+    }
+
+  /* set the address and port */
+  bzero((char *)&sock_out,sizeof(sock_out));
+  putip((char *)&sock_out.sin_addr,(char *)&ip);
+  sock_out.sin_port = htons( port );
+  sock_out.sin_family = AF_INET;
+  
+  if (DEBUGLEVEL > 0)
+    DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
+            len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
+       
+  /* send it */
+  ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
+
+  if (!ret)
+    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+            inet_ntoa(ip),port,strerror(errno)));
+
+  close(out_fd);
+  return(ret);
+}
+
+
+/****************************************************************************
+open a socket of the specified type, port and address for incoming data
+****************************************************************************/
+int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
+{
+  struct hostent *hp;
+  struct sockaddr_in sock;
+  pstring host_name;
+  int res;
+
+  /* get my host name */
+  if (gethostname(host_name, MAXHOSTNAMELEN) == -1) 
+    { DEBUG(0,("gethostname failed\n")); return -1; } 
+
+  /* get host info */
+  if ((hp = Get_Hostbyname(host_name)) == 0) 
+    {
+      DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",host_name));
+      return -1;
+    }
+  
+  bzero((char *)&sock,sizeof(sock));
+  memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
+
+#ifdef HAVE_SOCK_SIN_LEN
+  sock.sin_len = sizeof(sock);
+#endif
+  sock.sin_port = htons( port );
+  sock.sin_family = hp->h_addrtype;
+  sock.sin_addr.s_addr = socket_addr;
+  res = socket(hp->h_addrtype, type, 0);
+  if (res == -1) 
+    { DEBUG(0,("socket failed\n")); return -1; }
+
+  {
+    int one=1;
+    setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
+  }
+
+  /* now we've got a socket - we need to bind it */
+  if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) 
+    { 
+      if (port) {
+       if (port == SMB_PORT || port == NMB_PORT)
+         DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n",
+                       port,inet_ntoa(sock.sin_addr),strerror(errno))); 
+       close(res); 
+
+       if (dlevel > 0 && port < 1000)
+         port = 7999;
+
+       if (port >= 1000 && port < 9000)
+         return(open_socket_in(type,port+1,dlevel,socket_addr));
+      }
+
+      return(-1); 
+    }
+  DEBUG(3,("bind succeeded on port %d\n",port));
+
+  return res;
+}
+
+
+/****************************************************************************
+  create an outgoing socket
+  **************************************************************************/
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
+{
+  struct sockaddr_in sock_out;
+  int res,ret;
+  int connect_loop = 250; /* 250 milliseconds */
+  int loops = (timeout * 1000) / connect_loop;
+
+  /* create a socket to write to */
+  res = socket(PF_INET, type, 0);
+  if (res == -1) 
+    { DEBUG(0,("socket error\n")); return -1; }
+
+  if (type != SOCK_STREAM) return(res);
+  
+  bzero((char *)&sock_out,sizeof(sock_out));
+  putip((char *)&sock_out.sin_addr,(char *)addr);
+  
+  sock_out.sin_port = htons( port );
+  sock_out.sin_family = PF_INET;
+
+  /* set it non-blocking */
+  set_blocking(res,False);
+
+  DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
+  
+  /* and connect it to the destination */
+connect_again:
+  ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
+
+  /* Some systems return EAGAIN when they mean EINPROGRESS */
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+        errno == EAGAIN) && loops--) {
+    msleep(connect_loop);
+    goto connect_again;
+  }
+
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+         errno == EAGAIN)) {
+      DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
+      close(res);
+      return -1;
+  }
+
+#ifdef EISCONN
+  if (ret < 0 && errno == EISCONN) {
+    errno = 0;
+    ret = 0;
+  }
+#endif
+
+  if (ret < 0) {
+    DEBUG(1,("error connecting to %s:%d (%s)\n",
+            inet_ntoa(*addr),port,strerror(errno)));
+    close(res);
+    return -1;
+  }
+
+  /* set it blocking again */
+  set_blocking(res,True);
+
+  return res;
+}
+
+
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork(void)
+{
+  global_client_name_done = False;
+  global_client_addr_done = False;
+
+  /*
+   * Re-seed the random crypto generator, so all smbd's
+   * started from the same parent won't generate the same
+   * sequence.
+   */
+  {
+    unsigned char dummy;
+    generate_random_buffer( &dummy, 1, True);
+  } 
+}
+/*******************************************************************
+ return the DNS name of the client 
+ ******************************************************************/
+char *client_name(int fd)
+{
+       struct sockaddr sa;
+       struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+       int     length = sizeof(sa);
+       static pstring name_buf;
+       struct hostent *hp;
+       static int last_fd=-1;
+       
+       if (global_client_name_done && last_fd == fd) 
+               return name_buf;
+       
+       last_fd = fd;
+       global_client_name_done = False;
+       
+       pstrcpy(name_buf,"UNKNOWN");
+       
+       if (fd == -1) {
+               return name_buf;
+       }
+       
+       if (getpeername(fd, &sa, &length) < 0) {
+               DEBUG(0,("getpeername failed\n"));
+               return name_buf;
+       }
+       
+       /* Look up the remote host name. */
+       if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
+                               sizeof(sockin->sin_addr),
+                               AF_INET)) == 0) {
+               DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr(fd)));
+               StrnCpy(name_buf,client_addr(fd),sizeof(name_buf) - 1);
+       } else {
+               StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
+               if (!matchname(name_buf, sockin->sin_addr)) {
+                       DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr(fd)));
+                       pstrcpy(name_buf,"UNKNOWN");
+               }
+       }
+       global_client_name_done = True;
+       return name_buf;
+}
+
+/*******************************************************************
+ return the IP addr of the client as a string 
+ ******************************************************************/
+char *client_addr(int fd)
+{
+       struct sockaddr sa;
+       struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+       int     length = sizeof(sa);
+       static fstring addr_buf;
+       static int last_fd = -1;
+
+       if (global_client_addr_done && fd == last_fd) 
+               return addr_buf;
+
+       last_fd = fd;
+       global_client_addr_done = False;
+
+       fstrcpy(addr_buf,"0.0.0.0");
+
+       if (fd == -1) {
+               return addr_buf;
+       }
+       
+       if (getpeername(fd, &sa, &length) < 0) {
+               DEBUG(0,("getpeername failed\n"));
+               return addr_buf;
+       }
+       
+       fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+       
+       global_client_addr_done = True;
+       return addr_buf;
+}
diff --git a/source3/rpc_client/cli_reg.c b/source3/rpc_client/cli_reg.c
new file mode 100644 (file)
index 0000000..2f04fac
--- /dev/null
@@ -0,0 +1,645 @@
+
+/* 
+ *  Unix SMB/Netbios implementation.
+ *  Version 1.9.
+ *  RPC Pipe client / server routines
+ *  Copyright (C) Andrew Tridgell              1992-1997,
+ *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ *  Copyright (C) Paul Ashton                       1997.
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+do a REG Open Policy
+****************************************************************************/
+BOOL do_reg_open_policy(struct cli_state *cli, uint16 unknown_0, uint32 level,
+                               POLICY_HND *hnd)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_OPEN_POLICY q_o;
+       BOOL valid_pol = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_OPEN_POLICY */
+
+       DEBUG(4,("REG Open Policy\n"));
+
+       make_reg_q_open_pol(&q_o, unknown_0, level);
+
+       /* turn parameters into data stream */
+       reg_io_q_open_policy("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_OPEN_POLICY, &buf, &rbuf))
+       {
+               REG_R_OPEN_POLICY r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_open_policy("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_OPEN_POLICY: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       /* ok, at last: we're happy. return the policy handle */
+                       memcpy(hnd, r_o.pol.data, sizeof(hnd->data));
+                       valid_pol = True;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_pol;
+}
+
+/****************************************************************************
+do a REG Open Unknown 4
+****************************************************************************/
+BOOL do_reg_open_unk_4(struct cli_state *cli, uint16 unknown_0, uint32 level,
+                               POLICY_HND *hnd)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_OPEN_UNK_4 q_o;
+       BOOL valid_pol = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_OPEN_UNK_4 */
+
+       DEBUG(4,("REG Open Unknown4\n"));
+
+       make_reg_q_open_unk_4(&q_o, unknown_0, level);
+
+       /* turn parameters into data stream */
+       reg_io_q_open_unk_4("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_OPEN_UNK_4, &buf, &rbuf))
+       {
+               REG_R_OPEN_UNK_4 r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_open_unk_4("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_OPEN_UNK_4: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       /* ok, at last: we're happy. return the policy handle */
+                       memcpy(hnd, r_o.pol.data, sizeof(hnd->data));
+                       valid_pol = True;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_pol;
+}
+
+/****************************************************************************
+do a REG Query Unknown 10
+****************************************************************************/
+BOOL do_reg_query_unk_10(struct cli_state *cli, POLICY_HND *hnd,
+                               uint32 *unknown_0, uint32 *unknown_1,
+                               uint32 *num_subkeys, uint32 *max_subkeylen,
+                               uint32 *unknown_4, uint32 *num_values,
+                               uint32 *max_valnamelen, uint32 *max_valbufsize,
+                               uint32 *unknown_8, NTTIME *mod_time)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_QUERY_UNK_10 q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_QUERY_UNK_10 */
+
+       DEBUG(4,("REG Query Unknown 10\n"));
+
+       make_reg_q_query_unk_10(&q_o, hnd);
+
+       /* turn parameters into data stream */
+       reg_io_q_query_unk_10("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_QUERY_UNK_10, &buf, &rbuf))
+       {
+               REG_R_QUERY_UNK_10 r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_query_unk_10("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_QUERY_UNK_10: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_query = True;
+                       
+                       *unknown_0      = r_o.unknown_0     ;
+                       *unknown_1      = r_o.unknown_1     ;
+                       *num_subkeys    = r_o.num_subkeys   ;
+                       *max_subkeylen  = r_o.max_subkeylen ;
+                       *unknown_4      = r_o.unknown_4     ;
+                       *num_values     = r_o.num_values    ;
+                       *max_valnamelen = r_o.max_valnamelen;
+                       *max_valbufsize = r_o.max_valbufsize;
+                       *unknown_8      = r_o.unknown_8    ;
+                       *mod_time       = r_o.mod_time     ;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Unknown 1A
+****************************************************************************/
+BOOL do_reg_unknown_1a(struct cli_state *cli, POLICY_HND *hnd, uint32 *unk)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_UNK_1A q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_UNKNOWN_1A */
+
+       DEBUG(4,("REG Unknown 1a\n"));
+
+       make_reg_q_unk_1a(&q_o, hnd);
+
+       /* turn parameters into data stream */
+       reg_io_q_unk_1a("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_UNK_1A, &buf, &rbuf))
+       {
+               REG_R_UNK_1A r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_unk_1a("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_UNK_1A: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_query = True;
+                       (*unk) = r_o.unknown;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Query Info
+****************************************************************************/
+BOOL do_reg_query_info(struct cli_state *cli, POLICY_HND *hnd,
+                               char *type, uint32 *unk_0, uint32 *unk_1)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_INFO q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_INFO */
+
+       DEBUG(4,("REG Query Info\n"));
+
+       make_reg_q_info(&q_o, hnd, "ProductType", time(NULL), 4, 1);
+
+       /* turn parameters into data stream */
+       reg_io_q_info("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_INFO, &buf, &rbuf))
+       {
+               REG_R_INFO r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_info("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_INFO: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_query = True;
+                       fstrcpy(type, buffer2_to_str(&r_o.uni_type));
+                       (*unk_0) = r_o.unknown_0;
+                       (*unk_1) = r_o.unknown_1;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Query Key Security 
+****************************************************************************/
+BOOL do_reg_get_key_sec(struct cli_state *cli, POLICY_HND *hnd,
+                               uint32 *sec_buf_size, SEC_DESC_BUF *sec_buf)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_GET_KEY_SEC q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_GET_KEY_SEC */
+
+       DEBUG(4,("REG query key security.  buf_size: %d\n", *sec_buf_size));
+
+       make_reg_q_get_key_sec(&q_o, hnd, *sec_buf_size, sec_buf);
+
+       /* turn parameters into data stream */
+       reg_io_q_get_key_sec("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_GET_KEY_SEC, &buf, &rbuf))
+       {
+               REG_R_GET_KEY_SEC r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               r_o.data = sec_buf;
+               reg_io_r_get_key_sec("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status == 0x0000007a)
+               {
+                       /*
+                        * get the maximum buffer size: it was too small
+                        */
+                       (*sec_buf_size) = r_o.hdr_sec.buf_max_len;
+                       DEBUG(5,("sec_buf_size too small.  use %d\n", *sec_buf_size));
+                       valid_query = True;
+               }
+               else if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_GET_KEY_SEC: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+               else
+               {
+                       valid_query = True;
+                       (*sec_buf_size) = r_o.data->len;
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Enum Key
+****************************************************************************/
+BOOL do_reg_enum_key(struct cli_state *cli, POLICY_HND *hnd,
+                               int key_index, char *key_name,
+                               uint32 *unk_1, uint32 *unk_2,
+                               time_t *mod_time)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_ENUM_KEY q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_ENUM_KEY */
+
+       DEBUG(4,("REG Enum Key\n"));
+
+       make_reg_q_enum_key(&q_o, hnd, key_index);
+
+       /* turn parameters into data stream */
+       reg_io_q_enum_key("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_ENUM_KEY, &buf, &rbuf))
+       {
+               REG_R_ENUM_KEY r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_enum_key("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_ENUM_KEY: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_query = True;
+                       (*unk_1) = r_o.unknown_1;
+                       (*unk_2) = r_o.unknown_2;
+                       fstrcpy(key_name, unistr2(r_o.key_name.str.buffer));
+                       (*mod_time) = nt_time_to_unix(&r_o.time);
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Enum Value
+****************************************************************************/
+BOOL do_reg_enum_val(struct cli_state *cli, POLICY_HND *hnd,
+                               int val_index, int max_valnamelen, int max_valbufsize,
+                               fstring val_name,
+                               uint32 *val_type, BUFFER2 *value)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_ENUM_VALUE q_o;
+       BOOL valid_query = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_ENUM_VALUE */
+
+       DEBUG(4,("REG Enum Value\n"));
+
+       make_reg_q_enum_val(&q_o, hnd, val_index, max_valnamelen, max_valbufsize);
+
+       /* turn parameters into data stream */
+       reg_io_q_enum_val("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_ENUM_VALUE, &buf, &rbuf))
+       {
+               REG_R_ENUM_VALUE r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+               r_o.buf_value = value;
+
+               reg_io_r_enum_val("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_ENUM_VALUE: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_query = True;
+                       (*val_type) = r_o.type;
+                       fstrcpy(val_name, unistr2_to_str(&r_o.uni_name));
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_query;
+}
+
+/****************************************************************************
+do a REG Open Key
+****************************************************************************/
+BOOL do_reg_open_entry(struct cli_state *cli, POLICY_HND *hnd,
+                               char *key_name, uint32 unk_0,
+                               POLICY_HND *key_hnd)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_OPEN_ENTRY q_o;
+       BOOL valid_pol = False;
+
+       if (hnd == NULL) return False;
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       /* create and send a MSRPC command with api REG_OPEN_ENTRY */
+
+       DEBUG(4,("REG Open Entry\n"));
+
+       make_reg_q_open_entry(&q_o, hnd, key_name, unk_0);
+
+       /* turn parameters into data stream */
+       reg_io_q_open_entry("", &q_o, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_OPEN_ENTRY, &buf, &rbuf))
+       {
+               REG_R_OPEN_ENTRY r_o;
+               BOOL p;
+
+               ZERO_STRUCT(r_o);
+
+               reg_io_r_open_entry("", &r_o, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_o.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_OPEN_ENTRY: %s\n", get_nt_error_msg(r_o.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       valid_pol = True;
+                       memcpy(key_hnd, r_o.pol.data, sizeof(key_hnd->data));
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_pol;
+}
+
+/****************************************************************************
+do a REG Close
+****************************************************************************/
+BOOL do_reg_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+       prs_struct rbuf;
+       prs_struct buf; 
+       REG_Q_CLOSE q_c;
+       BOOL valid_close = False;
+
+       if (hnd == NULL) return False;
+
+       /* create and send a MSRPC command with api REG_CLOSE */
+
+       prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+       prs_init(&rbuf, 0   , 4, SAFETY_MARGIN, True );
+
+       DEBUG(4,("REG Close\n"));
+
+       /* store the parameters */
+       make_reg_q_close(&q_c, hnd);
+
+       /* turn parameters into data stream */
+       reg_io_q_close("", &q_c, &buf, 0);
+
+       /* send the data on \PIPE\ */
+       if (rpc_api_pipe_req(cli, REG_CLOSE, &buf, &rbuf))
+       {
+               REG_R_CLOSE r_c;
+               BOOL p;
+
+               ZERO_STRUCT(r_c);
+
+               reg_io_r_close("", &r_c, &rbuf, 0);
+               p = rbuf.offset != 0;
+
+               if (p && r_c.status != 0)
+               {
+                       /* report error code */
+                       DEBUG(0,("REG_CLOSE: %s\n", get_nt_error_msg(r_c.status)));
+                       p = False;
+               }
+
+               if (p)
+               {
+                       /* check that the returned policy handle is all zeros */
+                       int i;
+                       valid_close = True;
+
+                       for (i = 0; i < sizeof(r_c.pol.data); i++)
+                       {
+                               if (r_c.pol.data[i] != 0)
+                               {
+                                       valid_close = False;
+                                       break;
+                               }
+                       }       
+                       if (!valid_close)
+                       {
+                               DEBUG(0,("REG_CLOSE: non-zero handle returned\n"));
+                       }
+               }
+       }
+
+       prs_mem_free(&rbuf);
+       prs_mem_free(&buf );
+
+       return valid_close;
+}
+
+
diff --git a/source3/rpc_parse/parse_sec.c b/source3/rpc_parse/parse_sec.c
new file mode 100644 (file)
index 0000000..bedf042
--- /dev/null
@@ -0,0 +1,176 @@
+
+/* 
+ *  Unix SMB/Netbios implementation.
+ *  Version 1.9.
+ *  RPC Pipe client / server routines
+ *  Copyright (C) Andrew Tridgell              1992-1997,
+ *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ *  Copyright (C) Paul Ashton                       1997.
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void sec_io_info(char *desc, SEC_INFO *t, prs_struct *ps, int depth)
+{
+       if (t == NULL) return;
+
+       prs_debug(ps, depth, desc, "sec_io_info");
+       depth++;
+
+       prs_align(ps);
+       
+       prs_uint32("perms", ps, depth, &(t->perms));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void sec_io_ace(char *desc, SEC_ACE *t, prs_struct *ps, int depth)
+{
+       uint32 old_offset;
+       uint32 offset_ace_size;
+       if (t == NULL) return;
+
+       prs_debug(ps, depth, desc, "sec_io_ace");
+       depth++;
+
+       prs_align(ps);
+       
+       old_offset = ps->offset;
+
+       prs_uint16("unknown_1", ps, depth, &(t->unknown_1));
+       prs_uint16_pre("ace_size ", ps, depth, &(t->ace_size ), &offset_ace_size);
+
+       sec_io_info   ("info", &t->info, ps, depth);
+       prs_align(ps);
+       smb_io_dom_sid("sid ", &t->sid , ps, depth);
+
+       prs_uint16_post("ace_size ", ps, depth, offset_ace_size, old_offset);
+       if (ps->io)
+       {
+               ps->offset = old_offset + t->ace_size;
+       }
+}
+
+/*******************************************************************
+reads or writes a structure.  this is one of those retrospective jobs,
+which i hate.  why do we have to do this?  what's it all about?
+********************************************************************/
+void sec_io_acl(char *desc, SEC_ACL *t, prs_struct *ps, int depth)
+{
+       int i;
+       uint32 old_offset;
+       uint32 offset_acl_size;
+
+       if (t == NULL) return;
+
+       prs_debug(ps, depth, desc, "sec_io_acl");
+       depth++;
+
+       prs_align(ps);
+       
+       old_offset = ps->offset;
+
+       prs_uint16("unknown_1", ps, depth, &(t->unknown_1));
+       prs_uint16_pre("acl_size ", ps, depth, &(t->acl_size ), &offset_acl_size);
+       prs_uint32("num_aces ", ps, depth, &(t->num_aces ));
+
+       for (i = 0; i < MIN(t->num_aces, MAX_SEC_ACES); i++)
+       {
+               fstring tmp;
+               snprintf(tmp, sizeof(tmp), "ace[%02d]: ", i);
+               sec_io_ace(tmp, &t->ace[i], ps, depth);
+       }
+
+       prs_align(ps);
+
+       prs_uint16_post("acl_size ", ps, depth, offset_acl_size, old_offset);
+       if (ps->io)
+       {
+               ps->offset = old_offset + t->acl_size;
+       }
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void sec_io_desc(char *desc, SEC_DESC *t, prs_struct *ps, int depth)
+{
+       if (t == NULL) return;
+
+       prs_debug(ps, depth, desc, "sec_io_desc");
+       depth++;
+
+       prs_align(ps);
+       
+       prs_uint16("unknown_1", ps, depth, &(t->unknown_1));
+       prs_uint16("unknown_2", ps, depth, &(t->unknown_2));
+
+       prs_uint32("off_owner_sid", ps, depth, &(t->off_owner_sid));
+       prs_uint32("off_pnt_sid  ", ps, depth, &(t->off_pnt_sid  ));
+       prs_uint32("off_unknown  ", ps, depth, &(t->off_unknown  ));
+       prs_uint32("off_acl      ", ps, depth, &(t->off_acl      ));
+
+       sec_io_acl    ("acl"       , &t->acl       , ps, depth);
+       smb_io_dom_sid("owner_sid ", &t->owner_sid , ps, depth);
+       prs_align(ps);
+       smb_io_dom_sid("parent_sid", &t->parent_sid, ps, depth);
+       prs_align(ps);
+}
+
+/*******************************************************************
+creates a SEC_DESC_BUF structure.
+********************************************************************/
+void make_sec_desc_buf(SEC_DESC_BUF *buf, int len, uint32 buf_ptr)
+{
+       ZERO_STRUCTP(buf);
+
+       /* max buffer size (allocated size) */
+       buf->max_len = len;
+       buf->undoc       = 0;
+       buf->len = buf_ptr != 0 ? len : 0;
+}
+
+/*******************************************************************
+reads or writes a SEC_DESC_BUF structure.
+********************************************************************/
+void sec_io_desc_buf(char *desc, SEC_DESC_BUF *sec, prs_struct *ps, int depth)
+{
+       if (sec == NULL) return;
+
+       prs_debug(ps, depth, desc, "sec_io_desc_buf");
+       depth++;
+
+       prs_align(ps);
+       
+       prs_uint32("max_len", ps, depth, &(sec->max_len));
+       prs_uint32("undoc  ", ps, depth, &(sec->undoc  ));
+       prs_uint32("len    ", ps, depth, &(sec->len    ));
+
+       if (sec->len != 0)
+       {
+               sec_io_desc("sec   ", &sec->sec, ps, depth);
+       }
+}
diff --git a/source3/rpcclient/cmd_reg.c b/source3/rpcclient/cmd_reg.c
new file mode 100644 (file)
index 0000000..399fb30
--- /dev/null
@@ -0,0 +1,397 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NT Domain Authentication SMB / MSRPC client
+   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+extern struct cli_state *smb_cli;
+extern int smb_tidx;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+nt registry enum
+****************************************************************************/
+void cmd_reg_enum(struct client_info *info)
+{
+       fstring type;
+       uint32 unk_0;
+       uint32 unk_1;
+       BOOL res = True;
+       BOOL res1 = True;
+       BOOL res2 = True;
+       int i;
+
+       POLICY_HND key_pol;
+       fstring key_name;
+
+       /*
+        * query key info
+        */
+
+       uint32 unknown_0; 
+       uint32 unknown_1;
+       uint32 num_subkeys;
+       uint32 max_subkeylen;
+       uint32 unknown_4; 
+       uint32 num_values;
+       uint32 max_valnamelen;
+       uint32 max_valbufsize;
+       uint32 unknown_8;
+       NTTIME mod_time;
+
+       /*
+        * unknown 0x1a request
+        */
+
+       uint32 unk_1a_response;
+
+       DEBUG(5, ("cmd_reg_enum: smb_cli->fd:%d\n", smb_cli->fd));
+
+       if (!next_token(NULL, key_name, NULL, sizeof(key_name)))
+       {
+               fprintf(out_hnd, "regenum key_name\n");
+               return;
+       }
+
+       /* open WINREG session. */
+       res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+       /* open registry receive a policy handle */
+       res = res ? do_reg_open_policy(smb_cli,
+                               0x84E0, 0x02000000,
+                               &info->dom.reg_pol_connect) : False;
+
+       /* open an entry */
+       res1 = res  ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+                                key_name, 0x02000000, &key_pol) : False;
+
+       /* query it */
+       res1 = res1 ? do_reg_query_info(smb_cli, &key_pol,
+                               type, &unk_0, &unk_1) : False;
+
+       res1 = res1 ? do_reg_query_unk_10(smb_cli,
+                               &key_pol,
+                               &unknown_0, &unknown_1,
+                               &num_subkeys, &max_subkeylen,
+                               &unknown_4, &num_values,
+                               &max_valnamelen, &max_valbufsize,
+                               &unknown_8, &mod_time) : False;
+
+       if (res1)
+       {
+               fprintf(out_hnd,"Registry Query Info Key\n");
+               fprintf(out_hnd,"unk_0,1 : 0x%x 0x%x\n", unknown_0, unknown_1);
+               fprintf(out_hnd,"subkeys, max_len: %d %d\n", num_subkeys, max_subkeylen);
+               fprintf(out_hnd,"unk_4 : 0x%x\n", unknown_4);
+               fprintf(out_hnd,"vals, max_len, max_size: 0x%x 0x%x 0x%x\n", num_values, max_valnamelen, max_valbufsize);
+               fprintf(out_hnd,"unk_8: 0x%x\n", unknown_8);
+               fprintf(out_hnd,"mod time: %s\n", http_timestring(nt_time_to_unix(&mod_time)));
+       }
+
+       for (i = 0; i < num_subkeys; i++)
+       {
+               /*
+                * enumerate key
+                */
+
+               fstring enum_name;
+               uint32 enum_unk1;
+               uint32 enum_unk2;
+               time_t key_mod_time;
+
+               /* unknown 1a it */
+               res2 = res1 ? do_reg_unknown_1a(smb_cli, &key_pol,
+                                       &unk_1a_response) : False;
+
+               if (res2 && unk_1a_response != 5)
+               {
+                       fprintf(out_hnd,"Unknown 1a response: %x\n", unk_1a_response);
+               }
+
+               /* enum key */
+               res2 = res2 ? do_reg_enum_key(smb_cli, &key_pol,
+                                       i, enum_name,
+                                       &enum_unk1, &enum_unk2,
+                                       &key_mod_time) : False;
+               
+               if (res2)
+               {
+                       display_reg_key_info(out_hnd, ACTION_HEADER   , enum_name, key_mod_time);
+                       display_reg_key_info(out_hnd, ACTION_ENUMERATE, enum_name, key_mod_time);
+                       display_reg_key_info(out_hnd, ACTION_FOOTER   , enum_name, key_mod_time);
+               }
+
+       }
+
+       for (i = 0; i < num_values; i++)
+       {
+               /*
+                * enumerate key
+                */
+
+               uint32 val_type;
+               BUFFER2 value;
+               fstring val_name;
+
+               /* unknown 1a it */
+               res2 = res1 ? do_reg_unknown_1a(smb_cli, &key_pol,
+                                       &unk_1a_response) : False;
+
+               if (res2 && unk_1a_response != 5)
+               {
+                       fprintf(out_hnd,"Unknown 1a response: %x\n", unk_1a_response);
+               }
+
+               /* enum key */
+               res2 = res2 ? do_reg_enum_val(smb_cli, &key_pol,
+                                       i, max_valnamelen, max_valbufsize,
+                                       val_name, &val_type, &value) : False;
+               
+               if (res2)
+               {
+                       display_reg_value_info(out_hnd, ACTION_HEADER   , val_name, val_type, &value);
+                       display_reg_value_info(out_hnd, ACTION_ENUMERATE, val_name, val_type, &value);
+                       display_reg_value_info(out_hnd, ACTION_FOOTER   , val_name, val_type, &value);
+               }
+       }
+
+       /* close the handles */
+       res1 = res1 ? do_reg_close(smb_cli, &key_pol) : False;
+       res  = res  ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+       /* close the session */
+       cli_nt_session_close(smb_cli);
+
+       if (res && res1 && res2)
+       {
+               DEBUG(5,("cmd_reg_enum: query succeeded\n"));
+               fprintf(out_hnd,"Registry Enumeration\n");
+               fprintf(out_hnd,"Type: %s unk_0:%x unk_1:%x\n", type, unk_0, unk_1);
+       }
+       else
+       {
+               DEBUG(5,("cmd_reg_enum: query failed\n"));
+       }
+}
+
+/****************************************************************************
+nt registry test
+****************************************************************************/
+void cmd_reg_test2(struct client_info *info)
+{
+       BOOL res = True;
+       BOOL res1 = True;
+       BOOL res2 = True;
+       int i;
+
+       /*
+        * query key info
+        */
+
+       uint32 unknown_0; 
+       uint32 unknown_1;
+       uint32 num_subkeys;
+       uint32 max_subkeylen;
+       uint32 unknown_4; 
+       uint32 num_values;
+       uint32 max_valnamelen;
+       uint32 unknown_7;
+       uint32 unknown_8;
+       NTTIME mod_time;
+
+       /*
+        * unknown 0x1a request
+        */
+
+       uint32 unk_1a_response;
+
+       /*
+        * enumerate key
+        */
+
+       fstring enum_name;
+       uint32 enum_unk1;
+       uint32 enum_unk2;
+       time_t key_mod_time;
+
+       DEBUG(5, ("cmd_reg_test: smb_cli->fd:%d\n", smb_cli->fd));
+
+       /* open WINREG session. */
+       res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+       /* open registry receive a policy handle */
+       res  = res ? do_reg_open_policy(smb_cli,
+                               0x84E0, 0x02000000,
+                               &info->dom.reg_pol_connect) : False;
+
+       res1 = res ? do_reg_open_unk_4(smb_cli,
+                               0x84E0, 0x02000000,
+                               &info->dom.reg_pol_unk_4  ) : False;
+
+       res2 = res1 ? do_reg_query_unk_10(smb_cli,
+                               &info->dom.reg_pol_connect,
+                               &unknown_0, &unknown_1,
+                               &num_subkeys, &max_subkeylen,
+                               &unknown_4, &num_values,
+                               &max_valnamelen, &unknown_7,
+                               &unknown_8, &mod_time) : False;
+
+       if (res2)
+       {
+               fprintf(out_hnd,"Registry Query Info Key\n");
+               fprintf(out_hnd,"unk_0,1 : 0x%x 0x%x\n", unknown_0, unknown_1);
+               fprintf(out_hnd,"subkeys, max_len: %d %d\n", num_subkeys, max_subkeylen);
+               fprintf(out_hnd,"unk_4 : 0x%x\n", unknown_4);
+               fprintf(out_hnd,"vals, max_len : 0x%x 0x%x\n", num_values, max_valnamelen);
+               fprintf(out_hnd,"unk_7, 8: 0x%x 0x%x\n", unknown_7, unknown_8);
+               fprintf(out_hnd,"mod time: %s\n", http_timestring(nt_time_to_unix(&mod_time)));
+       }
+
+       for (i = 0; i < num_subkeys; i++)
+       {
+               /* unknown 1a it */
+               res2 = res1 ? do_reg_unknown_1a(smb_cli, &info->dom.reg_pol_connect,
+                                       &unk_1a_response) : False;
+
+               if (res2)
+               {
+                       fprintf(out_hnd,"Unknown 1a response: %x\n", unk_1a_response);
+               }
+
+               /* enum key */
+               res2 = res2 ? do_reg_enum_key(smb_cli, &info->dom.reg_pol_connect,
+                                       i, enum_name,
+                                       &enum_unk1, &enum_unk2,
+                                       &key_mod_time) : False;
+               
+               if (res2)
+               {
+                       fprintf(out_hnd,"Enum Key: %s  ", enum_name);
+                       fprintf(out_hnd,"unk (%08x %08x)  ", enum_unk1, enum_unk2);
+                       fprintf(out_hnd,"mod time: %s\n", http_timestring(key_mod_time));
+               }
+       }
+
+       /* close the handles */
+       res1 = res1 ? do_reg_close(smb_cli, &info->dom.reg_pol_unk_4  ) : False;
+       res  = res  ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+       /* close the session */
+       cli_nt_session_close(smb_cli);
+
+       if (res && res1 && res2)
+       {
+               DEBUG(5,("cmd_reg_test2: query succeeded\n"));
+               fprintf(out_hnd,"Registry Test2\n");
+       }
+       else
+       {
+               DEBUG(5,("cmd_reg_test2: query failed\n"));
+       }
+}
+
+/****************************************************************************
+nt registry security info
+****************************************************************************/
+void cmd_reg_get_key_sec(struct client_info *info)
+{
+       BOOL res = True;
+       BOOL res3 = True;
+       BOOL res4 = True;
+
+       POLICY_HND key_pol;
+       fstring key_name;
+
+       /*
+        * security info
+        */
+
+       uint32 sec_buf_size;
+       SEC_DESC_BUF sec_buf;
+
+       DEBUG(5, ("cmd_reg_get_key_sec: smb_cli->fd:%d\n", smb_cli->fd));
+
+       if (!next_token(NULL, key_name, NULL, sizeof(key_name)))
+       {
+               fprintf(out_hnd, "regtest key_name\n");
+               return;
+       }
+
+       /* open WINREG session. */
+       res = res ? cli_nt_session_open(smb_cli, PIPE_WINREG) : False;
+
+       /* open registry receive a policy handle */
+       res  = res ? do_reg_open_policy(smb_cli,
+                               0x84E0, 0x02000000,
+                               &info->dom.reg_pol_connect) : False;
+
+       /* open an entry */
+       res3 = res ? do_reg_open_entry(smb_cli, &info->dom.reg_pol_connect,
+                                key_name, 0x02000000, &key_pol) : False;
+
+       /* query key sec info.  first call sets sec_buf_size. */
+       sec_buf_size = 0;
+       res4 = res3 ? do_reg_get_key_sec(smb_cli, &key_pol,
+                               &sec_buf_size, &sec_buf) : False;
+       
+       res4 = res4 ? do_reg_get_key_sec(smb_cli, &key_pol,
+                               &sec_buf_size, &sec_buf) : False;
+
+       if (res4 && sec_buf.len > 0)
+       {
+               fprintf(out_hnd, "Security Info for %s: (%d)\n",
+                                key_name, sec_buf_size);
+               display_sec_desc(out_hnd, ACTION_HEADER   , &sec_buf.sec);
+               display_sec_desc(out_hnd, ACTION_ENUMERATE, &sec_buf.sec);
+               display_sec_desc(out_hnd, ACTION_FOOTER   , &sec_buf.sec);
+       }
+
+       /* close the key handle */
+       res3 = res3 ? do_reg_close(smb_cli, &key_pol) : False;
+
+       /* close the registry handles */
+       res  = res  ? do_reg_close(smb_cli, &info->dom.reg_pol_connect) : False;
+
+       /* close the session */
+       cli_nt_session_close(smb_cli);
+
+       if (res && res3 && res4)
+       {
+               DEBUG(5,("cmd_reg_test2: query succeeded\n"));
+               fprintf(out_hnd,"Registry Test2\n");
+       }
+       else
+       {
+               DEBUG(5,("cmd_reg_test2: query failed\n"));
+       }
+}
+