s3-rpc_server: Don't register the same rpc commands twice.
[abartlet/samba.git/.git] / source3 / rpc_server / srv_pipe_register.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Almost completely rewritten by (C) Jeremy Allison 2005 - 2010
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "srv_pipe_internal.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_RPC_SRV
25
26 struct rpc_table {
27         struct {
28                 const char *clnt;
29                 const char *srv;
30         } pipe;
31         struct ndr_syntax_id rpc_interface;
32         const struct api_struct *cmds;
33         uint32_t n_cmds;
34 };
35
36 static struct rpc_table *rpc_lookup;
37 static uint32_t rpc_lookup_size;
38
39 bool rpc_srv_pipe_exists_by_id(const struct ndr_syntax_id *id)
40 {
41         uint32_t i;
42
43         for (i = 0; i < rpc_lookup_size; i++) {
44                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
45                         return true;
46                 }
47         }
48
49         return false;
50 }
51
52 bool rpc_srv_pipe_exists_by_cli_name(const char *cli_name)
53 {
54         uint32_t i;
55
56         for (i = 0; i < rpc_lookup_size; i++) {
57                 if (strequal(rpc_lookup[i].pipe.clnt, cli_name)) {
58                         return true;
59                 }
60         }
61
62         return false;
63 }
64
65 bool rpc_srv_pipe_exists_by_srv_name(const char *srv_name)
66 {
67         uint32_t i;
68
69         for (i = 0; i < rpc_lookup_size; i++) {
70                 if (strequal(rpc_lookup[i].pipe.srv, srv_name)) {
71                         return true;
72                 }
73         }
74
75         return false;
76 }
77
78 const char *rpc_srv_get_pipe_cli_name(const struct ndr_syntax_id *id)
79 {
80         uint32_t i;
81
82         for (i = 0; i < rpc_lookup_size; i++) {
83                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
84                         return rpc_lookup[i].pipe.clnt;
85                 }
86         }
87
88         return NULL;
89 }
90
91 const char *rpc_srv_get_pipe_srv_name(const struct ndr_syntax_id *id)
92 {
93         uint32_t i;
94
95         for (i = 0; i < rpc_lookup_size; i++) {
96                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
97                         return rpc_lookup[i].pipe.srv;
98                 }
99         }
100
101         return NULL;
102 }
103
104 uint32_t rpc_srv_get_pipe_num_cmds(const struct ndr_syntax_id *id)
105 {
106         uint32_t i;
107
108         for (i = 0; i < rpc_lookup_size; i++) {
109                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
110                         return rpc_lookup[i].n_cmds;
111                 }
112         }
113
114         return 0;
115 }
116
117 const struct api_struct *rpc_srv_get_pipe_cmds(const struct ndr_syntax_id *id)
118 {
119         uint32_t i;
120
121         for (i = 0; i < rpc_lookup_size; i++) {
122                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
123                         return rpc_lookup[i].cmds;
124                 }
125         }
126
127         return NULL;
128 }
129
130 bool rpc_srv_get_pipe_interface_by_cli_name(const char *cli_name,
131                                             struct ndr_syntax_id *id)
132 {
133         uint32_t i;
134
135         for (i = 0; i < rpc_lookup_size; i++) {
136                 if (strequal(rpc_lookup[i].pipe.clnt, cli_name)) {
137                         if (id) {
138                                 *id = rpc_lookup[i].rpc_interface;
139                         }
140                         return true;
141                 }
142         }
143
144         return false;
145 }
146
147 /*******************************************************************
148  Register commands to an RPC pipe
149 *******************************************************************/
150
151 NTSTATUS rpc_srv_register(int version, const char *clnt, const char *srv,
152                           const struct ndr_interface_table *iface,
153                           const struct api_struct *cmds, int size)
154 {
155         struct rpc_table *rpc_entry;
156
157         if (!clnt || !srv || !cmds) {
158                 return NT_STATUS_INVALID_PARAMETER;
159         }
160
161         if (version != SMB_RPC_INTERFACE_VERSION) {
162                 DEBUG(0,("Can't register rpc commands!\n"
163                          "You tried to register a rpc module with SMB_RPC_INTERFACE_VERSION %d"
164                          ", while this version of samba uses version %d!\n",
165                          version,SMB_RPC_INTERFACE_VERSION));
166                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
167         }
168
169         /* Don't register the same command twice */
170         if (rpc_srv_pipe_exists_by_id(&iface->syntax_id)) {
171                 return NT_STATUS_OK;
172         }
173
174         /*
175          * We use a temporary variable because this call can fail and
176          * rpc_lookup will still be valid afterwards.  It could then succeed if
177          * called again later
178          */
179         rpc_lookup_size++;
180         rpc_entry = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(rpc_lookup, struct rpc_table, rpc_lookup_size);
181         if (NULL == rpc_entry) {
182                 rpc_lookup_size--;
183                 DEBUG(0, ("rpc_pipe_register_commands: memory allocation failed\n"));
184                 return NT_STATUS_NO_MEMORY;
185         } else {
186                 rpc_lookup = rpc_entry;
187         }
188
189         rpc_entry = rpc_lookup + (rpc_lookup_size - 1);
190         ZERO_STRUCTP(rpc_entry);
191         rpc_entry->pipe.clnt = SMB_STRDUP(clnt);
192         rpc_entry->pipe.srv = SMB_STRDUP(srv);
193         rpc_entry->rpc_interface = iface->syntax_id;
194         rpc_entry->cmds = cmds;
195         rpc_entry->n_cmds = size;
196
197         return NT_STATUS_OK;
198 }