00001
00002
00003
00004
00005
00006
00007
00008 #ifdef ENABLE_FIFO
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "vsl_api.h"
00018 #include "vsl_util.h"
00019 #include "vsl_fifo.h"
00020 #include "vsl.h"
00021
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <unistd.h>
00025 #include <fcntl.h>
00026 #include <sys/types.h>
00027 #include <sys/wait.h>
00028 #include <time.h>
00029 #include <sys/sem.h>
00030 #include <sys/mman.h>
00031 #include <stdio.h>
00032 #include <sys/ipc.h>
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 static struct {
00043 uint32_t clid;
00044 char key[VSL_KEYLENGTH];
00045 time_t timestamp;
00046 } *msgqueue;
00047
00048
00049 static uint32_t *client_id;
00050
00051
00052 static int sem = -1;
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 int ssh_init(void) {
00063
00064
00065
00066
00067 if ( (sem = semget(IPC_PRIVATE, 2, 0600 )) == -1 )
00068 LOGFAIL(VSL_ERRNO, "Cannot create semaphore: %s!", strerror(errno));
00069 if ( semctl(sem, 0, SETVAL, 1) == -1 ||
00070 semctl(sem, 1, SETVAL, 1) == -1 )
00071 LOGFAIL(VSL_ERRNO, "Cannot init semaphore: %s!", strerror(errno));
00072
00073
00074
00075 if ( (msgqueue = mmap(0, sizeof(*msgqueue) * MSG_QUEUE_SIZE + sizeof(*client_id),
00076 PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED,
00077 -1, 0)) == MAP_FAILED )
00078 LOGFAIL(VSL_ERRNO, "Cannot create shm: %s!", strerror(errno));
00079
00080
00081 memset( (void*) msgqueue, 0, sizeof(*msgqueue) * MSG_QUEUE_SIZE);
00082 client_id = (void*) msgqueue + sizeof(*msgqueue) * MSG_QUEUE_SIZE;
00083 *client_id = 0;
00084
00085 LOG("Initialized ssh IPC.");
00086 return 0;
00087 }
00088
00089
00090
00091
00092
00093
00094 int ssh_destruct(void){
00095
00096 if ( semctl(sem, 0, IPC_RMID) == -1 )
00097 LOGFAIL(VSL_ERRNO, "Can't release semaphore: %s!", strerror(errno));
00098
00099
00100 if ( munmap(msgqueue, sizeof(*msgqueue) * MSG_QUEUE_SIZE + sizeof(*client_id)) != 0)
00101 LOGFAIL(VSL_ERRNO, "Can't release shm: %s!", strerror(errno));
00102
00103 LOG("Destructed ssh IPC.");
00104 return 0;
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 int send_ssh_req(vsl_sock* socket) {
00121
00122 LOG("attempting to send ssh auth request...");
00123
00124
00125 phead_t head;
00126 FILL_MAGIC(head.magic);
00127 head.type = P_SSH_REQ;
00128 head.datalen = htonl(0);
00129
00130
00131 void *msg;
00132 int msglen;
00133 if ( (msg = write_objs(&msglen,
00134 (void*) &head.magic, sizeof(head.magic),
00135 (void*) &head.type, sizeof(head.type),
00136 (void*) &head.datalen, sizeof(head.datalen),
00137 NULL)) == NULL)
00138 LOGFAIL(VSL_ERRNO, "malloc failed: %s", strerror(errno));
00139
00140
00141
00142 int ret = vfer_send(socket->vfd, msg, msglen);
00143 free(msg);
00144 if (ret == VFER_WOULDBLOCK)
00145 return VFER_INPROGRESS;
00146 else if (ret == VFER_BADSOCK ||
00147 ret == VFER_UNCONN)
00148 return ret;
00149 else if (ret > 0 &&
00150 ret != msglen) {
00151 LOG("cannot send fragmented auth request");
00152 abort();
00153 }
00154 else if (ret < 0) {
00155 LOG("unknown send error: %s", vfer_errortext(ret));
00156 abort();
00157 }
00158 socket->status = C_SSH_REQ_SENT;
00159
00160 LOG("ssh auth request sent.");
00161 return(0);
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 int recv_ssh_res(vsl_sock* socket, const char* path) {
00185
00186 LOG("attempting to read ssh auth response...");
00187
00188
00189 int ret;
00190 char msg[MAX_FRAME_SIZE];
00191 ret = vfer_recv(socket->vfd, (void*) msg, MAX_FRAME_SIZE);
00192 if (ret == VFER_WOULDBLOCK) {
00193 return VFER_INPROGRESS;
00194 }
00195 else if (ret == VFER_BADSOCK ||
00196 ret == VFER_UNCONN) {
00197 return ret;
00198 }
00199 else if (ret < 0) {
00200 LOG("unknown send error: %s", vfer_errortext(ret));
00201 abort();
00202 }
00203
00204
00205 phead_t head;
00206 void *body = read_objs(msg,
00207 (void*) &head.magic, sizeof(head.magic),
00208 (void*) &head.type, sizeof(head.type),
00209 (void*) &head.datalen, sizeof(head.datalen),
00210 (void*) &(socket->client_id), sizeof(socket->client_id),
00211 NULL);
00212 head.datalen = ntohl(head.datalen);
00213 socket->client_id = ntohl(socket->client_id);
00214
00215
00216 if(!CHECK_MAGIC(head.magic) ||
00217 head.type != P_SSH_RES)
00218 LOGFAIL(VSL_BADPROT, "invalid packet received");
00219
00220
00221 if (head.datalen - sizeof(socket->client_id) > MAX_PATH)
00222 LOGFAIL(VSL_BADPROT, "received pathname too long");
00223
00224
00225 if ( strncmp(path, (char*)body, MAX_PATH) != 0 )
00226 LOGFAIL(VSL_BADPATH, "pathnames don't match.");
00227
00228
00229 LOG("ssh auth response read.");
00230
00231 return(0);
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 int fork_ssh(vsl_sock* sock, const char* user,
00250 const char* host, const char* fifo) {
00251
00252 LOG("attempting to fork ssh...");
00253
00254
00255 int fd[2];
00256 if ( pipe(fd) == -1 )
00257 LOGFAIL(VSL_ERRNO, "pipe failed: %s", strerror(err));
00258
00259
00260 pid_t pid;
00261 if ( (pid = fork()) == 0 ) {
00262 close(fd[1]);
00263 if ( fd[0] != STDIN_FILENO ) {
00264 if ( dup2(fd[0], STDIN_FILENO) != STDIN_FILENO )
00265 LOGFAIL(VSL_ERRNO, "(child) dup2 failed: %s", strerror(err));
00266 close(fd[0]);
00267 }
00268
00269 LOG("(child) calling 'ssh -T -l %s %s cat > %s'", user, host, fifo);
00270 execlp("ssh", "-T", "-l", user, host,
00271 "cat", ">", fifo, (char *) NULL);
00272 LOG("(child) exec failed: %s", strerror(errno));
00273 exit(255);
00274 }
00275 else if(pid == -1)
00276 LOGFAIL(VSL_ERRNO, "fork failed: %s", strerror(err));
00277
00278 close(fd[0]);
00279 sock->ssh_pid = pid;
00280 sock->ssh_fd = fd[1];
00281
00282
00283 if (!is_blocking(sock)) {
00284 long fdflags;
00285 if ( (fdflags = fcntl(fd[1], F_GETFL, 0)) < 0 ||
00286 fcntl(fd[1], F_SETFL, fdflags | O_NONBLOCK) < 0 )
00287 LOGFAIL(VSL_ERRNO, "fcntl failed: %s", strerror(err));
00288 }
00289
00290 LOG("ssh forked.");
00291 return(0);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 int send_key_ssh(vsl_sock* sock, const char* key) {
00307
00308 LOG("attempting to send shared secret over ssh...");
00309 LOG("secret is " KEY_STR, KEY_VEC(key));
00310
00311
00312 phead_t head;
00313 FILL_MAGIC(head.magic);
00314 head.type = P_SSH_KEY;
00315 head.datalen = htonl(sizeof(uint32_t) + VSL_KEYLENGTH);
00316
00317
00318 int msglen;
00319 void *msg;
00320 uint32_t clid = htonl(sock->client_id);
00321 if ( (msg = write_objs(&msglen,
00322 (void*) &head.magic, sizeof(head.magic),
00323 (void*) &head.type, sizeof(head.type),
00324 (void*) &head.datalen, sizeof(head.datalen),
00325 (void*) &clid, sizeof(clid),
00326 (void*) key, VSL_KEYLENGTH,
00327 NULL)) == NULL)
00328 LOGFAIL(VSL_ERRNO, "malloc failed: %s", strerror(err));
00329
00330
00331 if(write(sock->ssh_fd, msg, msglen) != msglen) {
00332 if(!is_blocking(sock) &&
00333 errno == EAGAIN)
00334 return(VFER_INPROGRESS);
00335 LOGFAIL(VSL_ERRNO, "write failed: %s", strerror(err));
00336 }
00337
00338
00339 if ( close(sock->ssh_fd) != 0 )
00340 LOGFAIL(VSL_ERRNO, "close failed: %s", strerror(err));
00341
00342 LOG("shared secret sent over ssh.");
00343
00344 return(0);
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 int close_ssh(vsl_sock* sock) {
00359 int ret, pidstat;
00360
00361 LOG("attempting to close ssh connection...");
00362
00363
00364 if(!is_blocking(sock)) {
00365 if( (ret=waitpid(sock->ssh_pid, &pidstat, WNOHANG)) == 0)
00366 return VFER_INPROGRESS;
00367 }
00368 else
00369 ret = waitpid(sock->ssh_pid, &pidstat, 0);
00370
00371 if(ret != sock->ssh_pid)
00372 LOGFAIL(VSL_ERRNO, "waitpid failed: %s", strerror(err));
00373
00374
00375 if( !WIFEXITED(pidstat) )
00376 LOGFAIL(VSL_SSHF, "ssh process aborted.");
00377
00378 if(WEXITSTATUS(pidstat) != 0)
00379 LOGFAIL(VSL_SSHF, "nonzero ssh exit status: %d", WEXITSTATUS(pidstat));
00380
00381 LOG("ssh connection closed.");
00382 return(0);
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 int recv_ssh_req(vsl_sock* socket) {
00401
00402 LOG("attempting to receive ssh auth request...");
00403
00404
00405 char msg[MAX_FRAME_SIZE];
00406 int ret = vfer_recv(socket->vfd, msg, MAX_FRAME_SIZE);
00407 if (ret == VFER_WOULDBLOCK)
00408 return VFER_INPROGRESS;
00409 else if (ret == VFER_BADSOCK ||
00410 ret == VFER_UNCONN)
00411 return ret;
00412 else if (ret < 0) {
00413 LOG("unknown receive error: %s", vfer_errortext(ret));
00414 abort();
00415 }
00416
00417
00418 phead_t head;
00419 read_objs(msg,
00420 (void*) &head.magic, sizeof(head.magic),
00421 (void*) &head.type, sizeof(head.type),
00422 (void*) &head.datalen, sizeof(head.datalen),
00423 NULL);
00424
00425
00426 if(!CHECK_MAGIC(head.magic) ||
00427 head.type != P_SSH_REQ)
00428 LOGFAIL(VSL_BADPROT, "invalid packet received");
00429
00430
00431
00432 if (semop(sem, (struct sembuf[]) { { 1, 1, SEM_UNDO }}, 1) == -1)
00433 LOGFAIL(VSL_ERRNO, "Cannot get lock: %s!", strerror(errno));
00434 socket->client_id = (*client_id)++;
00435
00436 if ( semop(sem, (struct sembuf[]) {{1, -1, SEM_UNDO}}, 1) == -1)
00437 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00438
00439 LOG("ssh auth request received.");
00440 return(0);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 int send_ssh_res(vsl_sock* socket, const char* path) {
00457
00458 LOG("attempting to send ssh auth response...");
00459
00460
00461 phead_t head;
00462 FILL_MAGIC(head.magic);
00463 head.type = P_SSH_RES;
00464 head.datalen =
00465 htonl(sizeof(uint32_t) + strlen(path) + 1);
00466
00467
00468 void *msg;
00469 int msglen;
00470 uint32_t clid = htonl(socket->client_id);
00471 if ( (msg = write_objs(&msglen,
00472 (void*) &head.magic, sizeof(head.magic),
00473 (void*) &head.type, sizeof(head.type),
00474 (void*) &head.datalen, sizeof(head.datalen),
00475 (void*) &clid, sizeof(socket->client_id),
00476 (void*) path, strlen(path)+1,
00477 NULL)) == NULL)
00478 LOGFAIL(VSL_ERRNO, "malloc failed: %s", strerror(err));
00479
00480
00481 int ret = vfer_send(socket->vfd, msg, msglen);
00482 free(msg);
00483 if (ret == VFER_WOULDBLOCK)
00484 return VFER_INPROGRESS;
00485 else if (ret == VFER_BADSOCK ||
00486 ret == VFER_UNCONN)
00487 return ret;
00488 else if (ret > 0 &&
00489 ret != msglen) {
00490 LOG("don't know how to handle fragmented sending!");
00491 abort();
00492 }
00493 else if (ret < 0) {
00494 LOG("unknown send error: %s!", vfer_errortext(ret));
00495 abort();
00496 }
00497 socket->status = C_SSH_REQ_SENT;
00498
00499 LOG("ssh auth response sent.");
00500 return(0);
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 int open_fifo(vsl_sock* sock, const char *path) {
00514 LOG("attempting to open FIFO %s...", path);
00515
00516 int flags = O_RDONLY;
00517 if (!is_blocking(sock))
00518 flags |= O_NONBLOCK ;
00519
00520
00521
00522
00523 if ( (sock->ssh_fd = open(path, flags)) == -1 )
00524 LOGFAIL(VSL_ERRNO, "open failed: %s", strerror(err));
00525
00526 LOG("opened new fd for FIFO %s.", path);
00527 return 0;
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 int close_fifo(vsl_sock* sock) {
00540 LOG("attempting to close FIFO...");
00541
00542 if ( close(sock->ssh_fd) != 0 )
00543 LOGFAIL(VSL_ERRNO,"close failed: %s", strerror(err));
00544
00545 LOG("FIFO closed.");
00546 return 0;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 int recv_key_ssh(vsl_sock* sock) {
00561 LOG("attempting to get shared secret for client %d...", sock->client_id);
00562
00563
00564
00565
00566 for (int i=0; i < MSG_QUEUE_SIZE; i++)
00567 if (msgqueue[i].clid == sock->client_id &&
00568 msgqueue[i].timestamp != 0) {
00569 init_keys_s(sock, msgqueue[i].key);
00570 msgqueue[i].timestamp = 0;
00571 LOG("got key for client %d from cache.", sock->client_id);
00572 return 0;
00573 }
00574
00575
00576 while(1) {
00577
00578 LOG("attempting to read secret from FIFO...");
00579
00580
00581 if (semop(sem, (struct sembuf[]) {
00582 { 0, 1, SEM_UNDO | (is_blocking(sock) ? 0 : IPC_NOWAIT) }}, 1) == -1) {
00583 if (!is_blocking(sock) &&
00584 errno == EAGAIN)
00585 return VFER_INPROGRESS;
00586 LOGFAIL(VSL_ERRNO, "Cannot get lock: %s!", strerror(errno));
00587 }
00588
00589
00590
00591 for (int i=0; i < MSG_QUEUE_SIZE; i++)
00592 if (msgqueue[i].clid == sock->client_id &&
00593 msgqueue[i].timestamp != 0) {
00594 init_keys_s(sock, msgqueue[i].key);
00595 msgqueue[i].timestamp = 0;
00596 LOG("got key for client %d from cache.", sock->client_id);
00597 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00598 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00599 return 0;
00600 }
00601
00602
00603 phead_t head;
00604 int ret;
00605 const int msglen = sizeof(head.magic) + sizeof(head.type)
00606 + sizeof(head.datalen) + sizeof(sock->client_id) + VSL_KEYLENGTH;
00607 char msg[msglen];
00608 if ( (ret = read(sock->ssh_fd, (void*) &msg, msglen)) != msglen) {
00609 if (errno == EAGAIN) {
00610 LOG("call would block, returning.");
00611 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00612 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00613 return VFER_INPROGRESS;
00614 }
00615 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00616 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00617 LOGFAIL(VSL_ERRNO, "read failed: %s", strerror(err));
00618 }
00619
00620
00621 uint32_t clid;
00622 char *key = read_objs(msg,
00623 (void*) &head.magic, sizeof(head.magic),
00624 (void*) &head.type, sizeof(head.type),
00625 (void*) &head.datalen, sizeof(head.datalen),
00626 (void*) &clid, sizeof(clid),
00627 NULL);
00628 head.datalen = ntohl(head.datalen);
00629 clid = ntohl(clid);
00630
00631
00632 if(!CHECK_MAGIC(head.magic) ||
00633 head.type != P_SSH_KEY ||
00634 head.datalen != sizeof(clid) + VSL_KEYLENGTH) {
00635 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00636 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00637 LOGFAIL(VSL_BADPROT, "invalid packet received");
00638 }
00639
00640
00641 if (clid == sock->client_id) {
00642 init_keys_s(sock, key);
00643 LOG("Correct secret read from FIFO.");
00644 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00645 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00646 return(0);
00647 }
00648
00649
00650 time_t timestamp = time(NULL);
00651 for (int i=0; i < MSG_QUEUE_SIZE; i++)
00652 if (msgqueue[i].timestamp == 0 ||
00653 timestamp - msgqueue[i].timestamp > MSG_TIMEOUT) {
00654 memcpy((void*) msgqueue[i].key, (void*) key, VSL_KEYLENGTH);
00655 msgqueue[i].clid = clid;
00656 msgqueue[i].timestamp = 0;
00657 LOG("Cached foreign secret.");
00658 if ( semop(sem, (struct sembuf[]) {{0, -1, SEM_UNDO}}, 1) == -1)
00659 LOGFAIL(VSL_ERRNO, "Cannot release lock: %s!", strerror(errno));
00660 continue;
00661 }
00662 LOGFAIL(VSL_MAXCONN, "Secret cache full!");
00663 }
00664
00665 LOG("something extremely strange happened.");
00666 abort();
00667 }
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 int vsl_auth_ssh_c(vsl_sock* socket, const char* user,
00716 const char* host, const char *path) {
00717 char key[VSL_KEYLENGTH];
00718
00719 LOG("trying ssh authentication as client");
00720
00721 switch(socket->status) {
00722 case(C_INITIALIZED):
00723
00724 TRY(send_ssh_req(socket));
00725 socket->status = C_SSH_REQ_SENT;
00726
00727 case(C_SSH_REQ_SENT):
00728
00729 TRY(recv_ssh_res(socket, path));
00730
00731
00732 TRY(fork_ssh(socket, user, host, path));
00733
00734
00735 TRY(gen_key(key));
00736
00737 socket->status = C_SSH_FORKED;
00738
00739 case(C_SSH_FORKED):
00740
00741 TRY(send_key_ssh(socket, key));
00742 socket->status = C_SSH_SEC_SENT;
00743
00744
00745 init_keys_c(socket, key);
00746
00747 case(C_SSH_SEC_SENT):
00748
00749 TRY(close_ssh(socket));
00750 socket->status = C_ESTABLISHED;
00751 socket->auth = VSL_AUTH_SSH;
00752 break;
00753
00754 default:
00755
00756 LOGFAIL(VFER_BADSOCK, "invalid socket state");
00757 }
00758
00759 LOG("ssh authentication successfull.");
00760 return(0);
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 int vsl_auth_ssh_s(vsl_sock* socket, const char* fifo) {
00797
00798
00799 if(strlen(fifo) >= MAX_PATH) {
00800 LOGFAIL(VSL_BADPATH, "fifo pathname too long");
00801 }
00802
00803
00804 struct stat sbuf;
00805 if(stat(fifo, &sbuf) != 0) {
00806 LOGFAIL(VSL_ERRNO, "can't stat() fifo: %s", strerror(err));
00807 }
00808 if(! S_ISFIFO(sbuf.st_mode)) {
00809 LOGFAIL(VSL_BADPATH, "fifo pathname is not a fifo");
00810 }
00811
00812 switch(socket->status) {
00813 case(C_INITIALIZED):
00814
00815 TRY(recv_ssh_req(socket));
00816 socket->status = C_SSH_REQ_RECV;
00817
00818 case(C_SSH_REQ_RECV):
00819
00820 TRY(send_ssh_res(socket, fifo));
00821 socket->status = C_SSH_RES_SENT;
00822
00823
00824 TRY(open_fifo(socket, fifo));
00825
00826 case(C_SSH_RES_SENT):
00827
00828 {
00829 int ret;
00830 if ( (ret=recv_key_ssh(socket)) != 0) {
00831 close_fifo(socket);
00832 return ret;
00833 }
00834 if ( (ret=close_fifo(socket)) != 0)
00835 return ret;
00836 }
00837
00838 socket->status = C_ESTABLISHED;
00839 socket->auth = VSL_AUTH_SSH;
00840 break;
00841
00842 default:
00843
00844 LOGFAIL(VFER_BADSOCK, "invalid socket state");
00845 }
00846 return(0);
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857 #endif