00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <errno.h>
00041 #include <fcntl.h>
00042 #include <unistd.h>
00043 #include <signal.h>
00044
00045 #include "../../dprint.h"
00046 #include "../../ut.h"
00047 #include "../../lib/kmi/mi.h"
00048 #include "../../mem/mem.h"
00049 #include "../../mem/shm_mem.h"
00050 #include "../../cfg/cfg_struct.h"
00051 #include "mi_fifo.h"
00052 #include "fifo_fnc.h"
00053 #include "mi_parser.h"
00054 #include "mi_writer.h"
00055
00056 static int mi_fifo_read = 0;
00057 static int mi_fifo_write = 0;
00058 static char *mi_buf = 0;
00059 static char *reply_fifo_s = 0;
00060 static int reply_fifo_len = 0;
00061
00062
00064 FILE *mi_init_fifo_server(char *fifo_name, int mi_fifo_mode,
00065 int mi_fifo_uid, int mi_fifo_gid, char* fifo_reply_dir)
00066 {
00067 FILE *fifo_stream;
00068 long opt;
00069
00070
00071 if ((mkfifo(fifo_name, mi_fifo_mode)<0)) {
00072 LM_ERR("Can't create FIFO: %s (mode=%d)\n", strerror(errno), mi_fifo_mode);
00073 return 0;
00074 }
00075
00076 LM_DBG("FIFO created @ %s\n", fifo_name );
00077
00078 if ((chmod(fifo_name, mi_fifo_mode)<0)) {
00079 LM_ERR("Can't chmod FIFO: %s (mode=%d)\n", strerror(errno), mi_fifo_mode);
00080 return 0;
00081 }
00082
00083 if ((mi_fifo_uid!=-1) || (mi_fifo_gid!=-1)){
00084 if (chown(fifo_name, mi_fifo_uid, mi_fifo_gid)<0){
00085 LM_ERR("Failed to change the owner/group for %s to %d.%d; %s[%d]\n",
00086 fifo_name, mi_fifo_uid, mi_fifo_gid, strerror(errno), errno);
00087 return 0;
00088 }
00089 }
00090
00091 LM_DBG("fifo %s opened, mode=%o\n", fifo_name, mi_fifo_mode );
00092
00093
00094
00095 mi_fifo_read=open(fifo_name, O_RDONLY|O_NONBLOCK, 0);
00096 if (mi_fifo_read<0) {
00097 LM_ERR("Can't open fifo %s for reading - mi_fifo_read did not open: %s\n", fifo_name, strerror(errno));
00098 return 0;
00099 }
00100
00101 fifo_stream = fdopen(mi_fifo_read, "r");
00102 if (fifo_stream==NULL) {
00103 LM_ERR("fdopen failed on %s: %s\n", fifo_name, strerror(errno));
00104 return 0;
00105 }
00106
00107
00108 mi_fifo_write=open( fifo_name, O_WRONLY|O_NONBLOCK, 0);
00109 if (mi_fifo_write<0) {
00110 LM_ERR("fifo_write did not open: %s\n", strerror(errno));
00111 return 0;
00112 }
00113
00114 if ((opt=fcntl(mi_fifo_read, F_GETFL))==-1){
00115 LM_ERR("fcntl(F_GETFL) failed: %s [%d]\n", strerror(errno), errno);
00116 return 0;
00117 }
00118 if (fcntl(mi_fifo_read, F_SETFL, opt & (~O_NONBLOCK))==-1){
00119 LM_ERR("cntl(F_SETFL) failed: %s [%d]\n", strerror(errno), errno);
00120 return 0;
00121 }
00122
00123
00124 mi_buf = pkg_malloc(MAX_MI_FIFO_BUFFER);
00125 reply_fifo_s = pkg_malloc(MAX_MI_FILENAME);
00126 if ( mi_buf==NULL|| reply_fifo_s==NULL) {
00127 LM_ERR("no more private memory\n");
00128 return 0;
00129 }
00130
00131
00132 reply_fifo_len = strlen(fifo_reply_dir);
00133 memcpy( reply_fifo_s, fifo_reply_dir, reply_fifo_len);
00134
00135 return fifo_stream;
00136 }
00137
00138
00139
00145 static int mi_fifo_check(int fd, char* fname)
00146 {
00147 struct stat fst;
00148 struct stat lst;
00149
00150 if (fstat(fd, &fst)<0){
00151 LM_ERR("security: fstat on %s failed: %s\n", fname, strerror(errno));
00152 return -1;
00153 }
00154
00155 if (!S_ISFIFO(fst.st_mode)){
00156 LM_ERR("security: %s is not a fifo\n", fname);
00157 return -1;
00158 }
00159
00160 if (fst.st_nlink>1){
00161 LM_ERR("security: fifo_check: %s is hard-linked %d times\n", fname, (unsigned)fst.st_nlink);
00162 return -1;
00163 }
00164
00165
00166 if (lstat(fname, &lst)<0){
00167 LM_ERR("security: lstat on %s failed: %s\n", fname, strerror(errno));
00168 return -1;
00169 }
00170 if (S_ISLNK(lst.st_mode)){
00171 LM_ERR("security: fifo_check: %s is a soft link\n", fname);
00172 return -1;
00173 }
00174
00175
00176
00177 if ((lst.st_dev!=fst.st_dev)||(lst.st_ino!=fst.st_ino)){
00178 LM_ERR("security: fifo_check: inode/dev number differ: %d %d (%s)\n",
00179 (int)fst.st_ino, (int)lst.st_ino, fname);
00180 return -1;
00181 }
00182
00183 return 0;
00184 }
00185
00186
00187
00189 static FILE *mi_open_reply_pipe( char *pipe_name )
00190 {
00191 int fifofd;
00192 FILE *file_handle;
00193 int flags;
00194
00195 int retries=FIFO_REPLY_RETRIES;
00196
00197 if (!pipe_name || *pipe_name==0) {
00198 LM_DBG("No file to write to about missing cmd\n");
00199 return 0;
00200 }
00201
00202 tryagain:
00203
00204
00205 fifofd=open( pipe_name, O_WRONLY | O_NONBLOCK );
00206 if (fifofd==-1) {
00207
00208
00209
00210 if (errno==ENXIO) {
00211
00212 if (retries==0) {
00213 LM_ERR("no client at %s\n",pipe_name );
00214 return 0;
00215 }
00216
00217 if (retries != FIFO_REPLY_RETRIES)
00218 LM_DBG("mi_fifo retry countdown: %d\n", retries );
00219 sleep_us( FIFO_REPLY_WAIT );
00220 retries--;
00221 goto tryagain;
00222 }
00223
00224 LM_ERR("open error (%s): %s\n", pipe_name, strerror(errno));
00225 return 0;
00226 }
00227
00228
00229
00230 if (mi_fifo_check(fifofd, pipe_name)<0)
00231 goto error;
00232
00233
00234 if ( (flags=fcntl(fifofd, F_GETFL, 0))<0) {
00235 LM_ERR("pipe (%s): getfl failed: %s\n", pipe_name, strerror(errno));
00236 goto error;
00237 }
00238 flags&=~O_NONBLOCK;
00239 if (fcntl(fifofd, F_SETFL, flags)<0) {
00240 LM_ERR("pipe (%s): setfl cntl failed: %s\n", pipe_name, strerror(errno));
00241 goto error;
00242 }
00243
00244
00245 file_handle=fdopen( fifofd, "w");
00246 if (file_handle==NULL) {
00247 LM_ERR("open error (%s): %s\n",
00248 pipe_name, strerror(errno));
00249 goto error;
00250 }
00251 return file_handle;
00252 error:
00253 close(fifofd);
00254 return 0;
00255 }
00256
00257
00258
00260 int mi_read_line( char *b, int max, FILE *stream, int *read)
00261 {
00262 int retry_cnt;
00263 int len;
00264 retry_cnt=0;
00265
00266 retry:
00267 if (fgets(b, max, stream)==NULL) {
00268 LM_ERR("fifo_server fgets failed: %s\n", strerror(errno));
00269
00270
00271
00272 if (errno==ESPIPE) {
00273 retry_cnt++;
00274 if (retry_cnt<4)
00275 goto retry;
00276 }
00277
00278 if ((errno==EINTR)||(errno==EAGAIN))
00279 goto retry;
00280 kill(0, SIGTERM);
00281 }
00282
00283
00284
00285
00286
00287 len=strlen(b);
00288 if (len && !(b[len-1]=='\n' || b[len-1]=='\r')) {
00289 LM_ERR("request line too long\n");
00290 return -1;
00291 }
00292 *read = len;
00293
00294 return 0;
00295 }
00296
00297
00298
00300 static inline char *get_reply_filename( char * file, int len )
00301 {
00302 if ( strchr(file,'.') || strchr(file,'/') || strchr(file, '\\') ) {
00303 LM_ERR("Forbidden reply fifo filename: %s\n", file);
00304 return 0;
00305 }
00306
00307 if (reply_fifo_len + len + 1 > MAX_MI_FILENAME) {
00308 LM_ERR("Reply fifo filename too long %d\n",reply_fifo_len + len);
00309 return 0;
00310 }
00311
00312 memcpy( reply_fifo_s+reply_fifo_len, file, len );
00313 reply_fifo_s[reply_fifo_len+len]=0;
00314
00315 return reply_fifo_s;
00316 }
00317
00318
00319 static inline void free_async_handler( struct mi_handler *hdl )
00320 {
00321 if (hdl)
00322 shm_free(hdl);
00323 }
00324
00325
00327 static void fifo_close_async( struct mi_root *mi_rpl, struct mi_handler *hdl, int done)
00328 {
00329 FILE *reply_stream;
00330 char *name;
00331
00332 name = (char*)hdl->param;
00333
00334 if ( mi_rpl!=0 || done ) {
00335
00336 reply_stream = mi_open_reply_pipe( name );
00337 if (reply_stream==NULL) {
00338 LM_ERR("Cannot open reply pipe %s\n", name );
00339 return;
00340 }
00341
00342 if (mi_rpl!=0) {
00343 mi_write_tree( reply_stream, mi_rpl);
00344 free_mi_tree( mi_rpl );
00345 } else {
00346 mi_fifo_reply( reply_stream, "500 command failed\n");
00347 }
00348
00349 fclose(reply_stream);
00350 }
00351
00352 if (done)
00353 free_async_handler( hdl );
00354 return;
00355 }
00356
00357
00358 static inline struct mi_handler* build_async_handler( char *name, int len)
00359 {
00360 struct mi_handler *hdl;
00361 char *p;
00362
00363 hdl = (struct mi_handler*)shm_malloc( sizeof(struct mi_handler) + len + 1);
00364 if (hdl==0) {
00365 LM_ERR("no more shared memory\n");
00366 return 0;
00367 }
00368
00369 p = (char*)(hdl) + sizeof(struct mi_handler);
00370 memcpy( p, name, len+1 );
00371
00372 hdl->handler_f = fifo_close_async;
00373 hdl->param = (void*)p;
00374
00375 return hdl;
00376 }
00377
00378
00379 #define mi_do_consume() \
00380 do { \
00381 LM_DBG("entered consume\n"); \
00382 \
00383 do { \
00384 mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream,&line_len); \
00385 } while(line_len>1); \
00386 LM_DBG("**** done consume\n"); \
00387 } while(0)
00388
00389
00390 #define mi_open_reply(_name,_file,_err) \
00391 do { \
00392 _file = mi_open_reply_pipe( _name ); \
00393 if (_file==NULL) { \
00394 LM_ERR("cannot open reply pipe %s\n", _name); \
00395 goto _err; \
00396 } \
00397 } while(0)
00398
00399
00400
00402 void mi_fifo_server(FILE *fifo_stream)
00403 {
00404 struct mi_root *mi_cmd;
00405 struct mi_root *mi_rpl;
00406 struct mi_handler *hdl;
00407 int line_len;
00408 char *file_sep, *command, *file;
00409 struct mi_cmd *f;
00410 FILE *reply_stream;
00411
00412 while(1) {
00413
00414 cfg_update();
00415
00416 reply_stream = NULL;
00417
00418
00419 if (mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream, &line_len)) {
00420 LM_ERR("failed to read fifo command\n");
00421 goto consume1;
00422 }
00423
00424
00425 while(line_len) {
00426 if(mi_buf[line_len-1]=='\n' || mi_buf[line_len-1]=='\r'
00427 || mi_buf[line_len-1]==' ' || mi_buf[line_len-1]=='\t' ) {
00428 line_len--;
00429 mi_buf[line_len]=0;
00430 } else break;
00431 }
00432
00433 if (line_len==0) {
00434 LM_DBG("fifo command empty\n");
00435 goto consume1;
00436 }
00437 if (line_len<3) {
00438 LM_ERR("fifo command must have at least 3 chars\n");
00439 goto consume1;
00440 }
00441 if (*mi_buf!=MI_CMD_SEPARATOR) {
00442 LM_ERR("fifo command must begin with %c: %.*s\n", MI_CMD_SEPARATOR, line_len, mi_buf );
00443 goto consume1;
00444 }
00445 command = mi_buf+1;
00446 file_sep=strchr(command, MI_CMD_SEPARATOR );
00447 if (file_sep==NULL) {
00448 LM_ERR("file separator missing in fifo command\n");
00449 goto consume1;
00450 }
00451 if (file_sep==command) {
00452 LM_ERR("empty fifo command\n");
00453 goto consume1;
00454 }
00455 if (*(file_sep+1)==0) {
00456 file = NULL;
00457 } else {
00458 file = file_sep+1;
00459 file = get_reply_filename(file, mi_buf+line_len-file);
00460 if (file==NULL) {
00461 LM_ERR("trimming fifo filename\n");
00462 goto consume1;
00463 }
00464 }
00465
00466 *file_sep=0;
00467
00468 f=lookup_mi_cmd( command, strlen(command) );
00469 if (f==0) {
00470 LM_ERR("fifo command %s is not available\n", command);
00471 mi_open_reply( file, reply_stream, consume1);
00472 mi_fifo_reply( reply_stream, "500 command '%s' not available\n",
00473 command);
00474 goto consume2;
00475 }
00476
00477
00478 if (f->flags&MI_ASYNC_RPL_FLAG) {
00479 hdl = build_async_handler( file, strlen(file) );
00480 if (hdl==0) {
00481 LM_ERR("failed to build async fifo handler\n");
00482 mi_open_reply( file, reply_stream, consume1);
00483 mi_fifo_reply( reply_stream, "500 Internal server error\n");
00484 goto consume2;
00485 }
00486 } else {
00487 hdl = 0;
00488 mi_open_reply( file, reply_stream, consume1);
00489 }
00490
00491 if (f->flags&MI_NO_INPUT_FLAG) {
00492 mi_cmd = 0;
00493 mi_do_consume();
00494 } else {
00495 mi_cmd = mi_parse_tree(fifo_stream);
00496 if (mi_cmd==NULL){
00497 LM_ERR("error parsing MI tree\n");
00498 if (!reply_stream)
00499 mi_open_reply( file, reply_stream, consume3);
00500 mi_fifo_reply( reply_stream, "400 parse error in "
00501 "command '%s'\n", command);
00502 goto consume3;
00503 }
00504 mi_cmd->async_hdl = hdl;
00505 }
00506
00507 LM_DBG("done parsing the mi tree\n");
00508
00509 if ( (mi_rpl=run_mi_cmd(f, mi_cmd))==0 ){
00510 if (!reply_stream)
00511 mi_open_reply( file, reply_stream, failure);
00512 mi_fifo_reply(reply_stream, "500 command '%s' failed\n", command);
00513 LM_ERR("command (%s) processing failed\n", command );
00514 } else if (mi_rpl!=MI_ROOT_ASYNC_RPL) {
00515 if (!reply_stream)
00516 mi_open_reply( file, reply_stream, failure);
00517 mi_write_tree( reply_stream, mi_rpl);
00518 free_mi_tree( mi_rpl );
00519 } else {
00520 if (mi_cmd)
00521 free_mi_tree( mi_cmd );
00522 continue;
00523 }
00524
00525 free_async_handler(hdl);
00526
00527 fclose(reply_stream);
00528
00529 if (mi_cmd)
00530 free_mi_tree( mi_cmd );
00531 continue;
00532
00533 failure:
00534 free_async_handler(hdl);
00535
00536 if (mi_cmd)
00537 free_mi_tree( mi_cmd );
00538
00539 if (mi_rpl)
00540 free_mi_tree(mi_rpl);
00541 continue;
00542
00543 consume3:
00544 free_async_handler(hdl);
00545 if (reply_stream)
00546 consume2:
00547 fclose(reply_stream);
00548 consume1:
00549 mi_do_consume();
00550 }
00551 }