3753596a2b135502d28f6fbee412ab8b7a999e74
[samba.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         bool (*shutdown_fn)(void *private_data);
35         void *shutdown_data;
36 };
37
38 static struct rpc_table *rpc_lookup;
39 static uint32_t rpc_lookup_size;
40
41 static struct rpc_table *rpc_srv_get_pipe_by_id(const struct ndr_syntax_id *id)
42 {
43         uint32_t i;
44
45         for (i = 0; i < rpc_lookup_size; i++) {
46                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
47                         return &rpc_lookup[i];
48                 }
49         }
50
51         return NULL;
52 }
53
54 bool rpc_srv_pipe_exists_by_id(const struct ndr_syntax_id *id)
55 {
56         uint32_t i;
57
58         for (i = 0; i < rpc_lookup_size; i++) {
59                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
60                         return true;
61                 }
62         }
63
64         return false;
65 }
66
67 bool rpc_srv_pipe_exists_by_cli_name(const char *cli_name)
68 {
69         uint32_t i;
70
71         for (i = 0; i < rpc_lookup_size; i++) {
72                 if (strequal(rpc_lookup[i].pipe.clnt, cli_name)) {
73                         return true;
74                 }
75         }
76
77         return false;
78 }
79
80 bool rpc_srv_pipe_exists_by_srv_name(const char *srv_name)
81 {
82         uint32_t i;
83
84         for (i = 0; i < rpc_lookup_size; i++) {
85                 if (strequal(rpc_lookup[i].pipe.srv, srv_name)) {
86                         return true;
87                 }
88         }
89
90         return false;
91 }
92
93 const char *rpc_srv_get_pipe_cli_name(const struct ndr_syntax_id *id)
94 {
95         uint32_t i;
96
97         for (i = 0; i < rpc_lookup_size; i++) {
98                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
99                         return rpc_lookup[i].pipe.clnt;
100                 }
101         }
102
103         return NULL;
104 }
105
106 const char *rpc_srv_get_pipe_srv_name(const struct ndr_syntax_id *id)
107 {
108         uint32_t i;
109
110         for (i = 0; i < rpc_lookup_size; i++) {
111                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
112                         return rpc_lookup[i].pipe.srv;
113                 }
114         }
115
116         return NULL;
117 }
118
119 uint32_t rpc_srv_get_pipe_num_cmds(const struct ndr_syntax_id *id)
120 {
121         uint32_t i;
122
123         for (i = 0; i < rpc_lookup_size; i++) {
124                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
125                         return rpc_lookup[i].n_cmds;
126                 }
127         }
128
129         return 0;
130 }
131
132 const struct api_struct *rpc_srv_get_pipe_cmds(const struct ndr_syntax_id *id)
133 {
134         uint32_t i;
135
136         for (i = 0; i < rpc_lookup_size; i++) {
137                 if (ndr_syntax_id_equal(&rpc_lookup[i].rpc_interface, id)) {
138                         return rpc_lookup[i].cmds;
139                 }
140         }
141
142         return NULL;
143 }
144
145 bool rpc_srv_get_pipe_interface_by_cli_name(const char *cli_name,
146                                             struct ndr_syntax_id *id)
147 {
148         uint32_t i;
149
150         for (i = 0; i < rpc_lookup_size; i++) {
151                 if (strequal(rpc_lookup[i].pipe.clnt, cli_name)) {
152                         if (id) {
153                                 *id = rpc_lookup[i].rpc_interface;
154                         }
155                         return true;
156                 }
157         }
158
159         return false;
160 }
161
162 /*******************************************************************
163  Register commands to an RPC pipe
164 *******************************************************************/
165
166 NTSTATUS rpc_srv_register(int version, const char *clnt, const char *srv,
167                           const struct ndr_interface_table *iface,
168                           const struct api_struct *cmds, int size,
169                           const struct rpc_srv_callbacks *rpc_srv_cb)
170 {
171         struct rpc_table *rpc_entry;
172
173         if (!clnt || !srv || !cmds) {
174                 return NT_STATUS_INVALID_PARAMETER;
175         }
176
177         if (version != SMB_RPC_INTERFACE_VERSION) {
178                 DEBUG(0,("Can't register rpc commands!\n"
179                          "You tried to register a rpc module with SMB_RPC_INTERFACE_VERSION %d"
180                          ", while this version of samba uses version %d!\n",
181                          version,SMB_RPC_INTERFACE_VERSION));
182                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
183         }
184
185         /* Don't register the same command twice */
186         if (rpc_srv_pipe_exists_by_id(&iface->syntax_id)) {
187                 return NT_STATUS_OK;
188         }
189
190         /*
191          * We use a temporary variable because this call can fail and
192          * rpc_lookup will still be valid afterwards.  It could then succeed if
193          * called again later
194          */
195         rpc_lookup_size++;
196         rpc_entry = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(rpc_lookup, struct rpc_table, rpc_lookup_size);
197         if (NULL == rpc_entry) {
198                 rpc_lookup_size--;
199                 DEBUG(0, ("rpc_pipe_register_commands: memory allocation failed\n"));
200                 return NT_STATUS_NO_MEMORY;
201         } else {
202                 rpc_lookup = rpc_entry;
203         }
204
205         rpc_entry = rpc_lookup + (rpc_lookup_size - 1);
206         ZERO_STRUCTP(rpc_entry);
207         rpc_entry->pipe.clnt = SMB_STRDUP(clnt);
208         rpc_entry->pipe.srv = SMB_STRDUP(srv);
209         rpc_entry->rpc_interface = iface->syntax_id;
210         rpc_entry->cmds = cmds;
211         rpc_entry->n_cmds = size;
212
213         if (rpc_srv_cb != NULL) {
214                 rpc_entry->shutdown_fn = rpc_srv_cb->shutdown;
215                 rpc_entry->shutdown_data = rpc_srv_cb->private_data;
216
217                 if (rpc_srv_cb->init != NULL &&
218                     !rpc_srv_cb->init(rpc_srv_cb->private_data)) {
219                         DEBUG(0, ("rpc_srv_register: Failed to call the %s "
220                                   "init function!\n", srv));
221                         return NT_STATUS_UNSUCCESSFUL;
222                 }
223         }
224
225         return NT_STATUS_OK;
226 }
227
228 NTSTATUS rpc_srv_unregister(const struct ndr_interface_table *iface)
229 {
230         struct rpc_table *rpc_entry = rpc_srv_get_pipe_by_id(&iface->syntax_id);
231
232         if (rpc_entry != NULL && rpc_entry->shutdown_fn != NULL) {
233                 if (!rpc_entry->shutdown_fn(rpc_entry->shutdown_data)) {
234                         DEBUG(0, ("rpc_srv_unregister: Failed to call the %s "
235                                   "init function!\n", rpc_entry->pipe.srv));
236                         return NT_STATUS_UNSUCCESSFUL;
237                 }
238         }
239
240         return NT_STATUS_OK;
241 }