1 /* Copyright (C) 2000-2006 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: UserFactory.pike,v 1.3 2010/02/09 19:33:24 astra Exp $
19 inherit "/factories/ContainerFactory";
26 #include <attributes.h>
29 class UserFactory : public ContainerFactory{
38 private array test_objects = ({ });
41 * Initialize the factory with its default attributes.
49 init_class_attribute(USER_ADRESS, CMD_TYPE_STRING, "user adress",
50 0, EVENT_ATTRIBUTES_CHANGE, 0,
51 CONTROL_ATTR_USER, "");
53 init_class_attribute(USER_MODE, CMD_TYPE_INT, "user mode",
54 0, EVENT_ATTRIBUTES_CHANGE, 0,
55 CONTROL_ATTR_CLIENT, 0);
57 init_class_attribute(USER_UMASK, CMD_TYPE_MAPPING, "user umask",
58 EVENT_ATTRIBUTES_QUERY, EVENT_ATTRIBUTES_CHANGE,0,
59 CONTROL_ATTR_USER, ([ ]));
61 init_class_attribute(USER_MODE_MSG, CMD_TYPE_STRING,
62 "user mode message", 0,
63 EVENT_ATTRIBUTES_CHANGE, 0,CONTROL_ATTR_USER,"");
65 init_class_attribute(USER_EMAIL, CMD_TYPE_STRING, "email",
66 0, EVENT_ATTRIBUTES_CHANGE,0,
67 CONTROL_ATTR_USER, "");
69 init_class_attribute(USER_FULLNAME, CMD_TYPE_STRING, "user fullname",0,
70 EVENT_ATTRIBUTES_CHANGE, 0,CONTROL_ATTR_USER, "");
72 init_class_attribute(USER_WORKROOM, CMD_TYPE_OBJECT, "workroom", 0,
73 EVENT_ATTRIBUTES_CHANGE, 0,CONTROL_ATTR_USER, 0);
75 init_class_attribute(USER_LOGOUT_PLACE, CMD_TYPE_OBJECT, "logout-env",
76 0, EVENT_ATTRIBUTES_CHANGE, 0,
77 CONTROL_ATTR_USER, 0);
79 init_class_attribute(USER_LAST_LOGIN, CMD_TYPE_TIME, "last-login",
80 0, EVENT_ATTRIBUTES_CHANGE, 0,
81 CONTROL_ATTR_SERVER, 0);
83 init_class_attribute(USER_BOOKMARKROOM, CMD_TYPE_OBJECT, "bookmark room",0,
84 EVENT_ATTRIBUTES_CHANGE, 0,CONTROL_ATTR_USER, 0);
86 init_class_attribute(USER_FORWARD_MSG, CMD_TYPE_INT, "forward message",
87 0, EVENT_ATTRIBUTES_CHANGE, 0,
88 CONTROL_ATTR_USER, 1);
90 init_class_attribute(USER_FAVOURITES, CMD_TYPE_ARRAY, "favourites list",
91 0, EVENT_ATTRIBUTES_CHANGE, 0,
92 CONTROL_ATTR_USER, ({ }) );
96 init_class_attribute(USER_CALENDAR, CMD_TYPE_OBJECT, "calendar", 0,
97 EVENT_ATTRIBUTES_CHANGE, 0, CONTROL_ATTR_SERVER,0);
99 init_class_attribute(USER_MONITOR, CMD_TYPE_OBJECT, "monitor", 0,
100 EVENT_ATTRIBUTES_CHANGE, 0, CONTROL_ATTR_SERVER,0);
102 init_class_attribute(USER_ID, CMD_TYPE_STRING, "user id",
103 EVENT_ATTRIBUTES_QUERY,
104 EVENT_ATTRIBUTES_CHANGE,
105 0,CONTROL_ATTR_USER, "");
109 * Create a new user object with the following vars:
110 * name - the users name (nickname is possible too).
111 * email - the users email adress.
112 * pw - the users initial password.
113 * fullname - the full name of the user.
114 * firstname - the last name of the user.
116 * @param mapping vars - variables for execution.
117 * @return the objectp of the new user if successfully, or 0 (no access or user
120 object execute(mapping vars)
125 try_event(EVENT_EXECUTE, CALLER, obj);
127 if ( stringp(vars["nickname"]) )
128 name = string_to_utf8(lower_case(utf8_to_string(vars["nickname"])));
132 obj = MODULE_USERS->lookup(name);
134 steam_error("user_create(): User does already exist.");
135 obj = MODULE_GROUPS->lookup(name);
137 steam_error("user_create(): Group with this name already exist.");
140 object ouid = seteuid(USER("root"));
141 obj = user_create(vars);
145 FATAL("Error in UserFactory: %O\n%O", err[0], err[1]);
146 // try to find the user and remove
147 obj = MODULE_USERS->lookup(name);
148 if ( objectp(obj) ) {
153 run_event(EVENT_EXECUTE, CALLER, obj);
160 private object user_create(mapping vars)
164 try_event(EVENT_EXECUTE, CALLER, obj);
167 if ( stringp(vars["nickname"]) )
168 name = lower_case(vars["nickname"]);
172 if ( search(name, " ") >= 0 )
173 steam_error("Whitespaces in Usernames are not allowed");
175 string pw = vars["pw"];
176 string email = vars["email"];
178 if ( stringp(vars->fullname) && !xml.utf8_check(vars->fullname) )
179 steam_error("Failed utf8-check for firstname or fullname !");
181 if ( stringp(vars->firstname) && !xml.utf8_check(vars->firstname) )
182 steam_error("Failed utf8-check for firstname or fullname !");
184 obj = object_create(name, CLASS_NAME_USER, 0, vars["attributes"],
185 vars["attributesAcquired"], vars["attributesLocked"]);
187 function obj_set_attribute = obj->get_function("do_set_attribute");
188 function obj_lock_attribute = obj->get_function("do_lock_attribute");
189 function obj_sanction = obj->get_function("do_sanction_object");
191 obj_lock_attribute(OBJ_NAME);
192 if ( !objectp(obj) ) {
193 SECURITY_LOG("Creation of user " + name + " failed...");
194 return null; // creation failed...
198 if (stringp(vars["language"]))
199 language=vars["language"];
201 if ( stringp(vars["pw:crypt"]) )
202 obj->set_user_password(vars["pw:crypt"],1);
204 obj->set_user_password(pw);
205 obj->set_user_name(name);
206 obj_set_attribute(USER_EMAIL, email);
207 obj_set_attribute(USER_FULLNAME, vars["fullname"]);
208 obj_set_attribute(USER_FIRSTNAME, vars["firstname"]);
210 if (stringp(language))
211 obj_set_attribute(USER_LANGUAGE, language);
212 obj->set_creator(_ROOT);
214 if ( objectp(this_user()) && this_user() != _GUEST )
215 obj_sanction(this_user(), SANCTION_ALL);
217 if ( stringp(vars["description"]) )
218 obj_set_attribute(OBJ_DESC, vars["description"]);
219 if ( stringp(vars["contact"]) )
220 obj_set_attribute(USER_ADRESS, vars["contact"]);
222 // create sent-mail folder and activate storage of sent-mails:
223 if ( name != "guest" ) {
224 object old_euid = geteuid();
227 obj->create_sent_mail_folder();
228 obj->set_is_storing_sent_mail( 1 );
233 object workroom, factory, calendar;
235 factory = _Server->get_factory(CLASS_ROOM);
237 mapping workroomAttributes = ([
238 OBJ_DESC: name + "s workroom", ]);
240 workroom = factory->execute( ([
241 "name":name+"'s workarea",
242 "attributes": workroomAttributes,
246 obj_set_attribute(USER_WORKROOM, workroom);
247 obj_lock_attribute(USER_WORKROOM);
250 object bookmarkroom = factory->execute(([
251 "name":name+"'s bookmarks",
253 obj_set_attribute(USER_BOOKMARKROOM, bookmarkroom);
254 obj_lock_attribute(USER_BOOKMARKROOM);
257 factory = _Server->get_factory(CLASS_TRASHBIN);
258 mapping trashbinAttributes = ([ OBJ_DESC: "Trashbin", ]);
259 object trashbin = factory->execute( ([
260 "name":"trashbin", "attributes":trashbinAttributes,
262 trashbin->set_acquire(0);
264 obj_set_attribute(USER_TRASHBIN, trashbin);
266 calendar = _Server->get_factory(CLASS_CALENDAR)->execute( ([
267 "name":name+"'s calendar", "attributes":calendarAttributes,
268 "attributesLocked": ([ CALENDAR_OWNER: 1, ]),
270 obj_set_attribute(USER_CALENDAR, calendar);
271 obj_lock_attribute(USER_CALENDAR);
273 // steam users can annotate and read the users attributes.
274 obj_sanction(_STEAMUSER, SANCTION_READ|SANCTION_ANNOTATE);
276 object forwards = get_module("forward");
277 if ( objectp(forwards) ) {
278 string mname = forwards->get_mask_char() + obj->get_user_name();
279 if ( stringp(email) && sizeof(email) > 0 ) {
281 FATAL("Failed to set forward to e-mail %O when creating user %O",
287 if ( name != "guest" ) {
291 if ( !_Persistence->get_dont_create_exits() ) {
292 array inv = workroom->get_inventory_by_class(CLASS_EXIT);
293 if ( sizeof(inv) == 0 ) {
294 factory = _Server->get_factory(CLASS_EXIT);
295 object swa = _STEAMUSER->query_attribute(GROUP_WORKROOM);
296 string exitname = "steam";
298 exitname = swa->get_identifier();
300 if ( strlen(exitname) == 0 )
303 object exit = factory->execute(([ "name": exitname, "exit_to": swa,]));
304 exit->move(workroom);
308 run_event(EVENT_EXECUTE, CALLER, obj);
310 // now remove all guest privileges on this object
311 if ( objectp(_GUEST) ) {
312 obj_sanction(_GUEST, 0);
314 iActivation = time() + random(100000);
315 obj->set_activation(iActivation);
322 * Queries and resets the activation code for an user. Thus
323 * it is required, that the creating object immidiately calls
324 * this function and sends the activation code to the user.
326 * @return activation code for the last created user
330 int res = iActivation;
335 object create_sent_mail_folder ( object user, void|string name )
337 _SECURITY->check_access(user, CALLER, SANCTION_READ, ROLE_READ_ALL, false);
339 if ( user == _GUEST ) return UNDEFINED;
340 object sent_mail = user->query_attribute( USER_MAIL_SENT );
341 if ( objectp(sent_mail) ) return sent_mail;
342 if ( !stringp(name) ) name = "sent";
344 _SECURITY->check_access(user, CALLER, SANCTION_WRITE, ROLE_WRITE_ALL, false);
347 sent_mail = get_factory( CLASS_CONTAINER )->execute(
348 ([ "name" : name, "attributes" : ([ OBJ_OWNER : user ]),
349 "sanction" : ([ user : SANCTION_ALL, _GUEST:0 ]) ]) );
350 if ( !objectp(sent_mail) )
352 sent_mail->set_creator( user );
353 user->add_annotation( sent_mail );
354 return user->set_sent_mail_folder( sent_mail );
359 string rename_user(object user, string new_name)
361 _SECURITY->check_access(user,CALLER,SANCTION_WRITE,ROLE_WRITE_ALL,false);
363 _Persistence->uncache_object( user );
365 object users = get_module("users");
367 if ( users->lookup(user->get_user_name()) != user )
368 user->set_user_name(new_name);
370 _Persistence->uncache_object( user );
372 // unmount user from home module:
373 int is_mounted = get_module( "home" )->is_mounted( user );
374 if ( is_mounted ) get_module( "home" )->unmount( user );
376 if ( users->rename_user(user, new_name) == new_name )
377 user->set_user_name(new_name);
379 _Persistence->uncache_object( user );
381 // re-mount user in home module:
382 if ( is_mounted ) get_module( "home" )->mount( user );
384 return user->get_user_name();
388 * Finds broken user objects (users with 0 username) and returns the user
390 * @return an array of usernames of broken users
392 array get_broken_users()
394 array result = ({ });
395 foreach ( get_module("users")->index(), string uname ) {
397 object user = get_module("users")->lookup(uname);
398 if ( objectp(user) && (user->get_object_class() & CLASS_USER) &&
399 (user->get_user_name()==0 || user->query_attribute(OBJ_NAME)==0) )
400 result += ({ uname });
407 * Function that tries to recover broken user objects (users with 0 username).
408 * @param user_names (optional) array of usernames (not user objects!) to
409 * recover. If missing, all broken users will be recovered.
410 * @return an array with the recovered user objects
412 array recover_users( void|array user_names)
414 array result = ({ });
416 MESSAGE("Starting USER RECOVERY !");
418 if ( !arrayp(user_names) ) {
419 MESSAGE("Checking all users...");
420 user_names = get_broken_users();
423 MESSAGE("Checking %d users...", sizeof(user_names));
425 foreach( user_names, mixed uname ) {
426 if ( !stringp(uname) ) continue;
428 object user = get_module("users")->lookup(uname);
429 if ( objectp(user) && (user->get_object_class() & CLASS_USER) &&
430 user->get_user_name()==0 || user->query_attribute(OBJ_NAME)==0 ) {
431 result += ({ user });
432 user->set_user_name(uname);
434 int user_oid = user->get_object_id();
436 int oid = user_oid + 1;
437 object obj = find_object( oid++ );
439 ((obj->get_object_class() & CLASS_ROOM) != CLASS_ROOM) ) {
440 // probably the sent-mail folder:
441 obj = find_object( oid++ );
443 if ( objectp(obj) && (obj->get_object_class() & CLASS_ROOM) )
444 user->set_attribute(USER_WORKROOM, obj);
445 obj = find_object( oid++ );
446 if ( objectp(obj) && (obj->get_object_class() & CLASS_ROOM) )
447 user->set_attribute(USER_BOOKMARKROOM, obj);
448 obj = find_object( oid++ );
449 if ( objectp(obj) && (obj->get_object_class() & CLASS_TRASHBIN) )
450 user->set_attribute(USER_TRASHBIN, obj);
451 obj = find_object( oid++ );
452 if ( objectp(obj) && (obj->get_object_class() & CLASS_CALENDAR) )
453 user->set_attribute(USER_CALENDAR, obj);
456 array groups = user->get_groups();
457 foreach ( get_module("groups")->get_groups(), object grp ) {
458 if ( grp->is_member(user) && search(groups, grp) == -1 ) {
459 grp->remove_member(user);
460 grp->add_member(user);
463 MESSAGE("Recovered user %O", uname );
467 FATAL("Failed to restore %O\n%O\n%O", uname, err0[0], err0[1]);
469 MESSAGE("Finished USER RECOVERY in %d seconds", time() - t);
475 USER("guest")->unlock_attribute(OBJ_NAME);
476 USER("guest")->set_attribute(OBJ_NAME, "guest");
477 USER("guest")->set_user_password("guest");
478 USER("guest")->set_user_name("guest");
479 foreach(USER("guest")->get_groups(), object grp) {
480 if ( grp != GROUP("everyone") )
481 grp->remove_member(USER("guest"));
485 string get_identifier() { return "User.factory"; }
486 string get_class_name() { return "User"; }
487 int get_class_id() { return CLASS_USER; }
495 uname = "test_" + ((string)time()) + "_" + ((string)uname_count++);
496 user = USER( uname );
497 } while ( objectp(user) );
498 user = execute( (["name": uname, "pw":"test", "email": "xyz",]) );
499 if ( objectp(user) ) test_objects += ({ user });
500 Test.test( "creating user", objectp(user) );
502 // try to get attributes
503 Test.test("User Attribute e-mail",
504 user->query_attribute(USER_EMAIL) == "xyz");
505 // now try to protect
506 user->add_attribute_reader(USER_EMAIL, user); // only for himself
507 Test.test("User Attribute by Root",
508 user->query_attribute(USER_EMAIL) == "xyz");
512 uname2 = "test2_"+ ((string)time()) + "_" + ((string)random(10000));
513 user2 = USER( uname2 );
514 } while ( objectp(user2) );
515 user2 = execute( (["name": uname2, "pw":"test", "email": "xyz",]) );
516 if ( objectp(user2) ) test_objects += ({ user2 });
518 Test.test("EUID", geteuid() == user2);
519 mixed err = catch(user->query_attribute(USER_EMAIL));
520 Test.test("Restricted Attribute access denied", err != 0);
521 werror("Looking up by email !\n");
522 array users = get_module("users")->lookup_email("xyz");
523 Test.test("Restricted email lookup fail", search(users, user)==-1);
526 if ( GROUP("steam") ) {
527 Test.test( "new user is in steam group",
528 GROUP("steam")->is_member( user ) );
529 //if ( !GROUP("steam")->is_member(user) )
530 // steam_error("Failure creating user: no in steam group !");
532 Test.test( "deleting user", user->delete() );
534 Test.test( "user unregistered ?",
535 !objectp(get_module("users")->lookup(uname)),
536 "Lookup of user still found !");
539 void test_cleanup () {
540 if ( arrayp(test_objects) ) {
541 foreach ( test_objects, object obj )
542 catch ( obj->delete() );