1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import re
20 import crypt
21
22
23 from rhn.UserDictCase import UserDictCase
24 from spacewalk.common.rhnLog import log_debug, log_error
25 from spacewalk.common.rhnConfig import CFG
26 from spacewalk.common.rhnException import rhnFault, rhnException
27 from spacewalk.common.rhnTranslate import _
28
29 import rhnSQL
30 import rhnSession
31
32
34
35 """ Main User class """
36
57
59 """ init web_user_personal_info """
60
61 self.info = rhnSQL.Row("web_user_personal_info",
62 "web_user_id")
63 self.info['first_names'] = "Valued"
64 self.info['last_name'] = "Customer"
65 self.info['prefix'] = "Mr."
66
68 """ init web_user_contact_permission """
69
70 self.perms = rhnSQL.Row("web_user_contact_permission",
71 "web_user_id")
72 self.perms["email"] = "Y"
73 self.perms["mail"] = "Y"
74 self.perms["call"] = "Y"
75 self.perms["fax"] = "Y"
76
78 """ init web_user_site_info """
79
80 self.site = rhnSQL.Row("web_user_site_info", "id")
81 self.site['city'] = "."
82 self.site['address1'] = "."
83 self.site['country'] = "US"
84 self.site['type'] = "M"
85 self.site['notes'] = "Entry created by Spacewalk registration process"
86
88 """ simple check for a password that might become more complex sometime """
89 if not allow_read_only and is_user_read_only(self.contact["login"]):
90 raise rhnFault(702)
91 good_pwd = str(self.contact["password"])
92 if CFG.pam_auth_service:
93
94
95
96
97
98
99
100
101 h = rhnSQL.prepare("""
102 select ui.use_pam_authentication
103 from web_contact w, rhnUserInfo ui
104 where w.login_uc = UPPER(:login)
105 and w.id = ui.user_id""")
106 h.execute(login=self.contact["login"])
107 data = h.fetchone_dict()
108 if not data:
109
110 raise rhnException("No entry found for user %s" %
111 self.contact["login"])
112 if data['use_pam_authentication'] == 'Y':
113
114 import rhnAuthPAM
115 return rhnAuthPAM.check_password(self.contact["login"],
116 password, CFG.pam_auth_service)
117
118 ret = check_password(password, good_pwd)
119 if ret and CFG.encrypted_passwords and self.contact['password'].find('$1$') == 0:
120
121
122 self.contact['password'] = encrypt_password(password)
123 self.contact.save()
124 rhnSQL.commit()
125 return ret
126
128 if not org_id:
129 raise rhnException("Invalid org_id requested for user", org_id)
130 self.contact["org_id"] = int(org_id)
131 self.customer.load(int(org_id))
132
134 if not self.contact.has_key("id"):
135 userid = rhnSQL.Sequence("web_contact_id_seq")()
136 self.contact.data["id"] = userid
137 else:
138 userid = self.contact["id"]
139 return userid
140
158
160 """ set a certain value for the userinfo field. This is BUTT ugly. """
161 log_debug(3, name, value)
162
163
164 mapping = {
165 "first_name": "first_names",
166 "position": "title",
167 "title": "prefix"
168 }
169 if not name:
170 return -1
171 name = name.lower()
172 if type(value) == type(""):
173 value = value.strip()
174
175
176 changed = 0
177
178
179 if name in list(mapping.keys()):
180 name = mapping[name]
181
182 if name in ["first_names", "last_name", "prefix",
183 "address1", "city", "country"]:
184
185 if len(str(value)) == 0:
186 return -1
187
188 if name in ["last_name", "first_names",
189 "company", "phone", "fax", "email", "title"]:
190 self.info[name] = value[:128]
191 changed = 1
192 elif name == "prefix":
193 values = ["Mr.", "Mrs.", "Ms.", "Dr.", "Hr.", "Sr.", " "]
194
195 valids = UserDictCase()
196 for v in values:
197 valids[v] = v
198 valids[v[:-1]] = v
199
200 valids["Miss"] = "Miss"
201 valids["Herr"] = "Hr."
202 valids["Sig."] = "Sr."
203 valids["Sir"] = "Mr."
204
205 if valids.has_key(value):
206 self.info["prefix"] = valids[value]
207 changed = 1
208 else:
209 log_error("Unknown prefix value `%s'. Assumed `Mr.' instead"
210 % value)
211 self.info["prefix"] = "Mr."
212 changed = 1
213
214
215 if name in ["phone", "fax", "zip"]:
216 self.site[name] = value[:32]
217 changed = 1
218 elif name in ["city", "country", "alt_first_names", "alt_last_name",
219 "address1", "address2", "email",
220 "last_name", "first_names"]:
221 if name == "last_name":
222 self.site["alt_last_name"] = value
223 changed = 1
224 elif name == "first_names":
225 self.site["alt_first_names"] = value
226 changed = 1
227 else:
228 self.site[name] = value[:128]
229 changed = 1
230 elif name in ["state"]:
231 self.site[name] = value[:60]
232 changed = 1
233 if not changed:
234 log_error("SET_INFO: Unknown info `%s' = `%s'" % (name, value))
235 return 0
236
238 user_id = self.getid()
239
240 h = rhnSQL.prepare("""
241 select ugt.label as role
242 from rhnUserGroup ug,
243 rhnUserGroupType ugt,
244 rhnUserGroupMembers ugm
245 where ugm.user_id = :user_id
246 and ugm.user_group_id = ug.id
247 and ug.group_type = ugt.id
248 """)
249 h.execute(user_id=user_id)
250 return [x['role'] for x in h.fetchall_dict() or []]
251
253 """ Reload the current data from the SQL database using the given id """
254 log_debug(3, user_id)
255
256
257 if not self.contact.load(user_id):
258 raise rhnException("Could not find contact record for id", user_id)
259 if not self.customer.load(self.contact["org_id"]):
260 raise rhnException("Could not find org record",
261 "user_id = %s" % user_id,
262 "org_id = %s" % self.contact["org_id"])
263
264 if not self.info.load(user_id):
265 self.__init_info()
266 if not self.perms.load(user_id):
267 self.__init_perms()
268
269 if not self.site.load_sql("web_user_id = :userid and type = 'M'",
270 {"userid": user_id}):
271 self.__init_site()
272
273 self.username = self.contact['login']
274 return 0
275
282
283
295
296
310
311
324
325
339
340
353
354
368
369
373
374
376 encrypted_password = CFG.encrypted_passwords
377 log_debug(3, user, CFG.disallow_user_creation, encrypted_password, CFG.pam_auth_service)
378 user = str(user)
379 h = rhnSQL.prepare("""
380 select w.id, w.password, w.org_id, ui.use_pam_authentication
381 from web_contact w, rhnUserInfo ui
382 where w.login_uc = upper(:p1)
383 and w.id = ui.user_id
384 """)
385 h.execute(p1=user)
386 data = h.fetchone_dict()
387 if data and data["id"]:
388
389 if data['use_pam_authentication'] == 'Y' and CFG.pam_auth_service:
390
391 import rhnAuthPAM
392 if rhnAuthPAM.check_password(user, password, CFG.pam_auth_service) > 0:
393 return 1
394 return -1
395
396 if check_password(password, data['password']) > 0:
397 return 1
398 return -1
399
400
401 if CFG.disallow_user_creation:
402 raise rhnFault(2001)
403 user, password = check_user_password(user, password)
404
405
406 h = rhnSQL.prepare("""
407 select r.login, r.password from rhnUserReserved r
408 where r.login_uc = upper(:p1)
409 """)
410 h.execute(p1=user)
411 data = h.fetchone_dict()
412 if data and data["login"]:
413
414 if check_password(password, data["password"]) > 0:
415 return 1
416 return -2
417
418 validate_new_username(user)
419 log_debug(3, "calling validate_new_password")
420 validate_new_password(password)
421
422
423 if encrypted_password:
424
425 password = encrypt_password(password)
426
427 h = rhnSQL.prepare("""
428 insert into rhnUserReserved (login, password)
429 values (:username, :password)
430 """)
431 h.execute(username=user, password=password)
432 rhnSQL.commit()
433
434
435 return 0
436
437
438 -def new_user(username, password, email, org_id, org_password):
441
442
443 -def __new_user_db(username, password, email, org_id, org_password):
444 encrypted_password = CFG.encrypted_passwords
445 log_debug(3, username, email, encrypted_password)
446
447
448 h = rhnSQL.prepare("""
449 select w.id, w.password, ui.use_pam_authentication
450 from web_contact w, rhnUserInfo ui
451 where w.login_uc = upper(:username)
452 and w.id = ui.user_id
453 """)
454 h.execute(username=username)
455 data = h.fetchone_dict()
456
457 pre_existing_user = 0
458
459 if not data:
460
461 h = rhnSQL.prepare("""
462 select login, password from rhnUserReserved
463 where login_uc = upper(:username)
464 """)
465 h.execute(username=username)
466 data = h.fetchone_dict()
467 if not data:
468 raise rhnFault(1, _("Username `%s' has not been reserved") % username)
469 else:
470 pre_existing_user = 1
471
472 if not pre_existing_user and not email:
473
474 raise rhnFault(30, _("E-mail address not specified"))
475
476
477
478
479
480 if data.get('use_pam_authentication') == 'Y' and CFG.pam_auth_service:
481
482 import rhnAuthPAM
483 if rhnAuthPAM.check_password(username, password, CFG.pam_auth_service) <= 0:
484
485 raise rhnFault(2)
486
487 import time
488 password = 'pam:%.8f' % time.time()
489 else:
490
491 if check_password(password, data["password"]) == 0:
492
493 raise rhnFault(2)
494
495
496
497
498 return 0
499
500
531
532
534 """ Do some minimal checks on the e-mail address """
535 if email is not None:
536 email = email.strip()
537
538 if not email:
539
540 return None
541
542 if len(email) > CFG.MAX_EMAIL_LEN:
543 raise rhnFault(100, _("Please limit your e-mail address to %s chars") %
544 CFG.MAX_EMAIL_LEN)
545
546 return email
547
548
550 """ Validates the given key against the current or old password
551 If encrypted_password is false, it compares key with pwd1.
552 If encrypted_password is true, it compares the encrypted key
553 with pwd1.
554
555 Historical note: we used to compare the passwords case-insensitive, and that
556 was working fine until we started to encrypt passwords. -- misa 20030530
557 """
558 encrypted_password = CFG.encrypted_passwords
559 log_debug(4, "Encrypted password:", encrypted_password)
560
561 key = str(key)
562 if len(key) == 0:
563
564 return 0
565
566 if not encrypted_password:
567
568 if key == pwd1:
569 return 1
570 log_debug(4, "Unencrypted password doesn't match")
571 return 0
572
573
574 if pwd1.find("$5") == 0:
575 if pwd1 == encrypt_password(key, pwd1, 'SHA-256'):
576 return 1
577 elif pwd1.find("$1$") == 0:
578 if pwd1 == encrypt_password(key, pwd1, 'MD5'):
579 return 1
580
581 log_debug(4, "Encrypted password doesn't match")
582 return 0
583
584
586 """ Encrypt the key
587 If no salt is supplied, generates one (md5-crypt salt)
588 """
589
590 pw_params = {
591 'MD5': [8, "$1$"],
592 'SHA-256': [16, "$5$"],
593 }
594
595 if not salt:
596
597 import base64
598 import time
599 import os
600
601
602 salt = (time.time() % 1) * 1e15 + os.getpid()
603
604 salt = base64.encodestring(str(salt))[:pw_params[method][0]]
605
606 salt = pw_params[method][1] + salt + '$'
607 salt = str(salt)
608 return crypt.crypt(key, salt)
609
610
612 """ Perform all the checks required for new passwords """
613 log_debug(3, "Entered validate_new_password")
614
615
616
617
618
619
620
621 if not password:
622 raise rhnFault(12)
623 if len(password) < CFG.MIN_PASSWD_LEN:
624 raise rhnFault(14, _("password must be at least %d characters")
625 % CFG.MIN_PASSWD_LEN)
626 if len(password) > CFG.MAX_PASSWD_LEN:
627 raise rhnFault(701, _("Password must be shorter than %d characters")
628 % CFG.MAX_PASSWD_LEN)
629
630 password = password[:CFG.MAX_PASSWD_LEN]
631 invalid_re = re.compile(
632 r"[^ A-Za-z0-9`!@#$%^&*()-_=+[{\]}\\|;:'\",<.>/?~]")
633 asterisks_re = re.compile(r"^\**$")
634
635
636 tmp = asterisks_re.match(password)
637 if tmp is not None:
638 raise rhnFault(15, "password cannot be all asterisks '*'")
639
640
641 tmp = invalid_re.search(password)
642 if tmp is not None:
643 pos = tmp.regs[0]
644 raise rhnFault(15,
645 _("password contains character `%s'") % password[pos[1] - 1])
646
647
649 """ Perform all the checks required for new usernames. """
650 log_debug(3)
651 if len(username) < CFG.MIN_NEW_USER_LEN:
652 raise rhnFault(13, _("username should be at least %d characters long")
653 % CFG.MIN_NEW_USER_LEN)
654
655 disallowed_suffixes = CFG.DISALLOWED_SUFFIXES or []
656 if not isinstance(disallowed_suffixes, type([])):
657 disallowed_suffixes = [disallowed_suffixes]
658
659 log_debug(4, "Disallowed suffixes", disallowed_suffixes)
660
661 for suffix in disallowed_suffixes:
662 if username[-len(suffix):].upper() == suffix.upper():
663 raise rhnFault(106, _("Cannot register usernames ending with %s") %
664 suffix)
665