1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include "wzd_all.h"
28
29 #ifndef WZD_USE_PCH
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <time.h>
36
37 #ifdef WIN32
38 #include <winsock2.h>
39 #else
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h> /* struct in_addr (wzd_misc.h) */
45 #endif
46
47 #include <sys/stat.h>
48
49 #include "wzd_structs.h"
50
51 #include "wzd_libmain.h"
52 #include "wzd_misc.h"
53
54 #include "wzd_configfile.h"
55 #include "wzd_fs.h"
56 #include "wzd_group.h"
57 #include "wzd_vars.h"
58 #include "wzd_log.h"
59 #include "wzd_mutex.h"
60 #include "wzd_user.h"
61
62
63 #include "wzd_debug.h"
64
65 #endif /* WZD_USE_PCH */
66
67
68
69 static struct wzd_shm_vars_t * _shm_vars[32] = { NULL };
70
71
72
vars_get(const char * varname,void * data,unsigned int datalength,wzd_config_t * config)73 int vars_get(const char *varname, void *data, unsigned int datalength, wzd_config_t * config)
74 {
75 if (!config) return 1;
76
77 if (strcasecmp(varname,"bw")==0) {
78 snprintf(data,datalength,"%lu",get_bandwidth(NULL,NULL));
79 return 0;
80 }
81 if (strcmp(varname,"loglevel")==0) {
82 const char * str;
83
84 str = config_get_value(config->cfg_file, "GLOBAL", "loglevel");
85 if (str) {
86 snprintf(data,datalength,"%s",str);
87 return 0;
88 }
89 snprintf(data,datalength,"%s",loglevel2str(config->loglevel));
90 return 0;
91 }
92 if (strcasecmp(varname,"max_dl")==0) {
93 snprintf(data,datalength,"%u",config->global_dl_limiter.maxspeed);
94 return 0;
95 }
96 if (strcasecmp(varname,"max_threads")==0) {
97 snprintf(data,datalength,"%d",config->max_threads);
98 return 0;
99 }
100 if (strcasecmp(varname,"max_ul")==0) {
101 snprintf(data,datalength,"%u",config->global_ul_limiter.maxspeed);
102 return 0;
103 }
104 if (strcasecmp(varname,"pasv_low")==0) {
105 snprintf(data,datalength,"%u",config->pasv_low_range);
106 return 0;
107 }
108 if (strcasecmp(varname,"pasv_high")==0) {
109 snprintf(data,datalength,"%u",config->pasv_high_range);
110 return 0;
111 }
112 if (strcmp(varname,"port")==0) {
113 const char * str;
114
115 str = config_get_value(config->cfg_file, "GLOBAL", "port");
116 if (str) {
117 snprintf(data,datalength,"%s",str);
118 return 0;
119 }
120 snprintf(data,datalength,"%u",config->port);
121 return 0;
122 }
123 if (strcmp(varname,"uptime")==0) {
124 time_t t;
125
126 (void)time(&t);
127 t = t - config->server_start;
128 snprintf(data,datalength,"%lu",(unsigned long)t);
129 return 0;
130 }
131
132 return 1;
133 }
134
135 /** \brief Change value of server variable
136 *
137 * \todo we should change the value in config->cfg_file
138 */
vars_set(const char * varname,const void * data,unsigned int datalength,wzd_config_t * config)139 int vars_set(const char *varname, const void *data, unsigned int datalength, wzd_config_t * config)
140 {
141 int i;
142 unsigned long ul;
143 char *ptr;
144
145 if (!data || !config) return 1;
146
147 if (strcasecmp(varname,"deny_access_files_uploaded")==0) {
148 ul = strtoul(data,NULL,0);
149 if (ul==1) { CFG_SET_OPTION(config,CFG_OPT_DENY_ACCESS_FILES_UPLOADED); return 0; }
150 if (ul==0) { CFG_CLR_OPTION(config,CFG_OPT_DENY_ACCESS_FILES_UPLOADED); return 0; }
151 return 1;
152 }
153 if (strcasecmp(varname,"hide_dotted_files")==0) {
154 ul = strtoul(data,NULL,0);
155 if (ul==1) { CFG_SET_OPTION(config,CFG_OPT_HIDE_DOTTED_FILES); return 0; }
156 if (ul==0) { CFG_CLR_OPTION(config,CFG_OPT_HIDE_DOTTED_FILES); return 0; }
157 return 1;
158 }
159 if (strcasecmp(varname,"loglevel")==0) {
160 i = str2loglevel(data);
161 if (i==-1) {
162 return 1;
163 }
164 config->loglevel = i;
165 return 0;
166 }
167 if (strcasecmp(varname,"max_dl")==0) {
168 ul = strtoul(data,&ptr,0);
169 if (ptr && *ptr == '\0') {
170 config->global_dl_limiter.maxspeed = ul;
171 return 0;
172 }
173 }
174 if (strcasecmp(varname,"max_threads")==0) {
175 ul = strtoul(data,&ptr,0);
176 if (ptr && *ptr == '\0') {
177 config->max_threads = ul;
178 return 0;
179 }
180 }
181 if (strcasecmp(varname,"max_ul")==0) {
182 ul = strtoul(data,&ptr,0);
183 if (ptr && *ptr == '\0') {
184 config->global_ul_limiter.maxspeed = ul;
185 return 0;
186 }
187 }
188 if (strcasecmp(varname,"pasv_low")==0) {
189 ul = strtoul(data,NULL,0);
190 if (ul < 65535 && ul < config->pasv_high_range) {
191 config->pasv_low_range = ul;
192 return 0;
193 }
194 }
195 if (strcasecmp(varname,"pasv_high")==0) {
196 ul = strtoul(data,NULL,0);
197 if (ul < 65535 && ul > config->pasv_low_range) {
198 config->pasv_high_range = ul;
199 return 0;
200 }
201 }
202
203 return 1;
204 }
205
vars_user_get(const char * username,const char * varname,void * data,unsigned int datalength,wzd_config_t * config)206 int vars_user_get(const char *username, const char *varname, void *data, unsigned int datalength, wzd_config_t * config)
207 {
208 wzd_user_t * user;
209 wzd_group_t * group;
210
211 if (!username || !varname) return 1;
212
213 user = GetUserByName(username);
214 if (!user) return 1;
215
216 if (strcasecmp(varname,"group")==0) {
217 if (user->group_num > 0) {
218 group = GetGroupByID(user->groups[0]);
219 snprintf(data,datalength,"%s",group->groupname);
220 } else
221 snprintf(data,datalength,"no group");
222 return 0;
223 }
224 if (strcasecmp(varname,"home")==0) {
225 snprintf(data,datalength,"%s",user->rootpath);
226 return 0;
227 }
228 if (strcasecmp(varname,"max_dl")==0) {
229 snprintf(data,datalength,"%u",user->max_dl_speed);
230 return 0;
231 }
232 if (strcasecmp(varname,"max_ul")==0) {
233 snprintf(data,datalength,"%u",user->max_ul_speed);
234 return 0;
235 }
236 if (strcasecmp(varname,"credits")==0) {
237 snprintf(data,datalength,"%" PRIu64,user->credits);
238 return 0;
239 }
240 if (strcasecmp(varname,"name")==0) {
241 snprintf(data,datalength,"%s",user->username);
242 return 0;
243 }
244 if (strcasecmp(varname,"tag")==0) {
245 if (user->tagline[0] != '\0')
246 snprintf(data,datalength,"%s",user->tagline);
247 else
248 snprintf(data,datalength,"no tagline set");
249 return 0;
250 }
251
252 return 1;
253 }
254
vars_user_addip(const char * username,const char * ip,wzd_config_t * config)255 int vars_user_addip(const char *username, const char *ip, wzd_config_t *config)
256 {
257 wzd_user_t *user;
258 int ret;
259
260 if (!username || !ip) return 1;
261
262 user = GetUserByName(username);
263 if (!user) return -1;
264
265 do {
266
267 ret = ip_inlist(user->ip_list, ip);
268 if (ret) return 1; /* already present */
269
270 ret = ip_add_check(&user->ip_list, ip, 1 /* is_allowed */);
271
272 /* ip = strtok_r(NULL," \t\r\n",&ptr);*/
273 ip = NULL; /** \todo add only one ip (for the moment) */
274 } while (ip);
275
276 /* commit to backend */
277 return backend_mod_user(config->backends->filename, user->uid, user, _USER_IP);
278 }
279
vars_user_delip(const char * username,const char * ip,wzd_config_t * config)280 int vars_user_delip(const char *username, const char *ip, wzd_config_t *config)
281 {
282 char *ptr_ul;
283 wzd_user_t *user;
284 unsigned long ul;
285 int ret;
286
287 if (!username || !ip) return 1;
288
289 user = GetUserByName(username);
290 if (!user) return -1;
291
292 do {
293
294 /* try to take argument as a slot number */
295 ul = strtoul(ip,&ptr_ul,0);
296 if (*ptr_ul=='\0') {
297 unsigned int i;
298 struct wzd_ip_list_t * current_ip;
299
300 current_ip = user->ip_list;
301 for (i=1; i<ul && current_ip != NULL; i++) {
302 current_ip = current_ip->next_ip;
303 }
304 if (current_ip == NULL) return 2; /* not found */
305 ret = ip_remove(&user->ip_list,current_ip->regexp);
306 if (ret != 0) return -1;
307 } else { /* if (*ptr=='\0') */
308
309 ret = ip_remove(&user->ip_list,ip);
310 if (ret != 0) return 3;
311
312 } /* if (*ptr=='\0') */
313
314 /* ip = strtok_r(NULL," \t\r\n",&ptr);*/
315 ip = NULL; /** \todo add only one ip (for the moment) */
316 } while (ip);
317
318 /* commit to backend */
319 return backend_mod_user(config->backends->filename, user->uid, user, _USER_IP);
320 }
321
vars_user_set(const char * username,const char * varname,const void * data,unsigned int datalength,wzd_config_t * config)322 int vars_user_set(const char *username, const char *varname, const void *data, unsigned int datalength, wzd_config_t * config)
323 {
324 wzd_user_t * user;
325 unsigned long mod_type;
326 unsigned long ul;
327 char *ptr;
328 int ret;
329
330 if (!username || !varname) return 1;
331
332 user = GetUserByName(username);
333 if (!user) return -1;
334
335 /* find modification type */
336 mod_type = _USER_NOTHING;
337
338 /* addip */
339 if (strcmp(varname, "addip")==0) {
340 return vars_user_addip(username, data, config);
341 }
342 /* credits */
343 else if (strcmp(varname, "credits")==0) {
344 u64_t ull;
345
346 ull = strtoull(data, &ptr, 0); /** \todo XXX check overflows */
347
348 user->credits = ull;
349 mod_type = _USER_CREDITS;
350 }
351 /* bytes_ul and bytes_dl should never be changed ... */
352 /* delip */
353 else if (strcmp(varname, "delip")==0) {
354 return vars_user_delip(username, data, config);
355 }
356 /* flags */ /* TODO accept modifications style +f or -f */
357 else if (strcmp(varname, "flags")==0) {
358 strncpy(user->flags, data, MAX_FLAGS_NUM-1);
359 mod_type = _USER_FLAGS;
360 }
361 /* homedir */
362 else if (strcmp(varname, "home")==0) {
363 /* check if homedir exist */
364 {
365 fs_filestat_t s;
366 if (fs_file_stat(data,&s) || !S_ISDIR(s.mode)) {
367 /* Homedir does not exist */
368 return 1;
369 }
370 }
371 mod_type = _USER_ROOTPATH;
372 strncpy(user->rootpath, data, WZD_MAX_PATH);
373 }
374 /* leech_slots */
375 else if (strcmp(varname, "leech_slots")==0) {
376 ul=strtoul(data, &ptr, 0);
377 /* TODO compare with USHORT_MAX */
378 if (*ptr) return -1;
379 mod_type = _USER_LEECHSLOTS; user->leech_slots = (unsigned short)ul;
380 }
381 /* max_dl */
382 else if (strcmp(varname, "max_dl")==0) {
383 ul=strtoul(data, &ptr, 0);
384 if (*ptr) return -1;
385 mod_type = _USER_MAX_DLS; user->max_dl_speed = ul;
386 }
387 /* max_idle */
388 else if (strcmp(varname, "max_idle")==0) {
389 ul=strtoul(data, &ptr, 0);
390 if (*ptr) return -1;
391 mod_type = _USER_IDLE; user->max_idle_time = ul;
392 }
393 /* max_ul */
394 else if (strcmp(varname, "max_ul")==0) {
395 ul=strtoul(data, &ptr, 0);
396 if (*ptr) return -1;
397 mod_type = _USER_MAX_ULS; user->max_ul_speed = ul;
398 }
399 /* num_logins */
400 else if (strcmp(varname, "num_logins")==0) {
401 ul=strtoul(data, &ptr,0);
402 if (*ptr) return -1;
403 mod_type = _USER_NUMLOGINS; user->num_logins = (unsigned short)ul;
404 }
405 /* pass */
406 else if (strcmp(varname, "pass")==0) {
407 mod_type = _USER_USERPASS;
408 strncpy(user->userpass, data, sizeof(user->userpass));
409 }
410 /* perms */
411 else if (strcmp(varname, "perms")==0) {
412 ul=strtoul(data, &ptr, 0);
413 if (*ptr) return -1;
414 mod_type = _USER_PERMS; user->userperms = ul;
415 }
416 /* ratio */
417 else if (strcmp(varname, "ratio")==0) {
418 ul=strtoul(data, &ptr,0);
419 if (*ptr) return -1;
420 mod_type = _USER_RATIO; user->ratio = ul;
421 }
422 /* tagline */
423 else if (strcmp(varname, "tag")==0) {
424 mod_type = _USER_TAGLINE;
425 strncpy(user->tagline, data, sizeof(user->tagline));
426 }
427 /* uid */ /* FIXME useless ? */
428 /* username (?) */
429 else if (strcmp(varname, "name")==0) {
430 mod_type = _USER_USERNAME;
431 strncpy(user->username, data, sizeof(user->username));
432 }
433 /* user_slots */
434 else if (strcmp(varname, "user_slots")==0) {
435 ul=strtoul(data, &ptr, 0);
436 /* TODO compare with USHORT_MAX */
437 if (*ptr) return -1;
438 mod_type = _USER_USERSLOTS; user->user_slots = (unsigned short)ul;
439 }
440
441 /* commit to backend */
442 ret = backend_mod_user(config->backends->filename, user->uid, user, mod_type);
443
444 return ret;
445 }
446
vars_user_new(const char * username,const char * pass,const char * groupname,wzd_config_t * config)447 int vars_user_new(const char *username, const char *pass, const char *groupname, wzd_config_t * config)
448 {
449 wzd_user_t * newuser;
450 int err;
451
452 if (!username || !groupname || !config) return -1;
453
454 newuser = user_create(username,pass,groupname,NULL,config,&err);
455 if (newuser == NULL) return err;
456
457 /* add it to backend */
458 err = backend_mod_user(config->backends->filename,0,newuser,_USER_CREATE);
459
460 if (err) { /* problem adding user */
461 user_free(newuser);
462 }
463
464 return err ? 1 : 0;
465 }
466
vars_group_get(const char * groupname,const char * varname,void * data,unsigned int datalength,wzd_config_t * config)467 int vars_group_get(const char *groupname, const char *varname, void *data, unsigned int datalength, wzd_config_t * config)
468 {
469 wzd_group_t * group;
470
471 if (!groupname || !varname) return 1;
472
473 group = GetGroupByName(groupname);
474 if (!group) return 1;
475
476 if (strcasecmp(varname,"home")==0) {
477 snprintf(data,datalength,"%s",group->defaultpath);
478 return 0;
479 }
480 if (strcasecmp(varname,"max_dl")==0) {
481 snprintf(data,datalength,"%u",group->max_dl_speed);
482 return 0;
483 }
484 if (strcasecmp(varname,"max_ul")==0) {
485 snprintf(data,datalength,"%u",group->max_ul_speed);
486 return 0;
487 }
488 if (strcasecmp(varname,"name")==0) {
489 snprintf(data,datalength,"%s",group->groupname);
490 return 0;
491 }
492 if (strcasecmp(varname,"tag")==0) {
493 if (group->tagline[0] != '\0')
494 snprintf(data,datalength,"%s",group->tagline);
495 else
496 snprintf(data,datalength,"no tagline set");
497 return 0;
498 }
499
500 return 1;
501 }
502
vars_group_set(const char * groupname,const char * varname,const void * data,unsigned int datalength,wzd_config_t * config)503 int vars_group_set(const char *groupname, const char *varname, const void *data, unsigned int datalength, wzd_config_t * config)
504 {
505 wzd_group_t * group;
506 unsigned long mod_type;
507 unsigned long ul;
508 char *ptr;
509 int ret;
510
511 if (!groupname || !varname) return 1;
512
513 group = GetGroupByName(groupname);
514 if (!group) return -1;
515
516 /* find modification type */
517 mod_type = _GROUP_NOTHING;
518
519 /* groupname */
520 if (strcmp(varname,"name")==0) {
521 mod_type = _GROUP_GROUPNAME;
522 strncpy(group->groupname,data,sizeof(group->groupname));
523 /* NOTE: we do not need to iterate through users, group is referenced
524 * by id, not by name
525 */
526 }
527 /* tagline */
528 else if (strcmp(varname,"tag")==0) {
529 mod_type = _GROUP_TAGLINE;
530 strncpy(group->tagline,data,sizeof(group->tagline));
531 }
532 /* homedir */
533 else if (strcmp(varname,"home")==0) {
534 /* check if homedir exist */
535 {
536 fs_filestat_t s;
537 if (fs_file_stat(data,&s) || !S_ISDIR(s.mode)) {
538 /* Homedir does not exist */
539 return 2;
540 }
541 }
542 mod_type = _GROUP_DEFAULTPATH;
543 strncpy(group->defaultpath,data,WZD_MAX_PATH);
544 }
545 /* max_idle */
546 else if (strcmp(varname,"max_idle")==0) {
547 ul=strtoul(data,&ptr,0);
548 if (!*ptr) { mod_type = _GROUP_IDLE; group->max_idle_time = ul; }
549 }
550 /* perms */
551 else if (strcmp(varname,"perms")==0) {
552 ul=strtoul(data,&ptr,0);
553 if (!*ptr) { mod_type = _GROUP_GROUPPERMS; group->groupperms = ul; }
554 }
555 /* max_ul */
556 else if (strcmp(varname,"max_ul")==0) {
557 ul=strtoul(data,&ptr,0);
558 if (!*ptr) { mod_type = _GROUP_MAX_ULS; group->max_ul_speed = ul; }
559 }
560 /* max_dl */
561 else if (strcmp(varname,"max_dl")==0) {
562 ul=strtoul(data,&ptr,0);
563 if (!*ptr) { mod_type = _GROUP_MAX_DLS; group->max_dl_speed = ul; }
564 }
565 /* num_logins */
566 else if (strcmp(varname,"num_logins")==0) {
567 ul=strtoul(data,&ptr,0);
568 if (!*ptr) { mod_type = _GROUP_NUMLOGINS; group->num_logins = (unsigned short)ul; }
569 }
570 /* ratio */
571 else if (strcmp(varname,"ratio")==0) {
572 ul=strtoul(data,&ptr,0);
573 if (!*ptr) {
574 mod_type = _GROUP_RATIO; group->ratio = ul;
575 }
576 }
577
578 /* commit to backend */
579 ret = backend_mod_group(config->backends->filename, group->gid, group, mod_type);
580
581 return ret;
582 }
583
vars_group_new(const char * groupname,wzd_config_t * config)584 int vars_group_new(const char *groupname, wzd_config_t * config)
585 {
586 int err;
587 wzd_group_t * newgroup;
588
589 newgroup = group_create(groupname,NULL,config,&err);
590 if (newgroup == NULL) return err;
591
592 /* add it to backend */
593 err = backend_mod_group(config->backends->filename,0,newgroup,_GROUP_CREATE);
594
595 if (err) { /* problem adding group */
596 group_free(newgroup);
597 }
598
599 return (err) ? 1 : 0;
600 }
601
602
_str_hash(const char * key)603 static unsigned int _str_hash(const char *key)
604 {
605 const char *p = key;
606 unsigned int h = *p;
607
608 if (h)
609 for (p += 1; *p != '\0'; p++)
610 h = (h << 5) - h + *p;
611 return h;
612 }
613
614
615
vars_shm_init(void)616 void vars_shm_init(void)
617 {
618 memset(_shm_vars, 0, sizeof(_shm_vars));
619 }
620
vars_shm_free(void)621 void vars_shm_free(void)
622 {
623 unsigned int i;
624 struct wzd_shm_vars_t * var, * next_var;
625
626 WZD_MUTEX_LOCK(SET_MUTEX_SHVARS);
627 for (i=0; i<32; i++)
628 {
629 var = _shm_vars[i];
630 _shm_vars[i] = 0;
631
632 while (var) {
633 if (var->key) {
634 wzd_free(var->key);
635 wzd_free(var->data);
636 }
637
638 next_var = var->next_var;
639 wzd_free(var);
640 var = next_var;
641 }
642 }
643 WZD_MUTEX_UNLOCK(SET_MUTEX_SHVARS);
644 }
645
646 /* finds shm entry corresponding to 'varname'
647 * @returns a pointer to the struct or NULL
648 */
vars_shm_find(const char * varname,wzd_config_t * config)649 struct wzd_shm_vars_t * vars_shm_find(const char *varname, wzd_config_t * config)
650 {
651 unsigned int hash;
652 unsigned short index;
653 struct wzd_shm_vars_t * var;
654
655 hash = _str_hash(varname);
656 index = (hash >> 7) & 31; /* take 5 bits start from the seventh, to give an index in 0 -> 31 */
657
658 var = _shm_vars[index];
659 while (var)
660 {
661 if (strcmp(var->key, varname)==0)
662 return var;
663 }
664
665 return NULL;
666 }
667
668 /* fills data with varname content, max size: datalength
669 * @returns 0 if ok, 1 if an error occured
670 */
vars_shm_get(const char * varname,void * data,unsigned int datalength,wzd_config_t * config)671 int vars_shm_get(const char *varname, void *data, unsigned int datalength, wzd_config_t * config)
672 {
673 struct wzd_shm_vars_t * var;
674 int ret = 1;
675
676 WZD_MUTEX_LOCK(SET_MUTEX_SHVARS);
677 var = vars_shm_find(varname, config);
678
679 if (var) {
680 memcpy(data, var->data, MIN(datalength,var->datalength));
681 ret = 0;
682 }
683
684 WZD_MUTEX_UNLOCK(SET_MUTEX_SHVARS);
685 return ret;
686 }
687
688 /* change varname with data contents size of data is datalength
689 * Create varname if needed.
690 * @returns 0 if ok, 1 if an error occured
691 */
vars_shm_set(const char * varname,void * data,unsigned int datalength,wzd_config_t * config)692 int vars_shm_set(const char *varname, void *data, unsigned int datalength, wzd_config_t * config)
693 {
694 struct wzd_shm_vars_t * var;
695
696 WZD_MUTEX_LOCK(SET_MUTEX_SHVARS);
697
698 var = vars_shm_find(varname, config);
699
700 if (!var) { /* new variable, must create it */
701 unsigned int hash;
702 unsigned short index;
703
704 hash = _str_hash(varname);
705 index = (hash >> 7) & 31; /* take 5 bits start from the seventh, to give an index in 0 -> 31 */
706
707 var = wzd_malloc(sizeof(struct wzd_shm_vars_t));
708 var->key = wzd_strdup(varname);
709 var->data = wzd_malloc(datalength);
710 memcpy(var->data, data, datalength);
711 var->datalength = datalength;
712
713 /* insertion */
714 var->next_var = _shm_vars[index];
715 _shm_vars[index] = var;
716 } else {
717 /* modification */
718 if (datalength < var->datalength)
719 memcpy(var->data, data, datalength);
720 else { /* need to realloc */
721 var->data = wzd_realloc(var->data, datalength);
722 memcpy(var->data, data, datalength);
723 var->datalength = datalength;
724 }
725 }
726 WZD_MUTEX_UNLOCK(SET_MUTEX_SHVARS);
727
728 return 0;
729 }
730