1 /*
2  * File: misc_new.c
3  *
4  * Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  */
11 
12 #include <errno.h>      /* errno, err-codes */
13 #include <unistd.h>
14 #include <time.h>
15 #include <sys/stat.h>   /* stat */
16 #include <stdlib.h>     /* rand, srand */
17 
18 #include "../dlib/dlib.h"
19 #include "dpid_common.h"
20 #include "misc_new.h"   /* for function prototypes */
21 
22 /*! Reads a dpi tag from a socket
23  * \li Continues after a signal interrupt
24  * \Return
25  * Dstr pointer to tag on success, NULL on failure
26  * \important Caller is responsible for freeing the returned Dstr *
27  */
a_Misc_rdtag(int socket)28 Dstr *a_Misc_rdtag(int socket)
29 {
30    char c = '\0';
31    ssize_t rdlen;
32    Dstr *tag;
33 
34    tag = dStr_sized_new(64);
35 
36    errno = 0;
37 
38    do {
39       rdlen = read(socket, &c, 1);
40       if (rdlen == -1 && errno != EINTR)
41          break;
42       dStr_append_c(tag, c);
43    } while (c != '>');
44 
45    if (rdlen == -1) {
46       perror("a_Misc_rdtag");
47       dStr_free(tag, TRUE);
48       return (NULL);
49    }
50    return (tag);
51 }
52 
53 /*!
54  * Read a dpi tag from sock
55  * \return
56  * pointer to dynamically allocated request tag
57  */
a_Misc_readtag(int sock)58 char *a_Misc_readtag(int sock)
59 {
60    char *tag, c;
61    size_t i;
62    size_t taglen = 0, tagmem = 10;
63    ssize_t rdln = 1;
64 
65    tag = NULL;
66    // new start
67    tag = (char *) dMalloc(tagmem + 1);
68    for (i = 0; (rdln = read(sock, &c, 1)) != 0; i++) {
69       if (i == tagmem) {
70          tagmem += tagmem;
71          tag = (char *) dRealloc(tag, tagmem + 1);
72       }
73       tag[i] = c;
74       taglen += rdln;
75       if (c == '>') {
76          tag[i + 1] = '\0';
77          break;
78       }
79    }
80    // new end
81    if (rdln == -1) {
82       ERRMSG("a_Misc_readtag", "read", errno);
83    }
84 
85    return (tag);
86 }
87 
88 /*! Reads a dpi tag from a socket without hanging on read.
89  * \li Continues after a signal interrupt
90  * \Return
91  * \li 1 on success
92  * \li 0 if input is not available within timeout microseconds.
93  * \li -1 on failure
94  * \important Caller is responsible for freeing the returned Dstr *
95  */
96 /* Is this useful?
97 int a_Misc_nohang_rdtag(int socket, int timeout, Dstr **tag)
98 {
99    int n_fd;
100    fd_set sock_set, select_set;
101    struct timeval tout;
102 
103    FD_ZERO(&sock_set);
104    FD_SET(socket, &sock_set);
105 
106    errno = 0;
107    do {
108       select_set = sock_set;
109       tout.tv_sec = 0;
110       tout.tv_usec = timeout;
111       n_fd = select(socket + 1, &select_set, NULL, NULL, &tout);
112    } while (n_fd == -1 && errno == EINTR);
113 
114    if (n_fd == -1) {
115       MSG_ERR("%s:%d: a_Misc_nohang_rdtag: %s\n",
116               __FILE__, __LINE__, dStrerror(errno));
117       return(-1);
118    }
119    if (n_fd == 0) {
120       return(0);
121    } else {
122       *tag = a_Misc_rdtag(socket);
123       return(1);
124    }
125 }
126 */
127 
128 /*
129  * Alternative to mkdtemp().
130  * Not as strong as mkdtemp, but enough for creating a directory.
131  */
a_Misc_mkdtemp(char * template)132 char *a_Misc_mkdtemp(char *template)
133 {
134    for (;;) {
135       if (a_Misc_mkfname(template) && mkdir(template, 0700) == 0)
136          break;
137       if (errno == EEXIST)
138          continue;
139       return 0;
140    }
141    return template;
142 }
143 
144 /*
145  * Return a new, nonexistent file name from a template
146  * (adapted from dietlibc; alternative to mkdtemp())
147  */
a_Misc_mkfname(char * template)148 char *a_Misc_mkfname(char *template)
149 {
150    char *tmp = template + strlen(template) - 6;
151    int i;
152    uint_t random;
153    struct stat stat_buf;
154 
155    if (tmp < template)
156       goto error;
157    for (i = 0; i < 6; ++i)
158       if (tmp[i] != 'X') {
159        error:
160          errno = EINVAL;
161          return 0;
162       }
163    srand((uint_t)(time(0) ^ getpid()));
164 
165    for (;;) {
166       random = (unsigned) rand();
167       for (i = 0; i < 6; ++i) {
168          int hexdigit = (random >> (i * 5)) & 0x1f;
169 
170          tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
171       }
172       if (stat(template, &stat_buf) == -1 && errno == ENOENT)
173          return template;
174 
175       MSG_ERR("a_Misc_mkfname: another round for %s \n", template);
176    }
177 }
178 
179 /*
180  * Return a new, random hexadecimal string of 'nchar' characters.
181  */
a_Misc_mksecret(int nchar)182 char *a_Misc_mksecret(int nchar)
183 {
184    int i;
185    uint_t random;
186    char *secret = dNew(char, nchar + 1);
187 
188    srand((uint_t)(time(0) ^ getpid()));
189    random = (unsigned) rand();
190    for (i = 0; i < nchar; ++i) {
191       int hexdigit = (random >> (i * 5)) & 0x0f;
192 
193       secret[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
194    }
195    secret[i] = 0;
196    MSG("a_Misc_mksecret: %s\n", secret);
197 
198    return secret;
199 }
200 
201