RIP BOOL. Convert BOOL -> bool. I found a few interesting
[nivanova/samba-autobuild/.git] / source3 / rpc_server / srv_srvsvc.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1997,
5  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
6  *  Copyright (C) Paul Ashton                       1997,
7  *  Copyright (C) Jeremy Allison                    2001,
8  *  Copyright (C) Jim McDonough <jmcd@us.ibm.com>   2003.
9  *  Copyright (C) Gera;d (Jerry) Carter             2006.
10  *  
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 3 of the License, or
14  *  (at your option) any later version.
15  *  
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *  
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /* This is the interface to the srvsvc pipe. */
26
27 #include "includes.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_RPC_SRV
31
32 static bool proxy_srvsvc_call(pipes_struct *p, uint8 opnum)
33 {
34         struct api_struct *fns;
35         int n_fns;
36
37         lsarpc_get_pipe_fns(&fns, &n_fns);
38
39         if (opnum >= n_fns)
40                 return False;
41
42         if (fns[opnum].opnum != opnum) {
43                 smb_panic("LSA function table not sorted\n");
44         }
45
46         return fns[opnum].fn(p);
47 }
48
49 /*******************************************************************
50  api_srv_net_srv_get_info
51 ********************************************************************/
52
53 static bool api_srv_net_srv_get_info(pipes_struct *p)
54 {
55         SRV_Q_NET_SRV_GET_INFO q_u;
56         SRV_R_NET_SRV_GET_INFO r_u;
57         prs_struct *data = &p->in_data.data;
58         prs_struct *rdata = &p->out_data.rdata;
59
60         ZERO_STRUCT(q_u);
61         ZERO_STRUCT(r_u);
62
63         /* grab the net server get info */
64         if (!srv_io_q_net_srv_get_info("", &q_u, data, 0))
65                 return False;
66
67         r_u.status = _srv_net_srv_get_info(p, &q_u, &r_u);
68
69         /* store the response in the SMB stream */
70         if (!srv_io_r_net_srv_get_info("", &r_u, rdata, 0))
71                 return False;
72
73         return True;
74 }
75
76 /*******************************************************************
77  api_srv_net_srv_get_info
78 ********************************************************************/
79
80 static bool api_srv_net_srv_set_info(pipes_struct *p)
81 {
82         SRV_Q_NET_SRV_SET_INFO q_u;
83         SRV_R_NET_SRV_SET_INFO r_u;
84         prs_struct *data = &p->in_data.data;
85         prs_struct *rdata = &p->out_data.rdata;
86
87         ZERO_STRUCT(q_u);
88         ZERO_STRUCT(r_u);
89
90         /* grab the net server set info */
91         if (!srv_io_q_net_srv_set_info("", &q_u, data, 0))
92                 return False;
93
94         r_u.status = _srv_net_srv_set_info(p, &q_u, &r_u);
95
96         /* store the response in the SMB stream */
97         if (!srv_io_r_net_srv_set_info("", &r_u, rdata, 0))
98                 return False;
99
100         return True;
101 }
102
103 /*******************************************************************
104  api_srv_net_file_enum
105 ********************************************************************/
106
107 static bool api_srv_net_file_enum(pipes_struct *p)
108 {
109         SRV_Q_NET_FILE_ENUM q_u;
110         SRV_R_NET_FILE_ENUM r_u;
111         prs_struct *data = &p->in_data.data;
112         prs_struct *rdata = &p->out_data.rdata;
113
114         ZERO_STRUCT(q_u);
115         ZERO_STRUCT(r_u);
116
117         /* grab the net file enum */
118         if (!srv_io_q_net_file_enum("", &q_u, data, 0))
119                 return False;
120
121         r_u.status = _srv_net_file_enum(p, &q_u, &r_u);
122
123         /* store the response in the SMB stream */
124         if(!srv_io_r_net_file_enum("", &r_u, rdata, 0))
125                 return False;
126
127         return True;
128 }
129
130 /*******************************************************************
131  api_srv_net_conn_enum
132 ********************************************************************/
133
134 static bool api_srv_net_conn_enum(pipes_struct *p)
135 {
136         SRV_Q_NET_CONN_ENUM q_u;
137         SRV_R_NET_CONN_ENUM r_u;
138         prs_struct *data = &p->in_data.data;
139         prs_struct *rdata = &p->out_data.rdata;
140
141         ZERO_STRUCT(q_u);
142         ZERO_STRUCT(r_u);
143
144         /* grab the net server get enum */
145         if (!srv_io_q_net_conn_enum("", &q_u, data, 0))
146                 return False;
147
148         r_u.status = _srv_net_conn_enum(p, &q_u, &r_u);
149
150         /* store the response in the SMB stream */
151         if (!srv_io_r_net_conn_enum("", &r_u, rdata, 0))
152                 return False;
153
154         return True;
155 }
156
157 /*******************************************************************
158  Enumerate sessions.
159 ********************************************************************/
160
161 static bool api_srv_net_sess_enum(pipes_struct *p)
162 {
163         SRV_Q_NET_SESS_ENUM q_u;
164         SRV_R_NET_SESS_ENUM r_u;
165         prs_struct *data = &p->in_data.data;
166         prs_struct *rdata = &p->out_data.rdata;
167
168         ZERO_STRUCT(q_u);
169         ZERO_STRUCT(r_u);
170
171         /* grab the net server get enum */
172         if (!srv_io_q_net_sess_enum("", &q_u, data, 0))
173                 return False;
174
175         /* construct reply.  always indicate success */
176         r_u.status = _srv_net_sess_enum(p, &q_u, &r_u);
177
178         /* store the response in the SMB stream */
179         if (!srv_io_r_net_sess_enum("", &r_u, rdata, 0))
180                 return False;
181
182         return True;
183 }
184
185 /*******************************************************************
186  Delete session.
187 ********************************************************************/
188
189 static bool api_srv_net_sess_del(pipes_struct *p)
190 {
191         SRV_Q_NET_SESS_DEL q_u;
192         SRV_R_NET_SESS_DEL r_u;
193         prs_struct *data = &p->in_data.data;
194         prs_struct *rdata = &p->out_data.rdata;
195
196         ZERO_STRUCT(q_u);
197         ZERO_STRUCT(r_u);
198
199         /* grab the net server get enum */
200         if (!srv_io_q_net_sess_del("", &q_u, data, 0))
201                 return False;
202
203         /* construct reply.  always indicate success */
204         r_u.status = _srv_net_sess_del(p, &q_u, &r_u);
205
206         /* store the response in the SMB stream */
207         if (!srv_io_r_net_sess_del("", &r_u, rdata, 0))
208                 return False;
209
210         return True;
211 }
212
213 /*******************************************************************
214  RPC to enumerate shares.
215 ********************************************************************/
216
217 static bool api_srv_net_share_enum_all(pipes_struct *p)
218 {
219         SRV_Q_NET_SHARE_ENUM q_u;
220         SRV_R_NET_SHARE_ENUM r_u;
221         prs_struct *data = &p->in_data.data;
222         prs_struct *rdata = &p->out_data.rdata;
223
224         ZERO_STRUCT(q_u);
225         ZERO_STRUCT(r_u);
226
227         /* Unmarshall the net server get enum. */
228         if(!srv_io_q_net_share_enum("", &q_u, data, 0)) {
229                 DEBUG(0,("api_srv_net_share_enum_all: Failed to unmarshall SRV_Q_NET_SHARE_ENUM.\n"));
230                 return False;
231         }
232
233         r_u.status = _srv_net_share_enum_all(p, &q_u, &r_u);
234
235         if (!srv_io_r_net_share_enum("", &r_u, rdata, 0)) {
236                 DEBUG(0,("api_srv_net_share_enum_all: Failed to marshall SRV_R_NET_SHARE_ENUM.\n"));
237                 return False;
238         }
239
240         return True;
241 }
242
243 /*******************************************************************
244  RPC to enumerate shares.
245 ********************************************************************/
246
247 static bool api_srv_net_share_enum(pipes_struct *p)
248 {
249         SRV_Q_NET_SHARE_ENUM q_u;
250         SRV_R_NET_SHARE_ENUM r_u;
251         prs_struct *data = &p->in_data.data;
252         prs_struct *rdata = &p->out_data.rdata;
253
254         ZERO_STRUCT(q_u);
255         ZERO_STRUCT(r_u);
256
257         /* Unmarshall the net server get enum. */
258         if(!srv_io_q_net_share_enum("", &q_u, data, 0)) {
259                 DEBUG(0,("api_srv_net_share_enum: Failed to unmarshall SRV_Q_NET_SHARE_ENUM.\n"));
260                 return False;
261         }
262
263         r_u.status = _srv_net_share_enum(p, &q_u, &r_u);
264
265         if (!srv_io_r_net_share_enum("", &r_u, rdata, 0)) {
266                 DEBUG(0,("api_srv_net_share_enum: Failed to marshall SRV_R_NET_SHARE_ENUM.\n"));
267                 return False;
268         }
269
270         return True;
271 }
272
273 /*******************************************************************
274  RPC to return share information.
275 ********************************************************************/
276
277 static bool api_srv_net_share_get_info(pipes_struct *p)
278 {
279         SRV_Q_NET_SHARE_GET_INFO q_u;
280         SRV_R_NET_SHARE_GET_INFO r_u;
281         prs_struct *data = &p->in_data.data;
282         prs_struct *rdata = &p->out_data.rdata;
283
284         ZERO_STRUCT(q_u);
285         ZERO_STRUCT(r_u);
286
287         /* Unmarshall the net server get info. */
288         if(!srv_io_q_net_share_get_info("", &q_u, data, 0)) {
289                 DEBUG(0,("api_srv_net_share_get_info: Failed to unmarshall SRV_Q_NET_SHARE_GET_INFO.\n"));
290                 return False;
291         }
292
293         r_u.status = _srv_net_share_get_info(p, &q_u, &r_u);
294
295         if(!srv_io_r_net_share_get_info("", &r_u, rdata, 0)) {
296                 DEBUG(0,("api_srv_net_share_get_info: Failed to marshall SRV_R_NET_SHARE_GET_INFO.\n"));
297                 return False;
298         }
299
300         return True;
301 }
302
303 /*******************************************************************
304  RPC to set share information.
305 ********************************************************************/
306
307 static bool api_srv_net_share_set_info(pipes_struct *p)
308 {
309         SRV_Q_NET_SHARE_SET_INFO q_u;
310         SRV_R_NET_SHARE_SET_INFO r_u;
311         prs_struct *data = &p->in_data.data;
312         prs_struct *rdata = &p->out_data.rdata;
313
314         ZERO_STRUCT(q_u);
315         ZERO_STRUCT(r_u);
316
317         /* Unmarshall the net server set info. */
318         if(!srv_io_q_net_share_set_info("", &q_u, data, 0)) {
319                 DEBUG(0,("api_srv_net_share_set_info: Failed to unmarshall SRV_Q_NET_SHARE_SET_INFO.\n"));
320                 return False;
321         }
322
323         r_u.status = _srv_net_share_set_info(p, &q_u, &r_u);
324
325         if(!srv_io_r_net_share_set_info("", &r_u, rdata, 0)) {
326                 DEBUG(0,("api_srv_net_share_set_info: Failed to marshall SRV_R_NET_SHARE_SET_INFO.\n"));
327                 return False;
328         }
329
330         return True;
331 }
332
333 /*******************************************************************
334  RPC to add share information.
335 ********************************************************************/
336
337 static bool api_srv_net_share_add(pipes_struct *p)
338 {
339         SRV_Q_NET_SHARE_ADD q_u;
340         SRV_R_NET_SHARE_ADD r_u;
341         prs_struct *data = &p->in_data.data;
342         prs_struct *rdata = &p->out_data.rdata;
343
344         ZERO_STRUCT(q_u);
345         ZERO_STRUCT(r_u);
346
347         /* Unmarshall the net server add info. */
348         if(!srv_io_q_net_share_add("", &q_u, data, 0)) {
349                 DEBUG(0,("api_srv_net_share_add: Failed to unmarshall SRV_Q_NET_SHARE_ADD.\n"));
350                 return False;
351         }
352
353         r_u.status = _srv_net_share_add(p, &q_u, &r_u);
354
355         if(!srv_io_r_net_share_add("", &r_u, rdata, 0)) {
356                 DEBUG(0,("api_srv_net_share_add: Failed to marshall SRV_R_NET_SHARE_ADD.\n"));
357                 return False;
358         }
359
360         return True;
361 }
362
363 /*******************************************************************
364  RPC to delete share information.
365 ********************************************************************/
366
367 static bool api_srv_net_share_del(pipes_struct *p)
368 {
369         SRV_Q_NET_SHARE_DEL q_u;
370         SRV_R_NET_SHARE_DEL r_u;
371         prs_struct *data = &p->in_data.data;
372         prs_struct *rdata = &p->out_data.rdata;
373
374         ZERO_STRUCT(q_u);
375         ZERO_STRUCT(r_u);
376
377         /* Unmarshall the net server del info. */
378         if(!srv_io_q_net_share_del("", &q_u, data, 0)) {
379                 DEBUG(0,("api_srv_net_share_del: Failed to unmarshall SRV_Q_NET_SHARE_DEL.\n"));
380                 return False;
381         }
382
383         r_u.status = _srv_net_share_del(p, &q_u, &r_u);
384
385         if(!srv_io_r_net_share_del("", &r_u, rdata, 0)) {
386                 DEBUG(0,("api_srv_net_share_del: Failed to marshall SRV_R_NET_SHARE_DEL.\n"));
387                 return False;
388         }
389
390         return True;
391 }
392
393 /*******************************************************************
394  RPC to delete share information.
395 ********************************************************************/
396
397 static bool api_srv_net_share_del_sticky(pipes_struct *p)
398 {
399         SRV_Q_NET_SHARE_DEL q_u;
400         SRV_R_NET_SHARE_DEL r_u;
401         prs_struct *data = &p->in_data.data;
402         prs_struct *rdata = &p->out_data.rdata;
403
404         ZERO_STRUCT(q_u);
405         ZERO_STRUCT(r_u);
406
407         /* Unmarshall the net server del info. */
408         if(!srv_io_q_net_share_del("", &q_u, data, 0)) {
409                 DEBUG(0,("api_srv_net_share_del_sticky: Failed to unmarshall SRV_Q_NET_SHARE_DEL.\n"));
410                 return False;
411         }
412
413         r_u.status = _srv_net_share_del_sticky(p, &q_u, &r_u);
414
415         if(!srv_io_r_net_share_del("", &r_u, rdata, 0)) {
416                 DEBUG(0,("api_srv_net_share_del_sticky: Failed to marshall SRV_R_NET_SHARE_DEL.\n"));
417                 return False;
418         }
419
420         return True;
421 }
422
423 /*******************************************************************
424  api_srv_net_remote_tod
425 ********************************************************************/
426
427 static bool api_srv_net_remote_tod(pipes_struct *p)
428 {
429         SRV_Q_NET_REMOTE_TOD q_u;
430         SRV_R_NET_REMOTE_TOD r_u;
431         prs_struct *data = &p->in_data.data;
432         prs_struct *rdata = &p->out_data.rdata;
433
434         ZERO_STRUCT(q_u);
435         ZERO_STRUCT(r_u);
436
437         /* grab the net server get enum */
438         if(!srv_io_q_net_remote_tod("", &q_u, data, 0))
439                 return False;
440
441         r_u.status = _srv_net_remote_tod(p, &q_u, &r_u);
442
443         /* store the response in the SMB stream */
444         if(!srv_io_r_net_remote_tod("", &r_u, rdata, 0))
445                 return False;
446
447         return True;
448 }
449
450 /*******************************************************************
451  RPC to enumerate disks available on a server e.g. C:, D: ...
452 *******************************************************************/
453
454 static bool api_srv_net_disk_enum(pipes_struct *p) 
455 {
456         SRV_Q_NET_DISK_ENUM q_u;
457         SRV_R_NET_DISK_ENUM r_u;
458         prs_struct *data = &p->in_data.data;
459         prs_struct *rdata = &p->out_data.rdata;
460
461         ZERO_STRUCT(q_u);
462         ZERO_STRUCT(r_u);
463
464         /* Unmarshall the net server disk enum. */
465         if(!srv_io_q_net_disk_enum("", &q_u, data, 0)) {
466                 DEBUG(0,("api_srv_net_disk_enum: Failed to unmarshall SRV_Q_NET_DISK_ENUM.\n"));
467                 return False;
468         }
469
470         r_u.status = _srv_net_disk_enum(p, &q_u, &r_u);
471
472         if(!srv_io_r_net_disk_enum("", &r_u, rdata, 0)) {
473                 DEBUG(0,("api_srv_net_disk_enum: Failed to marshall SRV_R_NET_DISK_ENUM.\n"));
474                 return False;
475         }
476
477         return True;
478 }
479
480 /*******************************************************************
481  NetValidateName (opnum 0x21) 
482 *******************************************************************/
483
484 static bool api_srv_net_name_validate(pipes_struct *p) 
485 {
486         SRV_Q_NET_NAME_VALIDATE q_u;
487         SRV_R_NET_NAME_VALIDATE r_u;
488         prs_struct *data = &p->in_data.data;
489         prs_struct *rdata = &p->out_data.rdata;
490  
491         ZERO_STRUCT(q_u);
492         ZERO_STRUCT(r_u);
493   
494         /* Unmarshall the net server disk enum. */
495         if(!srv_io_q_net_name_validate("", &q_u, data, 0)) {
496                 DEBUG(0,("api_srv_net_name_validate: Failed to unmarshall SRV_Q_NET_NAME_VALIDATE.\n"));
497                 return False;
498         }
499
500         r_u.status = _srv_net_name_validate(p, &q_u, &r_u);
501
502         if(!srv_io_r_net_name_validate("", &r_u, rdata, 0)) {
503                 DEBUG(0,("api_srv_net_name_validate: Failed to marshall SRV_R_NET_NAME_VALIDATE.\n"));
504                 return False;
505         }
506
507         return True;
508 }
509
510 /*******************************************************************
511  NetFileQuerySecdesc (opnum 0x27)
512 *******************************************************************/
513
514 static bool api_srv_net_file_query_secdesc(pipes_struct *p)
515 {
516         SRV_Q_NET_FILE_QUERY_SECDESC q_u;
517         SRV_R_NET_FILE_QUERY_SECDESC r_u;
518         prs_struct *data = &p->in_data.data;
519         prs_struct *rdata = &p->out_data.rdata;
520
521         ZERO_STRUCT(q_u);
522         ZERO_STRUCT(r_u);
523
524         /* Unmarshall the net file get info from Win9x */
525         if(!srv_io_q_net_file_query_secdesc("", &q_u, data, 0)) {
526                 DEBUG(0,("api_srv_net_file_query_secdesc: Failed to unmarshall SRV_Q_NET_FILE_QUERY_SECDESC.\n"));
527                 return False;
528         }
529
530         r_u.status = _srv_net_file_query_secdesc(p, &q_u, &r_u);
531
532         if(!srv_io_r_net_file_query_secdesc("", &r_u, rdata, 0)) {
533                 DEBUG(0,("api_srv_net_file_query_secdesc: Failed to marshall SRV_R_NET_FILE_QUERY_SECDESC.\n"));
534                 return False;
535         }
536
537         return True;
538 }
539
540 /*******************************************************************
541  NetFileSetSecdesc (opnum 0x28)
542 *******************************************************************/
543
544 static bool api_srv_net_file_set_secdesc(pipes_struct *p)
545 {
546         SRV_Q_NET_FILE_SET_SECDESC q_u;
547         SRV_R_NET_FILE_SET_SECDESC r_u;
548         prs_struct *data = &p->in_data.data;
549         prs_struct *rdata = &p->out_data.rdata;
550
551         ZERO_STRUCT(q_u);
552         ZERO_STRUCT(r_u);
553
554         /* Unmarshall the net file set info from Win9x */
555         if(!srv_io_q_net_file_set_secdesc("", &q_u, data, 0)) {
556                 DEBUG(0,("api_srv_net_file_set_secdesc: Failed to unmarshall SRV_Q_NET_FILE_SET_SECDESC.\n"));
557                 return False;
558         }
559
560         r_u.status = _srv_net_file_set_secdesc(p, &q_u, &r_u);
561
562         if(!srv_io_r_net_file_set_secdesc("", &r_u, rdata, 0)) {
563                 DEBUG(0,("api_srv_net_file_set_secdesc: Failed to marshall SRV_R_NET_FILE_SET_SECDESC.\n"));
564                 return False;
565         }
566
567         return True;
568 }
569
570 /*******************************************************************
571 *******************************************************************/
572
573 static bool api_srv_net_file_close(pipes_struct *p)
574 {
575         return proxy_srvsvc_call( p, NDR_SRVSVC_NETFILECLOSE );
576 }
577
578 /*******************************************************************
579 \PIPE\srvsvc commands
580 ********************************************************************/
581
582 static struct api_struct api_srv_cmds[] =
583 {
584       { "SRV_NET_CONN_ENUM"         , SRV_NET_CONN_ENUM         , api_srv_net_conn_enum          },
585       { "SRV_NET_SESS_ENUM"         , SRV_NET_SESS_ENUM         , api_srv_net_sess_enum          },
586       { "SRV_NET_SESS_DEL"          , SRV_NET_SESS_DEL          , api_srv_net_sess_del           },
587       { "SRV_NET_SHARE_ENUM_ALL"    , SRV_NET_SHARE_ENUM_ALL    , api_srv_net_share_enum_all     },
588       { "SRV_NET_SHARE_ENUM"        , SRV_NET_SHARE_ENUM        , api_srv_net_share_enum         },
589       { "SRV_NET_SHARE_ADD"         , SRV_NET_SHARE_ADD         , api_srv_net_share_add          },
590       { "SRV_NET_SHARE_DEL"         , SRV_NET_SHARE_DEL         , api_srv_net_share_del          },
591       { "SRV_NET_SHARE_DEL_STICKY"  , SRV_NET_SHARE_DEL_STICKY  , api_srv_net_share_del_sticky   },
592       { "SRV_NET_SHARE_GET_INFO"    , SRV_NET_SHARE_GET_INFO    , api_srv_net_share_get_info     },
593       { "SRV_NET_SHARE_SET_INFO"    , SRV_NET_SHARE_SET_INFO    , api_srv_net_share_set_info     },
594       { "SRV_NET_FILE_ENUM"         , SRV_NET_FILE_ENUM         , api_srv_net_file_enum          },
595       { "SRV_NET_SRV_GET_INFO"      , SRV_NET_SRV_GET_INFO      , api_srv_net_srv_get_info       },
596       { "SRV_NET_SRV_SET_INFO"      , SRV_NET_SRV_SET_INFO      , api_srv_net_srv_set_info       },
597       { "SRV_NET_REMOTE_TOD"        , SRV_NET_REMOTE_TOD        , api_srv_net_remote_tod         },
598       { "SRV_NET_DISK_ENUM"         , SRV_NET_DISK_ENUM         , api_srv_net_disk_enum          },
599       { "SRV_NET_NAME_VALIDATE"     , SRV_NET_NAME_VALIDATE     , api_srv_net_name_validate      },
600       { "SRV_NET_FILE_QUERY_SECDESC", SRV_NET_FILE_QUERY_SECDESC, api_srv_net_file_query_secdesc },
601       { "SRV_NET_FILE_SET_SECDESC"  , SRV_NET_FILE_SET_SECDESC  , api_srv_net_file_set_secdesc   },
602       { "SRV_NET_FILE_CLOSE"        , SRV_NET_FILE_CLOSE        , api_srv_net_file_close         }
603 };
604
605 void srvsvc2_get_pipe_fns( struct api_struct **fns, int *n_fns )
606 {
607         *fns = api_srv_cmds;
608         *n_fns = sizeof(api_srv_cmds) / sizeof(struct api_struct);
609 }
610
611
612 NTSTATUS rpc_srvsvc2_init(void)
613 {
614   return rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, "srvsvc", "ntsvcs", api_srv_cmds,
615                                     sizeof(api_srv_cmds) / sizeof(struct api_struct));
616 }