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