2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1996-1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
29 * This is set on startup - it defines the SID for this
32 DOM_SID global_machine_sid;
34 /**********************************************************
35 **********************************************************
37 low-level redirection routines:
51 **********************************************************
52 **********************************************************/
54 /***************************************************************
55 Start to enumerate the sam passwd list. Returns a void pointer
56 to ensure no modification outside this module.
57 ****************************************************************/
58 void *startsampwent(BOOL update)
61 return startldappwent(update);
63 return startsmbpwent(update);
67 /***************************************************************
68 End enumeration of the sam passwd list.
69 ****************************************************************/
70 void endsampwent(void *vp)
79 /*************************************************************************
80 Routine to return the next entry in the sam passwd list.
81 *************************************************************************/
82 struct smb_passwd *getsampwent(void *vp)
85 return getldappwent(vp);
87 return getsmbpwent(vp);
91 /*************************************************************************
92 Routine to return the next entry in the sam passwd list.
93 *************************************************************************/
94 struct sam_passwd *getsam21pwent(void *vp)
97 return getldap21pwent(vp);
99 return getsmb21pwent(vp);
100 #endif /* USE_LDAP */
103 /*************************************************************************
104 Return the current position in the sam passwd list as an unsigned long.
105 This must be treated as an opaque token.
106 *************************************************************************/
107 unsigned long getsampwpos(void *vp)
110 return getldappwpos(vp);
112 return getsmbpwpos(vp);
113 #endif /* USE_LDAP */
116 /*************************************************************************
117 Set the current position in the sam passwd list from unsigned long.
118 This must be treated as an opaque token.
119 *************************************************************************/
120 BOOL setsampwpos(void *vp, unsigned long tok)
123 return setldappwpos(vp, tok);
125 return setsmbpwpos(vp, tok);
126 #endif /* USE_LDAP */
129 /************************************************************************
130 Routine to add an entry to the sam passwd file.
131 *************************************************************************/
132 BOOL add_sampwd_entry(struct smb_passwd *newpwd)
135 return add_ldappwd_entry(newpwd);
137 return add_smbpwd_entry(newpwd);
138 #endif /* USE_LDAP */
141 /************************************************************************
142 Routine to add an entry to the sam passwd file.
143 *************************************************************************/
144 BOOL add_sam21pwd_entry(struct sam_passwd *newpwd)
148 return add_ldap21pwd_entry(newpwd);
150 return add_smb21pwd_entry(newpwd);
151 #endif /* USE_LDAP */
153 DEBUG(0,("add_sam21pwd_entry() - under development\n"));
158 /************************************************************************
159 Routine to search the sam passwd file for an entry matching the username.
160 and then modify its password entry. We can't use the startsampwent()/
161 getsampwent()/endsampwent() interfaces here as we depend on looking
162 in the actual file to decide how much room we have to write data.
163 override = False, normal
164 override = True, override XXXXXXXX'd out password or NO PASS
165 ************************************************************************/
166 BOOL mod_sampwd_entry(struct smb_passwd* pwd, BOOL override)
169 return mod_ldappwd_entry(pwd, override);
171 return mod_smbpwd_entry(pwd, override);
172 #endif /* USE_LDAP */
175 /************************************************************************
176 Routine to search the sam passwd file for an entry matching the username.
177 and then modify its password entry. We can't use the startsampwent()/
178 getsampwent()/endsampwent() interfaces here as we depend on looking
179 in the actual file to decide how much room we have to write data.
180 override = False, normal
181 override = True, override XXXXXXXX'd out password or NO PASS
182 ************************************************************************/
183 BOOL mod_sam21pwd_entry(struct sam_passwd* pwd, BOOL override)
187 return mod_ldap21pwd_entry(pwd, override);
189 return mod_smb21pwd_entry(pwd, override);
190 #endif /* USE_LDAP */
192 DEBUG(0,("mod_sam21pwd_entry() - under development\n"));
197 /**********************************************************
198 **********************************************************
200 high-level database routines:
206 **********************************************************
207 **********************************************************/
209 /************************************************************************
210 Routine to search sam passwd by name.
211 *************************************************************************/
212 struct smb_passwd *getsampwnam(char *name)
214 struct smb_passwd *pwd = NULL;
217 DEBUG(10, ("getsampwnam: search by name: %s\n", name));
219 /* Open the sam password file - not for update. */
220 fp = startsampwent(False);
224 DEBUG(0, ("getsampwnam: unable to open sam password database.\n"));
228 while ((pwd = getsampwent(fp)) != NULL && !strequal(pwd->smb_name, name));
232 DEBUG(10, ("getsampwnam: found by name: %s\n", name));
239 /************************************************************************
240 Routine to search sam passwd by name.
241 *************************************************************************/
242 struct sam_passwd *getsam21pwnam(char *name)
244 struct sam_passwd *pwd = NULL;
247 DEBUG(10, ("getsam21pwnam: search by name: %s\n", name));
249 /* Open the sam password file - not for update. */
250 fp = startsampwent(False);
254 DEBUG(0, ("getsam21pwnam: unable to open sam password database.\n"));
258 while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->smb_name, name));
262 DEBUG(10, ("getsam21pwnam: found by name: %s\n", name));
269 /************************************************************************
270 Routine to search sam passwd by uid.
271 *************************************************************************/
272 struct smb_passwd *getsampwuid(uid_t smb_userid)
274 struct smb_passwd *pwd = NULL;
277 DEBUG(10, ("getsampwuid: search by smb_userid: %x\n", smb_userid));
279 /* Open the sam password file - not for update. */
280 fp = startsampwent(False);
284 DEBUG(0, ("getsampwuid: unable to open sam password database.\n"));
288 while ((pwd = getsampwent(fp)) != NULL && pwd->smb_userid != smb_userid);
292 DEBUG(10, ("getsampwuid: found by smb_userid: %x\n", smb_userid));
299 /************************************************************************
300 Routine to search sam passwd by rid.
301 *************************************************************************/
302 struct sam_passwd *getsam21pwrid(uint32 rid)
304 struct sam_passwd *pwd = NULL;
307 DEBUG(10, ("getsam21pwrid: search by rid: %x\n", rid));
309 /* Open the sam password file - not for update. */
310 fp = startsampwent(False);
314 DEBUG(0, ("getsam21pwrid: unable to open sam password database.\n"));
318 while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid);
322 DEBUG(10, ("getsam21pwrid: found by smb_userid: %x\n", rid));
330 /**********************************************************
331 **********************************************************
333 utility routines which are likely to be useful to all password
336 **********************************************************
337 **********************************************************/
339 /**********************************************************
340 Encode the account control bits into a string.
341 **********************************************************/
342 char *encode_acct_ctrl(uint16 acct_ctrl)
344 static fstring acct_str;
349 if (acct_ctrl & ACB_HOMDIRREQ) *p++ = 'H';
350 if (acct_ctrl & ACB_TEMPDUP ) *p++ = 'T';
351 if (acct_ctrl & ACB_NORMAL ) *p++ = 'U';
352 if (acct_ctrl & ACB_MNS ) *p++ = 'M';
353 if (acct_ctrl & ACB_WSTRUST ) *p++ = 'W';
354 if (acct_ctrl & ACB_SVRTRUST ) *p++ = 'S';
355 if (acct_ctrl & ACB_AUTOLOCK ) *p++ = 'L';
356 if (acct_ctrl & ACB_PWNOEXP ) *p++ = 'X';
357 if (acct_ctrl & ACB_DOMTRUST ) *p++ = 'I';
364 /**********************************************************
365 Decode the account control bits from a string.
367 this function breaks coding standards minimum line width of 80 chars.
368 reason: vertical line-up code clarity - all case statements fit into
369 15 lines, which is more important.
370 **********************************************************/
371 uint16 decode_acct_ctrl(char *p)
373 uint16 acct_ctrl = 0;
374 BOOL finished = False;
377 * Check if the account type bits have been encoded after the
378 * NT password (in the form [NDHTUWSLXI]).
381 if (*p != '[') return 0;
383 for (p++; *p && !finished; p++)
389 * Hmmm. Don't allow these to be set/read independently
390 * of the actual password fields. We don't want a mismatch.
393 case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
394 case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
396 case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
397 case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
398 case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
399 case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
400 case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
401 case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
402 case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
403 case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
404 case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
410 default: { finished = True; }
417 /*************************************************************
418 Routine to get the next 32 hex characters and turn them
419 into a 16 byte array.
420 **************************************************************/
421 int gethexpwd(char *p, char *pwd)
424 unsigned char lonybble, hinybble;
425 char *hexchars = "0123456789ABCDEF";
428 for (i = 0; i < 32; i += 2) {
429 hinybble = toupper(p[i]);
430 lonybble = toupper(p[i + 1]);
432 p1 = strchr(hexchars, hinybble);
433 p2 = strchr(hexchars, lonybble);
436 hinybble = PTR_DIFF(p1, hexchars);
437 lonybble = PTR_DIFF(p2, hexchars);
439 pwd[i / 2] = (hinybble << 4) | lonybble;
444 /*******************************************************************
445 Group and User RID username mapping function
446 ********************************************************************/
447 BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
449 struct passwd *pw = Get_Pwnam(user_name, False);
451 if (u_rid == NULL || g_rid == NULL || user_name == NULL)
458 DEBUG(1,("Username %s is invalid on this system\n", user_name));
462 if (user_in_list(user_name, lp_domain_guest_users()))
464 *u_rid = DOMAIN_USER_RID_GUEST;
466 else if (user_in_list(user_name, lp_domain_admin_users()))
468 *u_rid = DOMAIN_USER_RID_ADMIN;
472 /* turn the unix UID into a Domain RID. this is what the posix
473 sub-system does (adds 1000 to the uid) */
474 *u_rid = uid_to_user_rid(pw->pw_uid);
477 /* absolutely no idea what to do about the unix GID to Domain RID mapping */
478 *g_rid = gid_to_group_rid(pw->pw_gid);
483 /****************************************************************************
484 Read the machine SID from a file.
485 ****************************************************************************/
487 static BOOL read_sid_from_file(int fd, char *sid_file)
491 if(read(fd, &fline, sizeof(fline) -1 ) < 0) {
492 DEBUG(0,("read_sid_from_file: unable to read file %s. Error was %s\n",
493 sid_file, strerror(errno) ));
498 * Convert to the machine SID.
501 fline[sizeof(fline)-1] = '\0';
502 if(!string_to_sid( &global_machine_sid, fline)) {
503 DEBUG(0,("read_sid_from_file: unable to generate machine SID.\n"));
510 /****************************************************************************
511 Generate the global machine sid. Look for the MACHINE.SID file first, if
512 not found then look in smb.conf and use it to create the MACHINE.SID file.
513 ****************************************************************************/
515 BOOL generate_machine_sid(void)
522 uchar raw_sid_data[12];
524 pstrcpy(sid_file, lp_smb_passwd_file());
525 p = strrchr(sid_file, '/');
529 pstrcat(sid_file, "MACHINE.SID");
531 if((fd = open( sid_file, O_RDWR | O_CREAT, 0644)) < 0 ) {
532 DEBUG(0,("generate_machine_sid: unable to open or create file %s. Error was %s\n",
533 sid_file, strerror(errno) ));
538 * Check if the file contains data.
541 if(fstat( fd, &st) < 0) {
542 DEBUG(0,("generate_machine_sid: unable to stat file %s. Error was %s\n",
543 sid_file, strerror(errno) ));
550 * We have a valid SID - read it.
552 if(!read_sid_from_file( fd, sid_file)) {
553 DEBUG(0,("generate_machine_sid: unable to read file %s. Error was %s\n",
554 sid_file, strerror(errno) ));
563 * The file contains no data - we may need to generate our
564 * own sid. Try the lp_domain_sid() first.
568 fstrcpy( sid_string, lp_domain_sid());
571 * Generate the new sid data & turn it into a string.
574 generate_random_buffer( raw_sid_data, 12, True);
576 fstrcpy( sid_string, "S-1-5-21");
577 for( i = 0; i < 3; i++) {
579 slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
580 fstrcat( sid_string, tmp_string);
584 fstrcat(sid_string, "\n");
587 * Ensure our new SID is valid.
590 if(!string_to_sid( &global_machine_sid, sid_string)) {
591 DEBUG(0,("generate_machine_sid: unable to generate machine SID.\n"));
596 * Do an exclusive blocking lock on the file.
599 if(!do_file_lock( fd, 60, F_WRLCK)) {
600 DEBUG(0,("generate_machine_sid: unable to lock file %s. Error was %s\n",
601 sid_file, strerror(errno) ));
607 * At this point we have a blocking lock on the SID
608 * file - check if in the meantime someone else wrote
609 * SID data into the file. If so - they were here first,
613 if(fstat( fd, &st) < 0) {
614 DEBUG(0,("generate_machine_sid: unable to stat file %s. Error was %s\n",
615 sid_file, strerror(errno) ));
622 * Unlock as soon as possible to reduce
623 * contention on the exclusive lock.
625 do_file_lock( fd, 60, F_UNLCK);
628 * We have a valid SID - read it.
631 if(!read_sid_from_file( fd, sid_file)) {
632 DEBUG(0,("generate_machine_sid: unable to read file %s. Error was %s\n",
633 sid_file, strerror(errno) ));
642 * The file is still empty and we have an exlusive lock on it.
643 * Write out out SID data into the file.
646 if(fchmod(fd, 0644) < 0) {
647 DEBUG(0,("generate_machine_sid: unable to set correct permissions on file %s. \
648 Error was %s\n", sid_file, strerror(errno) ));
653 if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
654 DEBUG(0,("generate_machine_sid: unable to write file %s. Error was %s\n",
655 sid_file, strerror(errno) ));
664 do_file_lock( fd, 60, F_UNLCK);
669 /*******************************************************************
670 XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
673 converts NT User RID to a UNIX uid.
674 ********************************************************************/
675 uid_t user_rid_to_uid(uint32 u_rid)
677 return (uid_t)(u_rid - 1000);
680 /*******************************************************************
681 XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
684 converts NT Group RID to a UNIX uid.
685 ********************************************************************/
686 uid_t group_rid_to_uid(uint32 u_gid)
688 return (uid_t)(u_gid - 1000);
691 /*******************************************************************
692 XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
695 converts UNIX uid to an NT User RID.
696 ********************************************************************/
697 uint32 uid_to_user_rid(uint32 uid)
699 return (uint32)(uid + 1000);
702 /*******************************************************************
703 XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
706 converts NT Group RID to a UNIX uid.
707 ********************************************************************/
708 uint32 gid_to_group_rid(uint32 gid)
710 return (uint32)(gid + 1000);