passdb/pdb_smbpasswd.c

説明を見る。
00001 /*
00002  * Unix SMB/CIFS implementation. 
00003  * SMB parameters and setup
00004  * Copyright (C) Andrew Tridgell       1992-1998 
00005  * Modified by Jeremy Allison          1995.
00006  * Modified by Gerald (Jerry) Carter   2000-2001,2003
00007  * Modified by Andrew Bartlett         2002.
00008  * 
00009  * This program is free software; you can redistribute it and/or modify it under
00010  * the terms of the GNU General Public License as published by the Free
00011  * Software Foundation; either version 2 of the License, or (at your option)
00012  * any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful, but WITHOUT
00015  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00017  * more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License along with
00020  * this program; if not, write to the Free Software Foundation, Inc., 675
00021  * Mass Ave, Cambridge, MA 02139, USA.
00022  */
00023 
00024 #include "includes.h"
00025 
00026 #undef DBGC_CLASS
00027 #define DBGC_CLASS DBGC_PASSDB
00028 
00029 /* 
00030    smb_passwd is analogous to sam_passwd used everywhere
00031    else.  However, smb_passwd is limited to the information
00032    stored by an smbpasswd entry 
00033  */
00034  
00035 struct smb_passwd
00036 {
00037         uint32 smb_userid;        /* this is actually the unix uid_t */
00038         const char *smb_name;     /* username string */
00039 
00040         const unsigned char *smb_passwd;    /* Null if no password */
00041         const unsigned char *smb_nt_passwd; /* Null if no password */
00042 
00043         uint16 acct_ctrl;             /* account info (ACB_xxxx bit-mask) */
00044         time_t pass_last_set_time;    /* password last set time */
00045 };
00046 
00047 struct smbpasswd_privates
00048 {
00049         /* used for maintain locks on the smbpasswd file */
00050         int     pw_file_lock_depth;
00051         
00052         /* Global File pointer */
00053         FILE    *pw_file;
00054         
00055         /* formerly static variables */
00056         struct smb_passwd pw_buf;
00057         pstring  user_name;
00058         unsigned char smbpwd[16];
00059         unsigned char smbntpwd[16];
00060 
00061         /* retrive-once info */
00062         const char *smbpasswd_file;
00063 };
00064 
00065 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
00066 
00067 static SIG_ATOMIC_T gotalarm;
00068 
00069 /***************************************************************
00070  Signal function to tell us we timed out.
00071 ****************************************************************/
00072 
00073 static void gotalarm_sig(void)
00074 {
00075         gotalarm = 1;
00076 }
00077 
00078 /***************************************************************
00079  Lock or unlock a fd for a known lock type. Abandon after waitsecs 
00080  seconds.
00081 ****************************************************************/
00082 
00083 static BOOL do_file_lock(int fd, int waitsecs, int type)
00084 {
00085         SMB_STRUCT_FLOCK lock;
00086         int             ret;
00087         void (*oldsig_handler)(int);
00088 
00089         gotalarm = 0;
00090         oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
00091 
00092         lock.l_type = type;
00093         lock.l_whence = SEEK_SET;
00094         lock.l_start = 0;
00095         lock.l_len = 1;
00096         lock.l_pid = 0;
00097 
00098         alarm(waitsecs);
00099         /* Note we must *NOT* use sys_fcntl here ! JRA */
00100         ret = fcntl(fd, SMB_F_SETLKW, &lock);
00101         alarm(0);
00102         CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler);
00103 
00104         if (gotalarm) {
00105                 DEBUG(0, ("do_file_lock: failed to %s file.\n",
00106                         type == F_UNLCK ? "unlock" : "lock"));
00107                 return False;
00108         }
00109 
00110         return (ret == 0);
00111 }
00112 
00113 /***************************************************************
00114  Lock an fd. Abandon after waitsecs seconds.
00115 ****************************************************************/
00116 
00117 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
00118 {
00119         if (fd < 0) {
00120                 return False;
00121         }
00122 
00123         if(*plock_depth == 0) {
00124                 if (!do_file_lock(fd, secs, type)) {
00125                         DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
00126                                 strerror(errno)));
00127                         return False;
00128                 }
00129         }
00130 
00131         (*plock_depth)++;
00132 
00133         return True;
00134 }
00135 
00136 /***************************************************************
00137  Unlock an fd. Abandon after waitsecs seconds.
00138 ****************************************************************/
00139 
00140 static BOOL pw_file_unlock(int fd, int *plock_depth)
00141 {
00142         BOOL ret=True;
00143 
00144         if (fd == 0 || *plock_depth == 0) {
00145                 return True;
00146         }
00147 
00148         if(*plock_depth == 1) {
00149                 ret = do_file_lock(fd, 5, F_UNLCK);
00150         }
00151 
00152         if (*plock_depth > 0) {
00153                 (*plock_depth)--;
00154         }
00155 
00156         if(!ret) {
00157                 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
00158                         strerror(errno)));
00159         }
00160         return ret;
00161 }
00162 
00163 /**************************************************************
00164  Intialize a smb_passwd struct
00165  *************************************************************/
00166 
00167 static void pdb_init_smb(struct smb_passwd *user)
00168 {
00169         if (user == NULL) 
00170                 return;
00171         ZERO_STRUCTP (user);
00172         
00173         user->pass_last_set_time = (time_t)0;
00174 }
00175 
00176 /***************************************************************
00177  Internal fn to enumerate the smbpasswd list. Returns a void pointer
00178  to ensure no modification outside this module. Checks for atomic
00179  rename of smbpasswd file on update or create once the lock has
00180  been granted to prevent race conditions. JRA.
00181 ****************************************************************/
00182 
00183 static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
00184 {
00185         FILE *fp = NULL;
00186         const char *open_mode = NULL;
00187         int race_loop = 0;
00188         int lock_type = F_RDLCK;
00189 
00190         if (!*pfile) {
00191                 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
00192                 return (NULL);
00193         }
00194 
00195         switch(type) {
00196                 case PWF_READ:
00197                         open_mode = "rb";
00198                         lock_type = F_RDLCK;
00199                         break;
00200                 case PWF_UPDATE:
00201                         open_mode = "r+b";
00202                         lock_type = F_WRLCK;
00203                         break;
00204                 case PWF_CREATE:
00205                         /*
00206                          * Ensure atomic file creation.
00207                          */
00208                         {
00209                                 int i, fd = -1;
00210 
00211                                 for(i = 0; i < 5; i++) {
00212                                         if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) {
00213                                                 break;
00214                                         }
00215                                         sys_usleep(200); /* Spin, spin... */
00216                                 }
00217                                 if(fd == -1) {
00218                                         DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
00219 creating file %s\n", pfile));
00220                                         return NULL;
00221                                 }
00222                                 close(fd);
00223                                 open_mode = "r+b";
00224                                 lock_type = F_WRLCK;
00225                                 break;
00226                         }
00227         }
00228                        
00229         for(race_loop = 0; race_loop < 5; race_loop++) {
00230                 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
00231 
00232                 if((fp = sys_fopen(pfile, open_mode)) == NULL) {
00233 
00234                         /*
00235                          * If smbpasswd file doesn't exist, then create new one. This helps to avoid
00236                          * confusing error msg when adding user account first time.
00237                          */
00238                         if (errno == ENOENT) {
00239                                 if ((fp = sys_fopen(pfile, "a+")) != NULL) {
00240                                         DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
00241 exist. File successfully created.\n", pfile));
00242                                 } else {
00243                                         DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
00244 exist. Couldn't create new one. Error was: %s",
00245                                         pfile, strerror(errno)));
00246                                         return NULL;
00247                                 }
00248                         } else {
00249                                 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
00250 Error was: %s\n", pfile, strerror(errno)));
00251                                 return NULL;
00252                         }
00253                 }
00254 
00255                 if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
00256                         DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
00257 Error was %s\n", pfile, strerror(errno) ));
00258                         fclose(fp);
00259                         return NULL;
00260                 }
00261 
00262                 /*
00263                  * Only check for replacement races on update or create.
00264                  * For read we don't mind if the data is one record out of date.
00265                  */
00266 
00267                 if(type == PWF_READ) {
00268                         break;
00269                 } else {
00270                         SMB_STRUCT_STAT sbuf1, sbuf2;
00271 
00272                         /*
00273                          * Avoid the potential race condition between the open and the lock
00274                          * by doing a stat on the filename and an fstat on the fd. If the
00275                          * two inodes differ then someone did a rename between the open and
00276                          * the lock. Back off and try the open again. Only do this 5 times to
00277                          * prevent infinate loops. JRA.
00278                          */
00279 
00280                         if (sys_stat(pfile,&sbuf1) != 0) {
00281                                 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
00282 Error was %s\n", pfile, strerror(errno)));
00283                                 pw_file_unlock(fileno(fp), lock_depth);
00284                                 fclose(fp);
00285                                 return NULL;
00286                         }
00287 
00288                         if (sys_fstat(fileno(fp),&sbuf2) != 0) {
00289                                 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
00290 Error was %s\n", pfile, strerror(errno)));
00291                                 pw_file_unlock(fileno(fp), lock_depth);
00292                                 fclose(fp);
00293                                 return NULL;
00294                         }
00295 
00296                         if( sbuf1.st_ino == sbuf2.st_ino) {
00297                                 /* No race. */
00298                                 break;
00299                         }
00300 
00301                         /*
00302                          * Race occurred - back off and try again...
00303                          */
00304 
00305                         pw_file_unlock(fileno(fp), lock_depth);
00306                         fclose(fp);
00307                 }
00308         }
00309 
00310         if(race_loop == 5) {
00311                 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
00312                 return NULL;
00313         }
00314 
00315         /* Set a buffer to do more efficient reads */
00316         setvbuf(fp, (char *)NULL, _IOFBF, 1024);
00317 
00318         /* Make sure it is only rw by the owner */
00319 #ifdef HAVE_FCHMOD
00320         if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
00321 #else
00322         if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) {
00323 #endif
00324                 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
00325 Error was %s\n.", pfile, strerror(errno) ));
00326                 pw_file_unlock(fileno(fp), lock_depth);
00327                 fclose(fp);
00328                 return NULL;
00329         }
00330 
00331         /* We have a lock on the file. */
00332         return fp;
00333 }
00334 
00335 /***************************************************************
00336  End enumeration of the smbpasswd list.
00337 ****************************************************************/
00338 
00339 static void endsmbfilepwent(FILE *fp, int *lock_depth)
00340 {
00341         if (!fp) {
00342                 return;
00343         }
00344 
00345         pw_file_unlock(fileno(fp), lock_depth);
00346         fclose(fp);
00347         DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
00348 }
00349 
00350 /*************************************************************************
00351  Routine to return the next entry in the smbpasswd list.
00352  *************************************************************************/
00353 
00354 static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
00355 {
00356         /* Static buffers we will return. */
00357         struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
00358         char  *user_name = smbpasswd_state->user_name;
00359         unsigned char *smbpwd = smbpasswd_state->smbpwd;
00360         unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
00361         char linebuf[256];
00362         int c;
00363         unsigned char *p;
00364         long uidval;
00365         size_t linebuf_len;
00366         char *status;
00367 
00368         if(fp == NULL) {
00369                 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
00370                 return NULL;
00371         }
00372 
00373         pdb_init_smb(pw_buf);
00374         pw_buf->acct_ctrl = ACB_NORMAL;  
00375 
00376         /*
00377          * Scan the file, a line at a time and check if the name matches.
00378          */
00379         status = linebuf;
00380         while (status && !feof(fp)) {
00381                 linebuf[0] = '\0';
00382 
00383                 status = fgets(linebuf, 256, fp);
00384                 if (status == NULL && ferror(fp)) {
00385                         return NULL;
00386                 }
00387 
00388                 /*
00389                  * Check if the string is terminated with a newline - if not
00390                  * then we must keep reading and discard until we get one.
00391                  */
00392                 if ((linebuf_len = strlen(linebuf)) == 0) {
00393                         continue;
00394                 }
00395 
00396                 if (linebuf[linebuf_len - 1] != '\n') {
00397                         c = '\0';
00398                         while (!ferror(fp) && !feof(fp)) {
00399                                 c = fgetc(fp);
00400                                 if (c == '\n') {
00401                                         break;
00402                                 }
00403                         }
00404                 } else {
00405                         linebuf[linebuf_len - 1] = '\0';
00406                 }
00407 
00408 #ifdef DEBUG_PASSWORD
00409                 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
00410 #endif
00411                 if ((linebuf[0] == 0) && feof(fp)) {
00412                         DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
00413                         break;
00414                 }
00415 
00416                 /*
00417                  * The line we have should be of the form :-
00418                  * 
00419                  * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
00420                  * ignored....
00421                  * 
00422                  * or,
00423                  *
00424                  * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
00425                  *
00426                  * if Windows NT compatible passwords are also present.
00427                  * [Account type] is an ascii encoding of the type of account.
00428                  * LCT-(8 hex digits) is the time_t value of the last change time.
00429                  */
00430 
00431                 if (linebuf[0] == '#' || linebuf[0] == '\0') {
00432                         DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
00433                         continue;
00434                 }
00435                 p = (unsigned char *) strchr_m(linebuf, ':');
00436                 if (p == NULL) {
00437                         DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
00438                         continue;
00439                 }
00440 
00441                 /*
00442                  * As 256 is shorter than a pstring we don't need to check
00443                  * length here - if this ever changes....
00444                  */
00445                 SMB_ASSERT(sizeof(pstring) > sizeof(linebuf));
00446 
00447                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
00448                 user_name[PTR_DIFF(p, linebuf)] = '\0';
00449 
00450                 /* Get smb uid. */
00451 
00452                 p++; /* Go past ':' */
00453 
00454                 if(*p == '-') {
00455                         DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name));
00456                         continue;
00457                 }
00458 
00459                 if (!isdigit(*p)) {
00460                         DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
00461                                 user_name));
00462                         continue;
00463                 }
00464 
00465                 uidval = atoi((char *) p);
00466 
00467                 while (*p && isdigit(*p)) {
00468                         p++;
00469                 }
00470 
00471                 if (*p != ':') {
00472                         DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
00473                                 user_name));
00474                         continue;
00475                 }
00476 
00477                 pw_buf->smb_name = user_name;
00478                 pw_buf->smb_userid = uidval;
00479 
00480                 /*
00481                  * Now get the password value - this should be 32 hex digits
00482                  * which are the ascii representations of a 16 byte string.
00483                  * Get two at a time and put them into the password.
00484                  */
00485 
00486                 /* Skip the ':' */
00487                 p++;
00488 
00489                 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
00490                         DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
00491                                 user_name ));
00492                         continue;
00493                 }
00494 
00495                 if (p[32] != ':') {
00496                         DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
00497                                 user_name));
00498                         continue;
00499                 }
00500 
00501                 if (strnequal((char *) p, "NO PASSWORD", 11)) {
00502                         pw_buf->smb_passwd = NULL;
00503                         pw_buf->acct_ctrl |= ACB_PWNOTREQ;
00504                 } else {
00505                         if (*p == '*' || *p == 'X') {
00506                                 /* NULL LM password */
00507                                 pw_buf->smb_passwd = NULL;
00508                                 DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
00509                         } else if (pdb_gethexpwd((char *)p, smbpwd)) {
00510                                 pw_buf->smb_passwd = smbpwd;
00511                         } else {
00512                                 pw_buf->smb_passwd = NULL;
00513                                 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
00514 (non hex chars)\n", user_name));
00515                         }
00516                 }
00517 
00518                 /* 
00519                  * Now check if the NT compatible password is
00520                  * available.
00521                  */
00522                 pw_buf->smb_nt_passwd = NULL;
00523                 p += 33; /* Move to the first character of the line after the lanman password. */
00524                 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
00525                         if (*p != '*' && *p != 'X') {
00526                                 if(pdb_gethexpwd((char *)p,smbntpwd)) {
00527                                         pw_buf->smb_nt_passwd = smbntpwd;
00528                                 }
00529                         }
00530                         p += 33; /* Move to the first character of the line after the NT password. */
00531                 }
00532 
00533                 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
00534                         user_name, uidval));
00535 
00536                 if (*p == '[') {
00537                         unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
00538                         pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
00539 
00540                         /* Must have some account type set. */
00541                         if(pw_buf->acct_ctrl == 0) {
00542                                 pw_buf->acct_ctrl = ACB_NORMAL;
00543                         }
00544 
00545                         /* Now try and get the last change time. */
00546                         if(end_p) {
00547                                 p = end_p + 1;
00548                         }
00549                         if(*p == ':') {
00550                                 p++;
00551                                 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
00552                                         int i;
00553                                         p += 4;
00554                                         for(i = 0; i < 8; i++) {
00555                                                 if(p[i] == '\0' || !isxdigit(p[i])) {
00556                                                         break;
00557                                                 }
00558                                         }
00559                                         if(i == 8) {
00560                                                 /*
00561                                                  * p points at 8 characters of hex digits - 
00562                                                  * read into a time_t as the seconds since
00563                                                  * 1970 that the password was last changed.
00564                                                  */
00565                                                 pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
00566                                         }
00567                                 }
00568                         }
00569                 } else {
00570                         /* 'Old' style file. Fake up based on user name. */
00571                         /*
00572                          * Currently trust accounts are kept in the same
00573                          * password file as 'normal accounts'. If this changes
00574                          * we will have to fix this code. JRA.
00575                          */
00576                         if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
00577                                 pw_buf->acct_ctrl &= ~ACB_NORMAL;
00578                                 pw_buf->acct_ctrl |= ACB_WSTRUST;
00579                         }
00580                 }
00581 
00582                 return pw_buf;
00583         }
00584 
00585         DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
00586         return NULL;
00587 }
00588 
00589 /************************************************************************
00590  Create a new smbpasswd entry - malloced space returned.
00591 *************************************************************************/
00592 
00593 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
00594 {
00595         int new_entry_length;
00596         char *new_entry;
00597         char *p;
00598 
00599         new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 
00600                                 NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
00601 
00602         if((new_entry = (char *)SMB_MALLOC( new_entry_length )) == NULL) {
00603                 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
00604                         newpwd->smb_name ));
00605                 return NULL;
00606         }
00607 
00608         slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
00609 
00610         p = new_entry+strlen(new_entry);
00611         pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
00612         p+=strlen(p);
00613         *p = ':';
00614         p++;
00615 
00616         pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
00617         p+=strlen(p);
00618         *p = ':';
00619         p++;
00620 
00621         /* Add the account encoding and the last change time. */
00622         slprintf((char *)p, new_entry_length - 1 - (p - new_entry),  "%s:LCT-%08X:\n",
00623                 pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
00624                 (uint32)newpwd->pass_last_set_time);
00625 
00626         return new_entry;
00627 }
00628 
00629 /************************************************************************
00630  Routine to add an entry to the smbpasswd file.
00631 *************************************************************************/
00632 
00633 static NTSTATUS add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state,
00634                                      struct smb_passwd *newpwd)
00635 {
00636         const char *pfile = smbpasswd_state->smbpasswd_file;
00637         struct smb_passwd *pwd = NULL;
00638         FILE *fp = NULL;
00639         int wr_len;
00640         int fd;
00641         size_t new_entry_length;
00642         char *new_entry;
00643         SMB_OFF_T offpos;
00644  
00645         /* Open the smbpassword file - for update. */
00646         fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth);
00647 
00648         if (fp == NULL && errno == ENOENT) {
00649                 /* Try again - create. */
00650                 fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth);
00651         }
00652 
00653         if (fp == NULL) {
00654                 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
00655                 return map_nt_error_from_unix(errno);
00656         }
00657 
00658         /*
00659          * Scan the file, a line at a time and check if the name matches.
00660          */
00661 
00662         while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
00663                 if (strequal(newpwd->smb_name, pwd->smb_name)) {
00664                         DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
00665                         endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
00666                         return NT_STATUS_USER_EXISTS;
00667                 }
00668         }
00669 
00670         /* Ok - entry doesn't exist. We can add it */
00671 
00672         /* Create a new smb passwd entry and set it to the given password. */
00673         /* 
00674          * The add user write needs to be atomic - so get the fd from 
00675          * the fp and do a raw write() call.
00676          */
00677         fd = fileno(fp);
00678 
00679         if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) {
00680                 NTSTATUS result = map_nt_error_from_unix(errno);
00681                 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
00682 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
00683                 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
00684                 return result;
00685         }
00686 
00687         if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) {
00688                 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
00689 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
00690                 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
00691                 return NT_STATUS_NO_MEMORY;
00692         }
00693 
00694         new_entry_length = strlen(new_entry);
00695 
00696 #ifdef DEBUG_PASSWORD
00697         DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", 
00698                         fd, (int)new_entry_length, new_entry));
00699 #endif
00700 
00701         if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) {
00702                 NTSTATUS result = map_nt_error_from_unix(errno);
00703                 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
00704 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
00705 
00706                 /* Remove the entry we just wrote. */
00707                 if(sys_ftruncate(fd, offpos) == -1) {
00708                         DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
00709 Error was %s. Password file may be corrupt ! Please examine by hand !\n", 
00710                                 newpwd->smb_name, strerror(errno)));
00711                 }
00712 
00713                 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
00714                 free(new_entry);
00715                 return result;
00716         }
00717 
00718         free(new_entry);
00719         endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
00720         return NT_STATUS_OK;
00721 }
00722 
00723 /************************************************************************
00724  Routine to search the smbpasswd file for an entry matching the username.
00725  and then modify its password entry. We can't use the startsmbpwent()/
00726  getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
00727  in the actual file to decide how much room we have to write data.
00728  override = False, normal
00729  override = True, override XXXXXXXX'd out password or NO PASS
00730 ************************************************************************/
00731 
00732 static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
00733 {
00734         /* Static buffers we will return. */
00735         pstring user_name;
00736 
00737         char *status;
00738         char linebuf[256];
00739         char readbuf[1024];
00740         int c;
00741         fstring ascii_p16;
00742         fstring encode_bits;
00743         unsigned char *p = NULL;
00744         size_t linebuf_len = 0;
00745         FILE *fp;
00746         int lockfd;
00747         const char *pfile = smbpasswd_state->smbpasswd_file;
00748         BOOL found_entry = False;
00749         BOOL got_pass_last_set_time = False;
00750 
00751         SMB_OFF_T pwd_seekpos = 0;
00752 
00753         int i;
00754         int wr_len;
00755         int fd;
00756 
00757         if (!*pfile) {
00758                 DEBUG(0, ("No SMB password file set\n"));
00759                 return False;
00760         }
00761         DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
00762 
00763         fp = sys_fopen(pfile, "r+");
00764 
00765         if (fp == NULL) {
00766                 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
00767                 return False;
00768         }
00769         /* Set a buffer to do more efficient reads */
00770         setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
00771 
00772         lockfd = fileno(fp);
00773 
00774         if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) {
00775                 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
00776                 fclose(fp);
00777                 return False;
00778         }
00779 
00780         /* Make sure it is only rw by the owner */
00781         chmod(pfile, 0600);
00782 
00783         /* We have a write lock on the file. */
00784         /*
00785          * Scan the file, a line at a time and check if the name matches.
00786          */
00787         status = linebuf;
00788         while (status && !feof(fp)) {
00789                 pwd_seekpos = sys_ftell(fp);
00790 
00791                 linebuf[0] = '\0';
00792 
00793                 status = fgets(linebuf, sizeof(linebuf), fp);
00794                 if (status == NULL && ferror(fp)) {
00795                         pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
00796                         fclose(fp);
00797                         return False;
00798                 }
00799 
00800                 /*
00801                  * Check if the string is terminated with a newline - if not
00802                  * then we must keep reading and discard until we get one.
00803                  */
00804                 linebuf_len = strlen(linebuf);
00805                 if (linebuf[linebuf_len - 1] != '\n') {
00806                         c = '\0';
00807                         while (!ferror(fp) && !feof(fp)) {
00808                                 c = fgetc(fp);
00809                                 if (c == '\n') {
00810                                         break;
00811                                 }
00812                         }
00813                 } else {
00814                         linebuf[linebuf_len - 1] = '\0';
00815                 }
00816 
00817 #ifdef DEBUG_PASSWORD
00818                 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
00819 #endif
00820 
00821                 if ((linebuf[0] == 0) && feof(fp)) {
00822                         DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
00823                         break;
00824                 }
00825 
00826                 /*
00827                  * The line we have should be of the form :-
00828                  * 
00829                  * username:uid:[32hex bytes]:....other flags presently
00830                  * ignored....
00831                  * 
00832                  * or,
00833                  *
00834                  * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
00835                  *
00836                  * if Windows NT compatible passwords are also present.
00837                  */
00838 
00839                 if (linebuf[0] == '#' || linebuf[0] == '\0') {
00840                         DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
00841                         continue;
00842                 }
00843 
00844                 p = (unsigned char *) strchr_m(linebuf, ':');
00845 
00846                 if (p == NULL) {
00847                         DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
00848                         continue;
00849                 }
00850 
00851                 /*
00852                  * As 256 is shorter than a pstring we don't need to check
00853                  * length here - if this ever changes....
00854                  */
00855 
00856                 SMB_ASSERT(sizeof(user_name) > sizeof(linebuf));
00857 
00858                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
00859                 user_name[PTR_DIFF(p, linebuf)] = '\0';
00860                 if (strequal(user_name, pwd->smb_name)) {
00861                         found_entry = True;
00862                         break;
00863                 }
00864         }
00865 
00866         if (!found_entry) {
00867                 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
00868                 fclose(fp);
00869 
00870                 DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
00871                         pwd->smb_name));
00872                 return False;
00873         }
00874 
00875         DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name));
00876 
00877         /* User name matches - get uid and password */
00878         p++; /* Go past ':' */
00879 
00880         if (!isdigit(*p)) {
00881                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
00882                         pwd->smb_name));
00883                 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
00884                 fclose(fp);
00885                 return False;
00886         }
00887 
00888         while (*p && isdigit(*p)) {
00889                 p++;
00890         }
00891         if (*p != ':') {
00892                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
00893                         pwd->smb_name));
00894                 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
00895                 fclose(fp);
00896                 return False;
00897         }
00898 
00899         /*
00900          * Now get the password value - this should be 32 hex digits
00901          * which are the ascii representations of a 16 byte string.
00902          * Get two at a time and put them into the password.
00903          */
00904         p++;
00905 
00906         /* Record exact password position */
00907         pwd_seekpos += PTR_DIFF(p, linebuf);
00908 
00909         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
00910                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
00911                         pwd->smb_name));
00912                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
00913                 fclose(fp);
00914                 return (False);
00915         }
00916 
00917         if (p[32] != ':') {
00918                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
00919                         pwd->smb_name));
00920                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
00921                 fclose(fp);
00922                 return False;
00923         }
00924 
00925         /* Now check if the NT compatible password is available. */
00926         p += 33; /* Move to the first character of the line after the lanman password. */
00927         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
00928                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
00929                         pwd->smb_name));
00930                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
00931                 fclose(fp);
00932                 return (False);
00933         }
00934 
00935         if (p[32] != ':') {
00936                 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
00937                         pwd->smb_name));
00938                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
00939                 fclose(fp);
00940                 return False;
00941         }
00942 
00943         /* 
00944          * Now check if the account info and the password last
00945          * change time is available.
00946          */
00947         p += 33; /* Move to the first character of the line after the NT password. */
00948 
00949         if (*p == '[') {
00950                 i = 0;
00951                 encode_bits[i++] = *p++;
00952                 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) {
00953                         encode_bits[i++] = *p++;
00954                 }
00955 
00956                 encode_bits[i++] = ']';
00957                 encode_bits[i++] = '\0';
00958 
00959                 if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
00960                         /*
00961                          * We are using a new format, space padded
00962                          * acct ctrl field. Encode the given acct ctrl
00963                          * bits into it.
00964                          */
00965                         fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
00966                 } else {
00967                         DEBUG(0,("mod_smbfilepwd_entry:  Using old smbpasswd format for user %s. \
00968 This is no longer supported.!\n", pwd->smb_name));
00969                         DEBUG(0,("mod_smbfilepwd_entry:  No changes made, failing.!\n"));
00970                         pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
00971                         fclose(fp);
00972                         return False;
00973                 }
00974 
00975                 /* Go past the ']' */
00976                 if(linebuf_len > PTR_DIFF(p, linebuf)) {
00977                         p++;
00978                 }
00979 
00980                 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
00981                         p++;
00982 
00983                         /* We should be pointing at the LCT entry. */
00984                         if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
00985                                 p += 4;
00986                                 for(i = 0; i < 8; i++) {
00987                                         if(p[i] == '\0' || !isxdigit(p[i])) {
00988                                                 break;
00989                                         }
00990                                 }
00991                                 if(i == 8) {
00992                                         /*
00993                                          * p points at 8 characters of hex digits -
00994                                          * read into a time_t as the seconds since
00995                                          * 1970 that the password was last changed.
00996                                          */
00997                                         got_pass_last_set_time = True;
00998                                 } /* i == 8 */
00999                         } /* *p && StrnCaseCmp() */
01000                 } /* p == ':' */
01001         } /* p == '[' */
01002 
01003         /* Entry is correctly formed. */
01004 
01005         /* Create the 32 byte representation of the new p16 */
01006         pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
01007 
01008         /* Add on the NT md4 hash */
01009         ascii_p16[32] = ':';
01010         wr_len = 66;
01011         pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
01012         ascii_p16[65] = ':';
01013         ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
01014 
01015         /* Add on the account info bits and the time of last password change. */
01016         if(got_pass_last_set_time) {
01017                 slprintf(&ascii_p16[strlen(ascii_p16)], 
01018                         sizeof(ascii_p16)-(strlen(ascii_p16)+1),
01019                         "%s:LCT-%08X:", 
01020                         encode_bits, (uint32)pwd->pass_last_set_time );
01021                 wr_len = strlen(ascii_p16);
01022         }
01023 
01024 #ifdef DEBUG_PASSWORD
01025         DEBUG(100,("mod_smbfilepwd_entry: "));
01026         dump_data(100, ascii_p16, wr_len);
01027 #endif
01028 
01029         if(wr_len > sizeof(linebuf)) {
01030                 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
01031                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01032                 fclose(fp);
01033                 return (False);
01034         }
01035 
01036         /*
01037          * Do an atomic write into the file at the position defined by
01038          * seekpos.
01039          */
01040 
01041         /* The mod user write needs to be atomic - so get the fd from 
01042                 the fp and do a raw write() call.
01043          */
01044 
01045         fd = fileno(fp);
01046 
01047         if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
01048                 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
01049                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01050                 fclose(fp);
01051                 return False;
01052         }
01053 
01054         /* Sanity check - ensure the areas we are writing are framed by ':' */
01055         if (read(fd, linebuf, wr_len+1) != wr_len+1) {
01056                 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
01057                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01058                 fclose(fp);
01059                 return False;
01060         }
01061 
01062         if ((linebuf[0] != ':') || (linebuf[wr_len] != ':'))    {
01063                 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
01064                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01065                 fclose(fp);
01066                 return False;
01067         }
01068  
01069         if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
01070                 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
01071                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01072                 fclose(fp);
01073                 return False;
01074         }
01075 
01076         if (write(fd, ascii_p16, wr_len) != wr_len) {
01077                 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
01078                 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01079                 fclose(fp);
01080                 return False;
01081         }
01082 
01083         pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
01084         fclose(fp);
01085         return True;
01086 }
01087 
01088 /************************************************************************
01089  Routine to delete an entry in the smbpasswd file by name.
01090 *************************************************************************/
01091 
01092 static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
01093 {
01094         const char *pfile = smbpasswd_state->smbpasswd_file;
01095         pstring pfile2;
01096         struct smb_passwd *pwd = NULL;
01097         FILE *fp = NULL;
01098         FILE *fp_write = NULL;
01099         int pfile2_lockdepth = 0;
01100 
01101         slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
01102 
01103         /*
01104          * Open the smbpassword file - for update. It needs to be update
01105          * as we need any other processes to wait until we have replaced
01106          * it.
01107          */
01108 
01109         if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) {
01110                 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
01111                 return False;
01112         }
01113 
01114         /*
01115          * Create the replacement password file.
01116          */
01117         if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
01118                 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
01119                 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
01120                 return False;
01121         }
01122 
01123         /*
01124          * Scan the file, a line at a time and check if the name matches.
01125          */
01126 
01127         while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
01128                 char *new_entry;
01129                 size_t new_entry_length;
01130 
01131                 if (strequal(name, pwd->smb_name)) {
01132                         DEBUG(10, ("del_smbfilepwd_entry: found entry with "
01133                                    "name %s - deleting it.\n", name));
01134                         continue;
01135                 }
01136 
01137                 /*
01138                  * We need to copy the entry out into the second file.
01139                  */
01140 
01141                 if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) {
01142                         DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
01143 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
01144                         unlink(pfile2);
01145                         endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
01146                         endsmbfilepwent(fp_write, &pfile2_lockdepth);
01147                         return False;
01148                 }
01149 
01150                 new_entry_length = strlen(new_entry);
01151 
01152                 if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) {
01153                         DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
01154 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
01155                         unlink(pfile2);
01156                         endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
01157                         endsmbfilepwent(fp_write, &pfile2_lockdepth);
01158                         free(new_entry);
01159                         return False;
01160                 }
01161 
01162                 free(new_entry);
01163         }
01164 
01165         /*
01166          * Ensure pfile2 is flushed before rename.
01167          */
01168 
01169         if(fflush(fp_write) != 0) {
01170                 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
01171                 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
01172                 endsmbfilepwent(fp_write,&pfile2_lockdepth);
01173                 return False;
01174         }
01175 
01176         /*
01177          * Do an atomic rename - then release the locks.
01178          */
01179 
01180         if(rename(pfile2,pfile) != 0) {
01181                 unlink(pfile2);
01182         }
01183   
01184         endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
01185         endsmbfilepwent(fp_write,&pfile2_lockdepth);
01186         return True;
01187 }
01188 
01189 /*********************************************************************
01190  Create a smb_passwd struct from a struct samu.
01191  We will not allocate any new memory.  The smb_passwd struct
01192  should only stay around as long as the struct samu does.
01193  ********************************************************************/
01194 
01195 static BOOL build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
01196 {
01197         uint32 rid;
01198 
01199         if (sampass == NULL) 
01200                 return False;
01201         ZERO_STRUCTP(smb_pw);
01202 
01203         if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
01204                 rid = pdb_get_user_rid(sampass);
01205                 
01206                 /* If the user specified a RID, make sure its able to be both stored and retreived */
01207                 if (rid == DOMAIN_USER_RID_GUEST) {
01208                         struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount());
01209                         if (!passwd) {
01210                                 DEBUG(0, ("Could not find guest account via getpwnam()! (%s)\n", lp_guestaccount()));
01211                                 return False;
01212                         }
01213                         smb_pw->smb_userid=passwd->pw_uid;
01214                         TALLOC_FREE(passwd);
01215                 } else if (algorithmic_pdb_rid_is_user(rid)) {
01216                         smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
01217                 } else {
01218                         DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
01219                         return False;
01220                 }
01221         }
01222 
01223         smb_pw->smb_name=(const char*)pdb_get_username(sampass);
01224 
01225         smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
01226         smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
01227 
01228         smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
01229         smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
01230 
01231         return True;
01232 }       
01233 
01234 /*********************************************************************
01235  Create a struct samu from a smb_passwd struct
01236  ********************************************************************/
01237 
01238 static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, 
01239                               struct samu *sam_pass, const struct smb_passwd *pw_buf)
01240 {
01241         struct passwd *pwfile;
01242         
01243         if ( !sam_pass ) {
01244                 DEBUG(5,("build_sam_account: struct samu is NULL\n"));
01245                 return False;
01246         }
01247 
01248         /* verify the user account exists */
01249 
01250         if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
01251                 DEBUG(0,("build_sam_account: smbpasswd database is corrupt!  username %s with uid "
01252                 "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
01253                         return False;
01254         }
01255         
01256         if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
01257                 return False;
01258                 
01259         TALLOC_FREE(pwfile);
01260 
01261         /* set remaining fields */
01262                 
01263         pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET);
01264         pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET);                  
01265         pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
01266         pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
01267         pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
01268         
01269         return True;
01270 }
01271 
01272 /*****************************************************************
01273  Functions to be implemented by the new passdb API 
01274  ****************************************************************/
01275 
01276 static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update, uint32 acb_mask)
01277 {
01278         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01279         
01280         smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 
01281                                                        update ? PWF_UPDATE : PWF_READ, 
01282                                                        &(smbpasswd_state->pw_file_lock_depth));
01283                                    
01284         /* did we fail?  Should we try to create it? */
01285         if (!smbpasswd_state->pw_file && update && errno == ENOENT) {
01286                 FILE *fp;
01287                 /* slprintf(msg_str,msg_str_len-1,
01288                    "smbpasswd file did not exist - attempting to create it.\n"); */
01289                 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
01290                 fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w");
01291                 if (fp) {
01292                         fprintf(fp, "# Samba SMB password file\n");
01293                         fclose(fp);
01294                 }
01295                 
01296                 smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 
01297                                                              update ? PWF_UPDATE : PWF_READ, 
01298                                                              &(smbpasswd_state->pw_file_lock_depth));
01299         }
01300         
01301         if (smbpasswd_state->pw_file != NULL)
01302                 return NT_STATUS_OK;
01303         else
01304                 return NT_STATUS_UNSUCCESSFUL;  
01305 }
01306 
01307 static void smbpasswd_endsampwent (struct pdb_methods *my_methods)
01308 {
01309         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01310         endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth));
01311 }
01312  
01313 /*****************************************************************
01314  ****************************************************************/
01315 
01316 static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, struct samu *user)
01317 {
01318         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
01319         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01320         struct smb_passwd *pw_buf=NULL;
01321         BOOL done = False;
01322 
01323         DEBUG(5,("pdb_getsampwent\n"));
01324 
01325         if ( !user ) {
01326                 DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n"));
01327                 return nt_status;
01328         }
01329 
01330         while (!done) {
01331                 /* do we have an entry? */
01332                 pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file);
01333                 if (pw_buf == NULL) 
01334                         return nt_status;
01335 
01336                 /* build the struct samu entry from the smb_passwd struct. 
01337                    We loop in case the user in the pdb does not exist in 
01338                    the local system password file */
01339                 if (build_sam_account(smbpasswd_state, user, pw_buf))
01340                         done = True;
01341         }
01342 
01343         DEBUG(5,("getsampwent (smbpasswd): done\n"));
01344 
01345         /* success */
01346         return NT_STATUS_OK;
01347 }
01348 
01349 /****************************************************************
01350  Search smbpasswd file by iterating over the entries.  Do not
01351  call getpwnam() for unix account information until we have found
01352  the correct entry
01353  ***************************************************************/
01354 
01355 static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, 
01356                                   struct samu *sam_acct, const char *username)
01357 {
01358         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
01359         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01360         struct smb_passwd *smb_pw;
01361         FILE *fp = NULL;
01362 
01363         DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
01364 
01365         /* startsmbfilepwent() is used here as we don't want to lookup
01366            the UNIX account in the local system password file until
01367            we have a match.  */
01368         fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
01369 
01370         if (fp == NULL) {
01371                 DEBUG(0, ("Unable to open passdb database.\n"));
01372                 return nt_status;
01373         }
01374 
01375         while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
01376                 /* do nothing....another loop */ ;
01377         
01378         endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
01379 
01380 
01381         /* did we locate the username in smbpasswd  */
01382         if (smb_pw == NULL)
01383                 return nt_status;
01384         
01385         DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
01386 
01387         if (!sam_acct) {
01388                 DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
01389                 return nt_status;
01390         }
01391                 
01392         /* now build the struct samu */
01393         if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
01394                 return nt_status;
01395 
01396         /* success */
01397         return NT_STATUS_OK;
01398 }
01399 
01400 static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const DOM_SID *sid)
01401 {
01402         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
01403         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01404         struct smb_passwd *smb_pw;
01405         FILE *fp = NULL;
01406         fstring sid_str;
01407         uint32 rid;
01408         
01409         DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n", sid_to_string(sid_str, sid)));
01410 
01411         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
01412                 return NT_STATUS_UNSUCCESSFUL;
01413 
01414         /* More special case 'guest account' hacks... */
01415         if (rid == DOMAIN_USER_RID_GUEST) {
01416                 const char *guest_account = lp_guestaccount();
01417                 if (!(guest_account && *guest_account)) {
01418                         DEBUG(1, ("Guest account not specfied!\n"));
01419                         return nt_status;
01420                 }
01421                 return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account);
01422         }
01423 
01424         /* Open the sam password file - not for update. */
01425         fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
01426 
01427         if (fp == NULL) {
01428                 DEBUG(0, ("Unable to open passdb database.\n"));
01429                 return nt_status;
01430         }
01431 
01432         while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
01433                 /* do nothing */ ;
01434 
01435         endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
01436 
01437 
01438         /* did we locate the username in smbpasswd  */
01439         if (smb_pw == NULL)
01440                 return nt_status;
01441         
01442         DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
01443                 
01444         if (!sam_acct) {
01445                 DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
01446                 return nt_status;
01447         }
01448 
01449         /* now build the struct samu */
01450         if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
01451                 return nt_status;
01452 
01453         /* build_sam_account might change the SID on us, if the name was for the guest account */
01454         if (NT_STATUS_IS_OK(nt_status) && !sid_equal(pdb_get_user_sid(sam_acct), sid)) {
01455                 fstring sid_string1, sid_string2;
01456                 DEBUG(1, ("looking for user with sid %s instead returned %s for account %s!?!\n",
01457                           sid_to_string(sid_string1, sid), sid_to_string(sid_string2, pdb_get_user_sid(sam_acct)), pdb_get_username(sam_acct)));
01458                 return NT_STATUS_NO_SUCH_USER;
01459         }
01460 
01461         /* success */
01462         return NT_STATUS_OK;
01463 }
01464 
01465 static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
01466 {
01467         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01468         struct smb_passwd smb_pw;
01469         
01470         /* convert the struct samu */
01471         if (!build_smb_pass(&smb_pw, sampass)) {
01472                 return NT_STATUS_UNSUCCESSFUL;
01473         }
01474         
01475         /* add the entry */
01476         return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
01477 }
01478 
01479 static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
01480 {
01481         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01482         struct smb_passwd smb_pw;
01483         
01484         /* convert the struct samu */
01485         if (!build_smb_pass(&smb_pw, sampass)) {
01486                 DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
01487                 return NT_STATUS_UNSUCCESSFUL;
01488         }
01489         
01490         /* update the entry */
01491         if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
01492                 DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
01493                 return NT_STATUS_UNSUCCESSFUL;
01494         }
01495         
01496         return NT_STATUS_OK;
01497 }
01498 
01499 static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
01500 {
01501         struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
01502 
01503         const char *username = pdb_get_username(sampass);
01504 
01505         if (del_smbfilepwd_entry(smbpasswd_state, username))
01506                 return NT_STATUS_OK;
01507 
01508         return NT_STATUS_UNSUCCESSFUL;
01509 }
01510 
01511 static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods, 
01512                                               struct samu *old_acct,
01513                                               const char *newname)
01514 {
01515         pstring rename_script;
01516         struct samu *new_acct = NULL;
01517         BOOL interim_account = False;
01518         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
01519 
01520         if (!*(lp_renameuser_script()))
01521                 goto done;
01522 
01523         if ( !(new_acct = samu_new( NULL )) ) {
01524                 return NT_STATUS_NO_MEMORY;
01525         }
01526         
01527         if ( !pdb_copy_sam_account( new_acct, old_acct ) 
01528                 || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
01529         {
01530                 goto done;
01531         }
01532         
01533         ret = smbpasswd_add_sam_account(my_methods, new_acct);
01534         if (!NT_STATUS_IS_OK(ret))
01535                 goto done;
01536 
01537         interim_account = True;
01538 
01539         /* rename the posix user */
01540         pstrcpy(rename_script, lp_renameuser_script());
01541 
01542         if (*rename_script) {
01543                 int rename_ret;
01544 
01545                 string_sub2(rename_script, "%unew", newname, sizeof(pstring), 
01546                             True, False, True);
01547                 string_sub2(rename_script, "%uold", pdb_get_username(old_acct), 
01548                             sizeof(pstring), True, False, True);
01549 
01550                 rename_ret = smbrun(rename_script, NULL);
01551 
01552                 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
01553 
01554                 if (rename_ret == 0) {
01555                         smb_nscd_flush_user_cache();
01556                 }
01557 
01558                 if (rename_ret) 
01559                         goto done; 
01560         } else {
01561                 goto done;
01562         }
01563 
01564         smbpasswd_delete_sam_account(my_methods, old_acct);
01565         interim_account = False;
01566 
01567 done:   
01568         /* cleanup */
01569         if (interim_account)
01570                 smbpasswd_delete_sam_account(my_methods, new_acct);
01571 
01572         if (new_acct)
01573                 TALLOC_FREE(new_acct);
01574         
01575         return (ret);   
01576 }
01577 
01578 static BOOL smbpasswd_rid_algorithm(struct pdb_methods *methods)
01579 {
01580         return True;
01581 }
01582 
01583 static void free_private_data(void **vp) 
01584 {
01585         struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
01586         
01587         endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
01588         
01589         *privates = NULL;
01590         /* No need to free any further, as it is talloc()ed */
01591 }
01592 
01593 static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
01594 {
01595         NTSTATUS nt_status;
01596         struct smbpasswd_privates *privates;
01597 
01598         if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
01599                 return nt_status;
01600         }
01601 
01602         (*pdb_method)->name = "smbpasswd";
01603 
01604         (*pdb_method)->setsampwent = smbpasswd_setsampwent;
01605         (*pdb_method)->endsampwent = smbpasswd_endsampwent;
01606         (*pdb_method)->getsampwent = smbpasswd_getsampwent;
01607         (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
01608         (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
01609         (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
01610         (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
01611         (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
01612         (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
01613 
01614         (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm;
01615 
01616         /* Setup private data and free function */
01617 
01618         if ( !(privates = TALLOC_ZERO_P( *pdb_method, struct smbpasswd_privates )) ) {
01619                 DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
01620                 return NT_STATUS_NO_MEMORY;
01621         }
01622 
01623         /* Store some config details */
01624 
01625         if (location) {
01626                 privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
01627         } else {
01628                 privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
01629         }
01630         
01631         if (!privates->smbpasswd_file) {
01632                 DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
01633                 return NT_STATUS_NO_MEMORY;
01634         }
01635 
01636         (*pdb_method)->private_data = privates;
01637 
01638         (*pdb_method)->free_private_data = free_private_data;
01639 
01640         return NT_STATUS_OK;
01641 }
01642 
01643 NTSTATUS pdb_smbpasswd_init(void) 
01644 {
01645         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd);
01646 }

Sambaに対してSat Aug 29 21:23:13 2009に生成されました。  doxygen 1.4.7