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