ssl.c (7024B)
1 /* 06sep07abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <dirent.h> 10 #include <errno.h> 11 #include <string.h> 12 #include <signal.h> 13 #include <netdb.h> 14 #include <sys/stat.h> 15 #include <sys/socket.h> 16 #include <arpa/inet.h> 17 #include <netinet/tcp.h> 18 #include <netinet/in.h> 19 #include <syslog.h> 20 21 #include <openssl/pem.h> 22 #include <openssl/ssl.h> 23 #include <openssl/err.h> 24 25 typedef enum {NO,YES} bool; 26 27 static char *File, *Dir, *Data; 28 static off_t Size; 29 static bool Log; 30 31 static char Get[] = 32 "GET /%s HTTP/1.0\r\n" 33 "User-Agent: PicoLisp\r\n" 34 "Host: %s:%s\r\n" 35 "Accept-Charset: utf-8\r\n\r\n"; 36 37 static void logger(char *msg) { 38 if (Log) 39 syslog(LOG_ERR, "%s", msg); 40 else 41 fprintf(stderr, "ssl: %s\n", msg); 42 } 43 44 static void giveup(char *msg) { 45 logger(msg); 46 exit(1); 47 } 48 49 static void sslChk(int n) { 50 if (n < 0) { 51 ERR_print_errors_fp(stderr); 52 exit(1); 53 } 54 } 55 56 static int sslConnect(SSL *ssl, char *host, int port) { 57 struct sockaddr_in addr; 58 struct hostent *p; 59 int sd; 60 61 memset(&addr, 0, sizeof(addr)); 62 if ((long)(addr.sin_addr.s_addr = inet_addr(host)) == -1) { 63 if (!(p = gethostbyname(host)) || p->h_length == 0) 64 return -1; 65 addr.sin_addr.s_addr = ((struct in_addr*)p->h_addr_list[0])->s_addr; 66 } 67 68 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 69 logger("No socket"); 70 return -1; 71 } 72 addr.sin_family = AF_INET; 73 addr.sin_port = htons((unsigned short)port); 74 if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 75 close(sd); 76 return -1; 77 } 78 79 SSL_set_fd(ssl,sd); 80 if (SSL_connect(ssl) >= 0) 81 return sd; 82 close(sd); 83 return -1; 84 } 85 86 static void sslClose(SSL *ssl, int sd) { 87 SSL_shutdown(ssl); 88 close(sd); 89 } 90 91 static bool sslFile(SSL *ssl, char *file) { 92 int fd, n; 93 char buf[BUFSIZ]; 94 95 if (file[0] == '-') 96 return SSL_write(ssl, file+1, strlen(file)-1) >= 0; 97 if ((fd = open(file, O_RDONLY)) < 0) 98 return NO; 99 while ((n = read(fd, buf, sizeof(buf))) > 0) 100 if (SSL_write(ssl, buf, n) < 0) { 101 close(fd); 102 return NO; 103 } 104 close(fd); 105 return n == 0; 106 } 107 108 static void doSigTerm(int n __attribute__((unused))) { 109 int fd1, fd2, cnt; 110 char buf[BUFSIZ]; 111 112 if (Data && (fd1 = open(File, O_RDWR)) >= 0) { 113 if (unlink(File) < 0) 114 giveup("Can't unlink back"); 115 if ((fd2 = open(File, O_CREAT|O_WRONLY|O_TRUNC, 0666)) < 0) 116 giveup("Can't create back"); 117 if (write(fd2, Data, Size) != Size) 118 giveup("Can't write back"); 119 while ((cnt = read(fd1, buf, sizeof(buf))) > 0) 120 write(fd2, buf, cnt); 121 } 122 exit(0); 123 } 124 125 // ssl host port url 126 // ssl host port url file 127 // ssl host port url key file 128 // ssl host port url key file dir sec 129 int main(int ac, char *av[]) { 130 SSL_CTX *ctx; 131 SSL *ssl; 132 bool bin; 133 int n, sec, getLen, lenLen, fd, sd; 134 DIR *dp; 135 struct dirent *p; 136 struct stat st; 137 struct flock fl; 138 char get[1024], buf[4096], nm[4096], len[64]; 139 140 if (!(ac >= 4 && ac <= 6 || ac == 8)) 141 giveup("host port url [[key] file] | host port url key file dir sec"); 142 if (strlen(Get)+strlen(av[1])+strlen(av[2])+strlen(av[3]) >= sizeof(get)) 143 giveup("Names too long"); 144 if (strchr(av[3],'/')) 145 bin = NO, getLen = sprintf(get, Get, av[3], av[1], av[2]); 146 else 147 bin = YES, getLen = sprintf(get, "@%s ", av[3]); 148 149 SSL_library_init(); 150 SSL_load_error_strings(); 151 if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) { 152 ERR_print_errors_fp(stderr); 153 giveup("SSL init"); 154 } 155 ssl = SSL_new(ctx); 156 157 if (ac <= 6) { 158 if (sslConnect(ssl, av[1], atoi(av[2])) < 0) { 159 logger("Can't connect"); 160 return 1; 161 } 162 sslChk(SSL_write(ssl, get, getLen)); 163 if (ac > 4) { 164 if (*av[4] && !sslFile(ssl,av[4])) 165 giveup(av[4]); 166 if (ac > 5 && *av[5] && !sslFile(ssl,av[5])) 167 giveup(av[5]); 168 } 169 while ((n = SSL_read(ssl, buf, sizeof(buf))) > 0) 170 write(STDOUT_FILENO, buf, n); 171 return 0; 172 } 173 174 signal(SIGCHLD,SIG_IGN); /* Prevent zombies */ 175 if ((n = fork()) < 0) 176 giveup("detach"); 177 if (n) 178 return 0; 179 setsid(); 180 181 openlog("ssl", LOG_CONS|LOG_PID, 0); 182 Log = YES; 183 File = av[5]; 184 Dir = av[6]; 185 sec = atoi(av[7]); 186 signal(SIGINT, doSigTerm); 187 signal(SIGTERM, doSigTerm); 188 signal(SIGPIPE, SIG_IGN); 189 for (;;) { 190 if (*File && (fd = open(File, O_RDWR)) >= 0) { 191 if (fstat(fd,&st) < 0 || st.st_size == 0) 192 close(fd); 193 else { 194 fl.l_type = F_WRLCK; 195 fl.l_whence = SEEK_SET; 196 fl.l_start = 0; 197 fl.l_len = 0; 198 if (fcntl(fd, F_SETLKW, &fl) < 0) 199 giveup("Can't lock"); 200 if (fstat(fd,&st) < 0 || (Size = st.st_size) == 0) 201 giveup("Can't access"); 202 lenLen = sprintf(len, "%lld\n", Size); 203 if ((Data = malloc(Size)) == NULL) 204 giveup("Can't alloc"); 205 if (read(fd, Data, Size) != Size) 206 giveup("Can't read"); 207 if (ftruncate(fd,0) < 0) 208 logger("Can't truncate"); 209 close(fd); 210 for (;;) { 211 if ((sd = sslConnect(ssl, av[1], atoi(av[2]))) >= 0) { 212 if (SSL_write(ssl, get, getLen) == getLen && 213 (!*av[4] || sslFile(ssl,av[4])) && // key 214 (bin || SSL_write(ssl, len, lenLen) == lenLen) && // length 215 SSL_write(ssl, Data, Size) == Size && // data 216 SSL_write(ssl, bin? "\0" : "T", 1) == 1 && // ack 217 SSL_read(ssl, buf, 1) == 1 && buf[0] == 'T' ) { 218 sslClose(ssl,sd); 219 break; 220 } 221 sslClose(ssl,sd); 222 logger("Transmit failed"); 223 } 224 sleep(sec); 225 logger("Try to retransmit"); 226 } 227 free(Data), Data = NULL; 228 } 229 } 230 if (*Dir && (dp = opendir(Dir))) { 231 while (p = readdir(dp)) { 232 if (p->d_name[0] != '.') { 233 snprintf(nm, sizeof(nm), "%s%s", Dir, p->d_name); 234 if ((n = readlink(nm, buf, sizeof(buf))) > 0 && 235 (sd = sslConnect(ssl, av[1], atoi(av[2]))) >= 0 ) { 236 if (SSL_write(ssl, get, getLen) == getLen && 237 (!*av[4] || sslFile(ssl,av[4])) && // key 238 (bin || SSL_write(ssl, buf, n) == n) && // path 239 (bin || SSL_write(ssl, "\n", 1) == 1) && // nl 240 sslFile(ssl, nm) ) // file 241 unlink(nm); 242 sslClose(ssl,sd); 243 } 244 } 245 } 246 closedir(dp); 247 } 248 sleep(sec); 249 } 250 }