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