summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/lib/util_sock.c851
-rw-r--r--source3/rpc_client/cli_reg.c645
-rw-r--r--source3/rpc_parse/parse_sec.c176
-rw-r--r--source3/rpcclient/cmd_reg.c397
4 files changed, 2069 insertions, 0 deletions
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
new file mode 100644
index 0000000000..47c94f21fc
--- /dev/null
+++ b/source3/lib/util_sock.c
@@ -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
index 0000000000..2f04facffd
--- /dev/null
+++ b/source3/rpc_client/cli_reg.c
@@ -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
index 0000000000..bedf042b7f
--- /dev/null
+++ b/source3/rpc_parse/parse_sec.c
@@ -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
index 0000000000..399fb30603
--- /dev/null
+++ b/source3/rpcclient/cmd_reg.c
@@ -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"));
+ }
+}
+