1 /*
2  * uf_features.c -- part of share.mod
3  *
4  * $Id: uf_features.c,v 1.13 (1.0.3) 2004/05/07 18:55:15 wcc Exp $
5  */
6 
7 typedef struct uff_list_struct {
8   struct uff_list_struct *next; /* Pointer to next entry                */
9   struct uff_list_struct *prev; /* Pointer to previous entry            */
10   uff_table_t *entry;
11 } uff_list_t;
12 
13 typedef struct {
14   uff_list_t *start;
15   uff_list_t *end;
16 } uff_head_t;
17 
18 static uff_head_t uff_list;
19 static char uff_sbuf[512];
20 
uff_init(void)21 static void uff_init(void)
22 {
23   EvangelineBzero(&uff_list, sizeof(uff_head_t));
24 }
25 
uff_expmem(void)26 static int uff_expmem(void)
27 {
28   uff_list_t *ul;
29   int tot = 0;
30 
31   for (ul = uff_list.start; ul; ul = ul->next)
32     tot += sizeof(uff_list_t);
33   return tot;
34 }
35 
36 /* Search for a feature in the uff feature list that matches a supplied
37  * feature flag. Returns a pointer to the entry in the list or NULL if
38  * no feature uses the flag. */
uff_findentry_byflag(int flag)39 static uff_list_t *uff_findentry_byflag(int flag)
40 {
41   uff_list_t *ul;
42 
43   for (ul = uff_list.start; ul; ul = ul->next)
44     if (ul->entry->flag & flag)
45       return ul;
46   return NULL;
47 }
48 
49 /* Search for a feature in the uff feature list. Returns a pointer to the
50  * entry in the list or NULL if no such feature exists. */
uff_findentry_byname(char * feature)51 static uff_list_t *uff_findentry_byname(char *feature)
52 {
53   uff_list_t *ul;
54 
55   for (ul = uff_list.start; ul; ul = ul->next)
56     if (!strcmp(ul->entry->feature, feature))
57       return ul;
58   return NULL;
59 }
60 
61 /* Insert entry into sorted list. */
uff_insert_entry(uff_list_t * nul)62 static void uff_insert_entry(uff_list_t *nul)
63 {
64   uff_list_t *ul, *lul = NULL;
65 
66   ul = uff_list.start;
67   while (ul && ul->entry->priority < nul->entry->priority) {
68     lul = ul;
69     ul = ul->next;
70   }
71 
72   nul->prev = NULL;
73   nul->next = NULL;
74   if (lul) {
75     if (lul->next)
76       lul->next->prev = nul;
77     nul->next = lul->next;
78     nul->prev = lul;
79     lul->next = nul;
80   } else if (ul) {
81     uff_list.start->prev = nul;
82     nul->next = uff_list.start;
83     uff_list.start = nul;
84   } else
85     uff_list.start = nul;
86   if (!nul->next)
87     uff_list.end = nul;
88 }
89 
90 /* Remove entry from sorted list. */
uff_remove_entry(uff_list_t * ul)91 static void uff_remove_entry(uff_list_t *ul)
92 {
93   if (!ul->next)
94     uff_list.end = ul->prev;
95   else
96     ul->next->prev = ul->prev;
97   if (!ul->prev)
98     uff_list.start = ul->next;
99   else
100     ul->prev->next = ul->next;
101 }
102 
103 /* Add a single feature to the list. */
uff_addfeature(uff_table_t * ut)104 static void uff_addfeature(uff_table_t *ut)
105 {
106   uff_list_t *ul;
107 
108   if (uff_findentry_byname(ut->feature)) {
109     putlog(LOG_MISC, "*", "(!) share: same feature name used twice: %s",
110            ut->feature);
111     return;
112   }
113   ul = uff_findentry_byflag(ut->flag);
114   if (ul) {
115     putlog(LOG_MISC, "*", "(!) share: feature flag %d used twice by %s and %s",
116            ut->flag, ut->feature, ul->entry->feature);
117     return;
118   }
119   ul = nmalloc(sizeof(uff_list_t));
120   ul->entry = ut;
121   uff_insert_entry(ul);
122 }
123 
124 /* Add a complete table to the list. */
uff_addtable(uff_table_t * ut)125 static void uff_addtable(uff_table_t *ut)
126 {
127   if (!ut)
128     return;
129   for (; ut->feature; ++ut)
130     uff_addfeature(ut);
131 }
132 
133 /* Remove a single feature from the list. */
uff_delfeature(uff_table_t * ut)134 static int uff_delfeature(uff_table_t *ut)
135 {
136   uff_list_t *ul;
137 
138   for (ul = uff_list.start; ul; ul = ul->next)
139     if (!strcmp(ul->entry->feature, ut->feature)) {
140       uff_remove_entry(ul);
141       nfree(ul);
142       return 1;
143     }
144   return 0;
145 }
146 
147 /* Remove a complete table from the list. */
uff_deltable(uff_table_t * ut)148 static void uff_deltable(uff_table_t *ut)
149 {
150   if (!ut)
151     return;
152   for (; ut->feature; ++ut)
153     (int) uff_delfeature(ut);
154 }
155 
156 /* Parse the given features string, set internal flags apropriately and
157  * eventually respond with all features we will use. */
uf_features_parse(int idx,char * par)158 static void uf_features_parse(int idx, char *par)
159 {
160   char *buf, *s, *p;
161   uff_list_t *ul;
162 
163   uff_sbuf[0] = 0;
164   p = s = buf = nmalloc(strlen(par) + 1);
165   strcpy(buf, par);
166 
167   dcc[idx].u.bot->uff_flags = 0;
168 
169   while ((s = strchr(s, ' ')) != NULL) {
170     *s = '\0';
171 
172     ul = uff_findentry_byname(p);
173     if (ul && (ul->entry->ask_func == NULL || ul->entry->ask_func(idx))) {
174       dcc[idx].u.bot->uff_flags |= ul->entry->flag;
175       strcat(uff_sbuf, ul->entry->feature);
176       strcat(uff_sbuf, " ");
177       if (!strncmp(p, "encrypt", 7)) {
178         encrypt_userfile = 1;
179         debug0("uf_features.c->uf_features_parse) Found 'encrypt' feature, enabling");
180       }
181     }
182     p = ++s;
183   }
184   nfree(buf);
185 
186   if (uff_sbuf[0]) {
187     dprintf(idx, "s feats %s\n", uff_sbuf);
188   }
189 }
190 
191 /* Return a list of features we are supporting. */
uf_features_dump(int idx)192 static char *uf_features_dump(int idx)
193 {
194   uff_list_t *ul;
195 
196   uff_sbuf[0] = 0;
197   for (ul = uff_list.start; ul; ul = ul->next)
198     if (ul->entry->ask_func == NULL || ul->entry->ask_func(idx)) {
199       strcat(uff_sbuf, ul->entry->feature);
200       strcat(uff_sbuf, " ");
201     }
202   return uff_sbuf;
203 }
204 
uf_features_check(int idx,char * par)205 static int uf_features_check(int idx, char *par)
206 {
207   char *buf, *s, *p;
208   uff_list_t *ul;
209 
210   uff_sbuf[0] = 0;
211   p = s = buf = nmalloc(strlen(par) + 1);
212   strcpy(buf, par);
213 
214   dcc[idx].u.bot->uff_flags = 0;
215 
216   while ((s = strchr(s, ' ')) != NULL) {
217     *s = '\0';
218 
219     ul = uff_findentry_byname(p);
220     if (ul && (ul->entry->ask_func == NULL || ul->entry->ask_func(idx))) {
221       dcc[idx].u.bot->uff_flags |= ul->entry->flag;
222     } else {
223       putlog(LOG_BOTS, "*", "Bot %s tried unsupported feature!", dcc[idx].nick);
224       dprintf(idx, "s e Attempt to use an unsupported feature\n");
225       zapfbot(idx);
226 
227       nfree(buf);
228       return 0;
229     }
230     p = ++s;
231   }
232   nfree(buf);
233   return 1;
234 }
235 
236 /* Call all active feature functions, sorted by their priority. This
237  * should be called when we're about to send a user file. */
uff_call_sending(int idx,char * user_file)238 static int uff_call_sending(int idx, char *user_file)
239 {
240   uff_list_t *ul;
241 
242   for (ul = uff_list.start; ul; ul = ul->next)
243     if (ul->entry && ul->entry->snd &&
244         (dcc[idx].u.bot->uff_flags & ul->entry->flag))
245       if (!(ul->entry->snd(idx, user_file)))
246         return 0;
247   return 1;
248 }
249 
250 /* Call all active feature functions, sorted by their priority. This
251  * should be called when we've received a user file and are about to
252  * parse it. */
uff_call_receiving(int idx,char * user_file)253 static int uff_call_receiving(int idx, char *user_file)
254 {
255   uff_list_t *ul;
256 
257   for (ul = uff_list.end; ul; ul = ul->prev)
258     if (ul->entry && ul->entry->rcv &&
259         (dcc[idx].u.bot->uff_flags & ul->entry->flag))
260       if (!(ul->entry->rcv(idx, user_file)))
261         return 0;
262   return 1;
263 }
264 
265 /* Feature `overbots' */
uff_ask_override_bots(int idx)266 static int uff_ask_override_bots(int idx)
267 {
268   if (overr_local_bots)
269     return 1;
270   else
271     return 0;
272 }
273 
274 /* Feature `compress` */
275 #ifndef ZLIB_PROBLEM
276 int compress_level = 9;
277 
uff_comp(int idx,char * filename)278 static int uff_comp(int idx, char *filename)
279 {
280   debug1("(uf_features.c->uff_comp) Compressing user file for %s. (zlib)", dcc[idx].nick);
281   return compress_file(filename, compress_level);
282 }
283 
uff_uncomp(int idx,char * filename)284 static int uff_uncomp(int idx, char *filename)
285 {
286   debug1("(uf_features.c->uff_uncomp) Uncompressing user file from %s. (zlib)", dcc[idx].nick);
287   return uncompress_file(filename);
288 }
289 
uff_ask_compress(int idx)290 static int uff_ask_compress(int idx)
291 {
292   if (share_compressed)
293     return 1;
294   else
295     return 0;
296 }
297 #endif
298 
299 /* Feature `encrypt` */
300 static int uff_writeenc(int idx, char *fname);
301 static int uff_readenc(int idx, char *fname);
302 static int is_encryptedfile(char *fname);
303 
share_cryptKey(int idx,char * par)304 static void share_cryptKey(int idx, char *par) {
305   char *ki;
306   ki = newsplit(&par);
307   debug2("(uf_features.c->share_cryptKey) Got shareKey from %s: %s", dcc[idx].nick, ki);
308   strcpy(shareKey, ki);
309 }
310 
share_md5sum(int idx,char * par)311 static void share_md5sum(int idx, char *par) {
312   char *ki;
313   ki = newsplit(&par);
314   debug2("(uf_features.c->share_md5sum) Got md5sum from %s: %s", dcc[idx].nick, ki);
315   strcpy(md5sum, ki);
316 }
317 
is_encryptedfile(char * fname)318 static int is_encryptedfile(char *fname) {
319   FILE *file;
320   char buffer[512];
321 
322   file = fopen(fname, "r");
323   if (file == NULL)
324     return 0;
325   fgets(buffer, 511, file);
326   if (!strncmp(buffer, "#Evangeline!Encrypted: Userfile", 31))
327     return 1;
328   else
329     return 0;
330 }
331 
uff_writeenc(int idx,char * fname)332 static int uff_writeenc(int idx, char *fname) {
333 
334   debug2("(uf_features.c->uff_writeenc) Sending shareKey to %s: %s", dcc[idx].nick, shareKey);
335   dprintf(idx, "s sck %s\n", shareKey);
336   putlog(LOG_BOTS, "*", "Encrypting userfile for %s", dcc[idx].nick);
337 
338   return 1;
339 }
340 
uff_readenc(int idx,char * fname)341 static int uff_readenc(int idx, char *fname) {
342 
343   if (is_encryptedfile(fname)) {
344     encrypt_userfile = 1;
345     putlog(LOG_BOTS, "*", "Decrypting userfile from %s", dcc[idx].nick);
346   }
347   return 1;
348 }
349 
uff_ask_sharecrypt(int idx)350 static int uff_ask_sharecrypt(int idx) {
351   if (share_encrypted)
352     return 1;
353   else
354     return 0;
355 }
356 
357 static uff_table_t internal_uff_table[] = {
358   {"overbots", UFF_OVERRIDE, uff_ask_override_bots, 0, NULL, NULL},
359   {"invites",  UFF_INVITE,   NULL,                  0, NULL, NULL},
360   {"exempts",  UFF_EXEMPT,   NULL,                  0, NULL, NULL},
361 #ifndef ZLIB_PROBLEM
362   {"compress", UFF_COMPRESS, uff_ask_compress, 	  100, uff_comp, uff_uncomp},
363 #endif
364   {"encrypt",  UFF_ENCRYPT,  uff_ask_sharecrypt,  100, uff_writeenc, uff_readenc},
365   {NULL,       0,            NULL,                  0, NULL, NULL}
366 };
367