1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_config_proto.h"
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <fcntl.h> /* open/creat */
9 #include <unistd.h> /* close */
10 #include <time.h> /* time */
11 #include <sys/stat.h>
12 #include <pobl/bl_conf_io.h>
13 #include <pobl/bl_util.h>
14 #include <pobl/bl_mem.h>
15 #include <pobl/bl_debug.h>
16
17 #if 0
18 #define __DEBUG
19 #endif
20
21 /* --- static functions --- */
22
23 static char *challenge;
24 static char *path;
25
26 /* --- static functions --- */
27
read_challenge(void)28 static int read_challenge(void) {
29 FILE *file;
30 struct stat st;
31
32 if ((file = fopen(path, "r")) == NULL) {
33 return 0;
34 }
35
36 fstat(fileno(file), &st);
37
38 if (st.st_size > DIGIT_STR_LEN(int)) {
39 return 0;
40 }
41
42 free(challenge);
43
44 if ((challenge = malloc(DIGIT_STR_LEN(int)+1)) == NULL) {
45 return 0;
46 }
47
48 fread(challenge, st.st_size, 1, file);
49 challenge[st.st_size] = '\0';
50
51 fclose(file);
52
53 return 1;
54 }
55
56 /* --- global functions --- */
57
vt_config_proto_init(void)58 int vt_config_proto_init(void) {
59 if ((path = bl_get_user_rc_path("mlterm/challenge")) == NULL) {
60 return 0;
61 }
62
63 bl_mkdir_for_file(path, 0700);
64
65 return vt_gen_proto_challenge();
66 }
67
vt_config_proto_final(void)68 void vt_config_proto_final(void) {
69 free(path);
70 free(challenge);
71 }
72
vt_gen_proto_challenge(void)73 int vt_gen_proto_challenge(void) {
74 int fd;
75
76 if ((fd = creat(path, 0600)) == -1) {
77 bl_error_printf("Failed to create %s.\n", path);
78
79 return 0;
80 }
81
82 free(challenge);
83
84 if ((challenge = malloc(DIGIT_STR_LEN(int)+1)) == NULL) {
85 return 0;
86 }
87
88 srand((u_int)(time(NULL) + (int)challenge));
89 sprintf(challenge, "%d", rand());
90
91 write(fd, challenge, strlen(challenge));
92
93 close(fd);
94
95 return 1;
96 }
97
vt_get_proto_challenge(void)98 char *vt_get_proto_challenge(void) { return challenge; }
99
100 /*
101 * Returns 0 if illegal format.
102 * Returns -1 if do_challenge is 1 and challenge failed.
103 */
vt_parse_proto_prefix(char ** dev,char ** str,int do_challenge)104 int vt_parse_proto_prefix(char **dev, /* can be NULL */
105 char **str, int do_challenge) {
106 char *p;
107
108 p = *str;
109
110 while (do_challenge) {
111 char *chal;
112
113 chal = p;
114
115 if ((p = strchr(p, ';'))) {
116 *(p++) = '\0';
117
118 if ((challenge && strcmp(chal, challenge) == 0) ||
119 /* Challenge could have been re-generated. */
120 (read_challenge() && challenge && strcmp(chal, challenge) == 0)) {
121 /* challenge succeeded. */
122 break;
123 }
124 }
125
126 return -1;
127 }
128
129 *str = p; /* for no_dev */
130
131 if (strncmp(p, "/dev/", 5) == 0) {
132 p += 4;
133 while (*(++p) != ':') {
134 /* Don't contain ';' in "/dev/...". */
135 if (*p == ';' || *p == '\0') {
136 /* Illegal format */
137 #ifdef DEBUG
138 bl_warn_printf(BL_DEBUG_TAG " Illegal protocol format.\n");
139 #endif
140
141 goto no_dev;
142 }
143 }
144 } else {
145 if (strncmp(p, "color:", 6) == 0) {
146 p += 5;
147 } else {
148 if (*p == 't' || *p == 'v') {
149 p++;
150 }
151 if (*p == 'a' && *(p + 1) == 'a') {
152 p += 2;
153 }
154 if (strncmp(p, "font:", 5) == 0) {
155 p += 4;
156 } else {
157 goto no_dev;
158 }
159 }
160 }
161
162 if (dev) {
163 *dev = *str;
164 }
165
166 *(p++) = '\0';
167 *str = p;
168
169 return 1;
170
171 no_dev:
172 if (dev) {
173 *dev = NULL;
174 }
175
176 return 1;
177 }
178
179 /*
180 * Returns 0 if illegal format.
181 * Returns -1 if do_challenge is 1 and challenge failed.
182 * If finished parsing str, *str is set NULL(see *str = strchr( p , ';')).
183 */
vt_parse_proto(char ** dev,char ** key,char ** val,char ** str,int do_challenge,int sep_by_semicolon)184 int vt_parse_proto(char **dev, /* can be NULL */
185 char **key, /* can be NULL. *key is never NULL. */
186 char **val, /* can be NULL */
187 char **str, int do_challenge, int sep_by_semicolon) {
188 char *p;
189
190 p = *str;
191
192 if (vt_parse_proto_prefix(dev, &p, do_challenge) < 0) {
193 return -1;
194 }
195
196 if (sep_by_semicolon) {
197 if ((*str = strchr(p, ';'))) {
198 /* *str points next key=value. */
199 *((*str)++) = '\0';
200 }
201 } else {
202 *str = NULL;
203 }
204
205 if (key) {
206 *key = p;
207 }
208
209 if ((p = strchr(p, '='))) {
210 *(p++) = '\0';
211
212 if (val) {
213 *val = p;
214 }
215 } else {
216 if (val) {
217 *val = NULL;
218 }
219 }
220
221 #ifdef __DEBUG
222 bl_debug_printf("%s %s %s\n", key ? *key : NULL, val ? *val : NULL, dev ? *dev : NULL);
223 #endif
224
225 return 1;
226 }
227