summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/textdocs/Samba-OpenSSL.txt405
-rw-r--r--source/include/doserr.h173
-rw-r--r--source/nsswitch/pam_winbind.h81
-rw-r--r--source/nsswitch/winbindd_glue.c442
-rw-r--r--source/nsswitch/winbindd_misc.c174
-rw-r--r--source/passdb/machine_sid.c255
-rw-r--r--source/passdb/pdb_ldap.c1033
-rw-r--r--source/passdb/pdb_nisplus.c1404
-rw-r--r--source/passdb/pdb_smbpasswd.c1520
-rw-r--r--source/passdb/pdb_tdb.c830
-rw-r--r--source/rpc_client/cli_trust.c247
-rw-r--r--source/utils/pdbedit.c709
12 files changed, 7273 insertions, 0 deletions
diff --git a/docs/textdocs/Samba-OpenSSL.txt b/docs/textdocs/Samba-OpenSSL.txt
new file mode 100644
index 00000000000..e1b54b1a032
--- /dev/null
+++ b/docs/textdocs/Samba-OpenSSL.txt
@@ -0,0 +1,405 @@
+Contributor: Christian Starkjohann <cs@obdev.at>
+Date: May 29, 1998
+Status:
+
+Comment: Updated by Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>
+Date: July 16, 2001
+
+Subject: Compiling and using samba with SSL support
+============================================================================
+
+What is SSL and SSLeay/OpenSSL?
+===============================
+SSL (Secure Socket Layer) is a protocol for encrypted and authenticated data
+transport. It is used by secure web servers for shopping malls, telebanking
+and things like that.
+
+SSLeay is a free implementation of the SSL protocol. The successor of it is
+OpenSSL, available from
+
+ http://www.openssl.org/
+
+The current version while these lines are written is 0.9.6b. In some countries
+encryption is plagued by legal problems, even though things have relaxed a
+lot in the last years.
+
+To compile samba with SSL support, you must first compile and install OpenSSL.
+At least version 0.9.5 of OpenSSL is required. Version 0.9.6b is the latest
+version and is strongly recommended.
+OpenSSL consists of a library (which can be linked to other applications like
+samba) and several utility programs needed for key generation, certification
+etc. OpenSSL installs to /usr/local/ssl/ by default.
+
+
+Compiling samba with OpenSSL
+============================
+1. Get and install OpenSSL. The rest of this documentation assumes that you
+ have installed it at the default location, which is /usr/local/ssl/.
+2. Call "configure" with the "--with-ssl" flag. If OpenSSL is not installed in
+ the default directory, you can use the "--with-sslinc" and "--with-ssllib"
+ flags to specify the location.
+3. Compile and install as usual.
+
+
+Configuring SSL in samba
+========================
+Before you configure SSL, you should know the basics of cryptography and how
+SSL relates to all of this. A basic introduction can be found further down in
+this document. The following variables in the "[global]" section of the
+configuration file are used to configure SSL:
+
+ssl = yes
+ This variable enables or disables the entire SSL mode. If it is set to
+ "no", the SSL enabled samba behaves exactly like the non-SSL samba. If set
+ to "yes", it depends on the variables "ssl hosts" and "ssl hosts resign"
+ whether an SSL connection will be required.
+ssl hosts =
+ssl hosts resign = 192.168.
+ These two variables define whether samba will go into SSL mode or not. If
+ none of them is defined, samba will allow only SSL connections. If the
+ "ssl hosts" variable lists hosts (by IP-address, IP-address range, net
+ group or name), only these hosts will be forced into SSL mode. If the
+ "ssl hosts resign" variable lists hosts, only these hosts will NOT be
+ forced into SSL mode. The syntax for these two variables is the same as
+ for the "hosts allow" and "hosts deny" pair of variables, only that the
+ subject of the decision is different: It's not the access right but
+ whether SSL is used or not. See the man page of smb.conf (section about
+ "allow hosts") for details. The above example requires SSL connections
+ from all hosts outside the local net (which is 192.168.*.*).
+ssl CA certDir = /usr/local/ssl/certs
+ This variable defines where to look up the Certification Autorities. The
+ given directory should contain one file for each CA that samba will trust.
+ The file name must be the hash value over the "Distinguished Name" of the
+ CA. How this directory is set up is explained later in this document. All
+ files within the directory that don't fit into this naming scheme are
+ ignored. You don't need this variable if you don't verify client
+ certificates.
+ssl CA certFile = /usr/local/ssl/certs/trustedCAs.pem
+ This variable is a second way to define the trusted CAs. The certificates
+ of the trusted CAs are collected in one big file and this variable points
+ to the file. You will probably only use one of the two ways to define your
+ CAs. The first choice is preferable if you have many CAs or want to be
+ flexible, the second is perferable if you only have one CA and want to
+ keep things simple (you won't need to create the hashed file names). You
+ don't need this variable if you don't verify client certificates.
+ssl server cert = /usr/local/ssl/certs/samba.pem
+ This is the file containing the server's certificate. The server _must_
+ have a certificate. The file may also contain the server's private key.
+ See later for how certificates and private keys are created.
+ssl server key = /usr/local/ssl/private/samba.pem
+ This file contains the private key of the server. If this variable is not
+ defined, the key is looked up in the certificate file (it may be appended
+ to the certificate). The server _must_ have a private key and the
+ certificate _must_ match this private key.
+ssl client cert = /usr/local/ssl/certs/smbclient.pem
+ The certificate in this file is used by smbclient if it exists. It's needed
+ if the server requires a client certificate.
+ssl client key = /usr/local/ssl/private/smbclient.pem
+ This is the private key for smbclient. It's only needed if the client
+ should have a certificate.
+ssl require clientcert = yes
+ If this variable is set to "yes", the server will not tolerate connections
+ from clients that don't have a valid certificate. The directory/file
+ given in "ssl CA certDir" and "ssl CA certFile" will be used to look up
+ the CAs that issued the client's certificate. If the certificate can't be
+ verified positively, the connection will be terminated.
+ If this variable is set to "no", clients don't need certificates. Contrary
+ to web applications you really _should_ require client certificates. In
+ the web environment the client's data is sensitive (credit card numbers)
+ and the server must prove to be trustworthy. In a file server environment
+ the server's data will be sensitive and the clients must prove to be
+ trustworthy.
+ssl require servercert = yes
+ If this variable is set to "yes", the smbclient will request a certificate
+ from the server. Same as "ssl require clientcert" for the server.
+ssl ciphers = ???
+ This variable defines the ciphers that should be offered during SSL
+ negotiation. You should not set this variable unless you know what you do.
+ssl version = ssl2or3
+ This enumeration variable defines the versions of the SSL protocol that
+ will be used. "ssl2or3" allows dynamic negotiation of SSL v2 or v3, "ssl2"
+ results SSL v2, "ssl3" results in SSL v3 and "tls1" results in TLS v1. TLS
+ (Transport Layer Security) is the (proposed?) new standard for SSL. The
+ default value is "ssl2or3".
+ssl compatibility = no
+ This variable defines whether SSLeay should be configured for bug
+ compatibility with other SSL implementations. This is probably not
+ desirable because currently no clients with SSL implementations other than
+ SSLeay exist.
+ssl entropy file =
+ Specifies a file from which processes will read "random bytes" on startup.
+ In order to seed the internal pseudo random number generator, entropy
+ must be provided. On system with a /dev/urandom device file, the processes
+ will retrieve its entropy from the kernel. On systems without kernel
+ entropy support, a file can be supplied that will be read on startup
+ and that will be used to seed the PRNG.
+ssl entropy bytes = 256
+ Number of bytes that will be read from entropy file. If -1 is given, the
+ complete file will be read.
+ssl egd socket =
+ Location of the communiation socket of an EGD or PRNGD daemon, from which
+ entropy can be retrieved. This option can be used instead of or together
+ with the "ssl entropy file" directive. 255bytes of entropy will be
+ retrieved from the daemon.
+
+
+Running samba with OpenSSL
+==========================
+Samba is started as usual. The daemon will ask for the private key's pass
+phrase before it goes to background if the private key has been encrypted.
+If you start smbd from inetd, this won't work. Therefore you must not encrypt
+your private key if you run smbd from inetd.
+
+Windows clients will try to connect to the SSL enabled samba daemon and they
+will fail. This can fill your log with failed SSL negotiation messages. To
+avoid this, you can either not run nmbd (if all clients use DNS to look up
+the server), which will leave the Windows machine unaware of the server, or
+list all (local) Windows machines in the "ssl hosts resign" variable.
+
+
+About certificates
+==================
+Secure samba servers will not be set up for public use as it is the case with
+secure web servers. Most installations will probably use it for distributed
+offices that use parts of the internet for their intranet, for access to a
+web server that's physically hosted by the provider or simply for teleworking.
+All these applications work with a known group of users that can easily agree
+on a certification authority. The CA can be operated by the company and the
+policy for issuing certificates can be determined by the company. If samba is
+configured to verify client certificates, it (currently) only verifies
+whether a valid certificate exists. It does not verify any of the data within
+the certificate (although it prints some of the data to the log file).
+
+
+Which clients are available that support SSL?
+=============================================
+Currently there are only smbclient which is part of the samba package and
+Sharity. Shariy versions newer than 0.14 in the beta branch and 1.01 in the
+main branch can be compiled with SSLeay. Sharity is a CIFS/SMB client
+implementation for Unix. It is a commercial product, but it is available in
+source code and the demo-mode allows access to the first three layers of the
+mounted directory hierarchy. Licenses for universities and students are free.
+Sharity is available at
+
+ http://www.obdev.at/Products/Sharity.html
+
+
+
+###########################################################################
+Basics about Cryptography and SSL(eay)
+###########################################################################
+
+There are many good introductions to cryptography. I assume that the reader
+is familiar with the words "encryption", "digital signature" and RSA. If you
+don't know these terms, please read the cryptography FAQ part 6 and 7, which
+is posted to the usenet newsgroup sci.crypt. It is also available from
+
+ ftp://rtfm.mit.edu/pub/usenet/news.answers/cryptography-faq
+and
+ http://www.cis.ohio-state.edu/hypertext/faq/usenet/cryptography-faq
+
+I'll concentrate on the questions specific to SSL and samba here.
+
+
+What is a certificate?
+======================
+A certificate is issued by an issuer, usually a "Certification Authority"
+(CA), who confirms something by issuing the certificate. The subject of this
+confirmation depends on the CA's policy. CAs for secure web servers (used for
+shopping malls etc.) usually only attest that the given public key belongs the
+the given domain name. Company-wide CAs might attest that you are an employee
+of the company, that you have permissions to use a server or whatever.
+
+
+What is an X.509 certificate technically?
+=========================================
+Technically, the certificate is a block of data signed by the certificate
+issuer (the CA). The relevant fields are:
+ - unique identifier (name) of the certificate issuer
+ - time range during that the certificate is valid
+ - unique identifier (name) of the certified subject
+ - public key of the certified subject
+ - the issuer's signature over all of the above
+If this certificate should be verified, the verifier must have a table of the
+names and public keys of trusted CAs. For simplicity, these tables are lists
+of certificates issued by the respective CAs for themselves (self-signed
+certificates).
+
+
+What are the implications of this certificate structure?
+========================================================
+ - Because the certificate contains the subject's public key, the
+ certificate and the private key together are all that's needed to encrypt
+ and decrypt.
+ - To verify certificates, you need the certificates of all CAs you trust.
+ - The simplest form of a dummy-certificate is one that's signed by the
+ subject itself.
+ - A CA is needed. The client can't simply issue local certificates for
+ servers it trusts because the server determines which certificate it
+ presents.
+
+
+
+###########################################################################
+Setting up files and directories for OpenSSL
+###########################################################################
+
+The first thing you should do is to change your PATH environment variable to
+include the bin directory of OpenSSL. E.g.:
+
+ PATH=$PATH:/usr/local/ssl/bin
+
+If your system's kernel supports a /dev/urandom device, all OpenSSL operations
+will automatically retrieve its entropy from it. If your system does not
+support /dev/urandom, you may install an EGD/PRNGD daemon for entropy
+supply or can generate seed from reading files (that should contain information
+unpredictable/unknown to attackers). Use the "-rand" option to the openssl
+commands to specify the entropy source (if /dev/urandom is not available).
+
+OpenSSL additionally keeps random seed in the $HOME/.rnd file. You can
+initialize this file using:
+
+ openssl rand -rand /tmp/rfile.txt > $HOME/.rnd
+ rm -f /tmp/rfile.txt # nobody must know!!
+
+or
+
+ openssl rand -rand /path/to/egd-socket > $HOME/.rnd
+
+How to create a keypair
+=======================
+This is done with 'genrsa' for RSA keys and 'gendsa' for DSA keys. For an RSA
+key with 1024 bits which is written to the file "key.pem" type:
+
+ openssl genrsa -des3 -rand /path/to/source 1024 > key.pem
+
+You will be asked for a pass phrase to protect this key. If you don't want to
+protect your private key with a pass phrase, just omit the parameter "-des3".
+If you want a different key size, replace the parameter "1024". You really
+should use a pass phrase.
+
+If you want to remove the pass phrase from a key use:
+
+ openssl rsa -in key.pem -out newkey.pem
+
+And to add or change a pass phrase:
+
+ openssl rsa -des3 -in key.pem -out newkey.pem
+
+
+How to create a dummy certificate
+=================================
+If you still have your keypair in the file "key.pem", the command
+
+ openssl req -new -x509 -key key.pem -out cert.pem
+
+will write a self-signed dummy certificate to the file "cert.pem". This can
+be used for testing or if only encryption and no certification is needed.
+Please bear in mind that encryption without authentication (certification)
+can never be secure. It's open to (at least) "man-in-the-middle" attacks.
+
+
+How to create a certificate signing request
+===========================================
+You must not simply send your keypair to the CA for signing because it
+contains the private key which _must_ be kept secret. A signing request
+consists of your public key and some additional information you want to have
+bound to that key by the certificate. If you operate a secure web server,
+this additional information will (among other things) contain the URL of
+your server in the field "Common Name". The certificate signing request is
+created from the keypair with the following command (assuming that the key
+pair is still in "key.pem"):
+
+ openssl req -new -key key.pem -out csr.pem
+
+This command will ask you for the information which must be included in the
+certificate and will write the signing request to the file "csr.pem". This
+signing request is all the CA needs for signing, at least technically. Most
+CAs will demand bureaucratic material and money, too.
+
+
+How to set up a Certification Authority (CA)
+============================================
+Being a certification authority requires a database that holds the CA's
+keypair, the CA's certificate, a list of all signed certificates and other
+information. This database is kept in a directory hierarchy below a
+configurable starting point. The starting point must be configured in the
+ssleay.conf file. This file is at /usr/local/ssl/lib/ssleay.conf if you have
+not changed the default installation path.
+
+The first thing you should do is to edit this file according to your needs.
+Let's assume that you want to hold the CA's database at the directory
+"/usr/local/ssl/CA". Change the variable "dir" in section "CA_default" to
+this path. You may also want to edit the default settings for some variables,
+but the values given should be OK. This path is also contained in the shell
+script CA.sh, which should be at "/usr/local/ssl/bin/CA.sh". Change the path
+in the shell script:
+
+ CATOP=/usr/local/ssl/CA
+ CAKEY=./cakey.pem # relative to $CATOP/
+ CACERT=./cacert.pem # relative to $CATOP/private/
+
+Then create the directory "/usr/local/ssl/CA" and make it writable for the
+user that operates the CA. You should also initialize SSLeay as CA user (set
+up the random number generator). Now you should call the shell script CA.sh
+to set up the initial database:
+
+ CA.sh -newca
+
+This command will ask you whether you want to use an existing certificate or
+create one. Just press enter to create a new key pair and certificate. You
+will be asked the usual questions for certificates: the country, state, city,
+"Common Name", etc. Enter the appropriate values for the CA. When CA.sh
+finishes, it has set up a bunch of directories and files. A CA must publish
+it's certificate, which is in the file "/usr/local/ssl/CA/cacert.pem".
+
+
+How to sign a certificate request
+=================================
+After setting up the CA stuff, you can start signing certificate requests.
+Make sure that the SSLeay utilities know where the configuration file is.
+The default is compiled in, if you don't use the default location, add the
+parameter "-config <cfg-file>". Make also sure that the configuration file
+contains the correct path to the CA database. If all this is set up properly,
+you can sign the request in the file "csr.pem" with the command:
+
+ openssl ca -policy policy_anything -days 365 -infiles csr.pem >cert.pem
+
+The resulting certificate (and additional information) will be in "cert.pem".
+If you want the certificate to be valid for a period different from 365 days,
+simply change the "-days" parameter.
+
+
+How to install a new CA certificate
+===================================
+Whereever a certificate must be checked, the CA's certificate must be
+available. Let's take the common case where the client verifies the server's
+certificate. The case where the server verfies the client's certificate works
+the same way. The client receives the server's certificate, which contains
+the "Distinguished Name" of the CA. To verify whether the signature in this
+certificate is OK, it must look up the public key of that CA. Therefore each
+client must hold a database of CAs, indexed by CA name. This database is best
+kept in a directory where each file contains the certificate of one CA and is
+named after the hashvalue (checksum) of the CA's name. This section describes
+how such a database is managed technically. Whether or not to install (and
+thereby trust) a CA is a totally different matter.
+
+The client must know the directory of the CA database. This can be configured.
+There may also be a configuration option to set up a CA database file which
+contains all CA certs in one file. Let's assume that the CA database is kept
+in the directory "/usr/local/ssl/certs". The following example assumes that
+the CA's certificate is in the file "cacert.pem" and the CA is known as
+"myCA". To install the certificate, do the following:
+
+ cp cacert.pem /usr/local/ssl/cers/myCA.pem
+ cd /usr/local/ssl/certs
+ ln -s myCA.pem `openssl x509 -noout -hash < myCA.pem`.0
+
+The last command creates a link from the hashed name to the real file.
+
+From now on all certificates signed by the myCA authority will be accepted by
+clients that use the directory "/usr/local/ssl/certs/" as their CA certificate
+database.
+
+
+
diff --git a/source/include/doserr.h b/source/include/doserr.h
new file mode 100644
index 00000000000..dc5bd0414a3
--- /dev/null
+++ b/source/include/doserr.h
@@ -0,0 +1,173 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ DOS error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _DOSERR_H
+#define _DOSERR_H
+
+/* Error classes */
+
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRDOS error class */
+#define ERRsuccess 0 /* No error */
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRbadshare 32 /* Share mode on file conflict with open mode */
+#define ERRlock 33 /* Lock request conflicts with existing lock */
+#define ERRunsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */
+#define ERRnosuchshare 67 /* You specified an invalid share name */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRinvalidparam 87
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRinsufficientbuffer 122
+#define ERRinvalidname 123 /* Invalid name */
+#define ERRunknownlevel 124
+#define ERRnotlocked 158 /* This region is not locked by this locking context. */
+#define ERRrename 183
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERRnomoreitems 259
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
+#define ERReasnotsupported 282 /* Extended attributes */
+#define ERRbuftoosmall 2123
+#define ERRunknownipc 2142
+#define ERRnosuchprintjob 2151
+
+/* here's a special one from observing NT */
+#define ERRnoipc 66 /* don't support ipc */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+#define ERRunknownsmb 22 /* from NT 3.5 response */
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+
+/* these are win32 error codes. There are only a few places where
+ these matter for Samba, primarily in the NT printing code */
+#define WERR_OK W_ERROR(0)
+#define WERR_ACCESS_DENIED W_ERROR(5)
+#define WERR_BADFID W_ERROR(6)
+#define WERR_BADFUNC W_ERROR(1)
+#define WERR_INSUFFICIENT_BUFFER W_ERROR(122)
+#define WERR_INVALID_PARAM W_ERROR(87)
+#define WERR_NOT_SUPPORTED W_ERROR(50)
+#define WERR_BAD_PASSWORD W_ERROR(86)
+#define WERR_NOMEM W_ERROR(8)
+#define WERR_INVALID_NAME W_ERROR(123)
+#define WERR_UNKNOWN_LEVEL W_ERROR(124)
+#define WERR_NO_MORE_ITEMS W_ERROR(259)
+#define WERR_MORE_DATA W_ERROR(234)
+#define WERR_UNKNOWN_PRINTER_DRIVER W_ERROR(1797)
+#define WERR_INVALID_PRINTER_NAME W_ERROR(1801)
+#define WERR_INVALID_DATATYPE W_ERROR(1804)
+#define WERR_INVALID_ENVIRONMENT W_ERROR(1805)
+#define WERR_BUF_TOO_SMALL W_ERROR(2123)
+#define WERR_JOB_NOT_FOUND W_ERROR(2151)
+#define WERR_DEST_NOT_FOUND W_ERROR(2152)
+#define WERR_PRINTER_DRIVER_IN_USE W_ERROR(3001)
+#define WERR_STATUS_MORE_ENTRIES W_ERROR(0x0105)
+
+/* DFS errors */
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#define WERR_DFS_NO_SUCH_VOL W_ERROR(NERR_BASE+562)
+#define WERR_DFS_NO_SUCH_SHARE W_ERROR(NERR_BASE+565)
+#define WERR_DFS_NO_SUCH_SERVER W_ERROR(NERR_BASE+573)
+#define WERR_DFS_INTERNAL_ERROR W_ERROR(NERR_BASE+590)
+#define WERR_DFS_CANT_CREATE_JUNCT W_ERROR(NERR_BASE+569)
+
+#endif /* _DOSERR_H */
diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h
new file mode 100644
index 00000000000..991c117656f
--- /dev/null
+++ b/source/nsswitch/pam_winbind.h
@@ -0,0 +1,81 @@
+/* pam_winbind header file
+ (Solaris needs some macros from Linux for common PAM code)
+
+ Shirish Kalele 2000
+*/
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <config.h>
+
+#define MODULE_NAME "pam_winbind"
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#if defined(SUNOS5) || defined(SUNOS4)
+
+/* Solaris always uses dynamic pam modules */
+#define PAM_EXTERN extern
+#include <security/pam_appl.h>
+
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+#ifdef HAVE_SECURITY_PAM_MODULES_H
+#include <security/pam_modules.h>
+#endif
+
+#ifdef HAVE_SECURITY__PAM_MACROS_H
+#include <security/_pam_macros.h>
+#else
+/* Define required macros from (Linux PAM 0.68) security/_pam_macros.h */
+#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
+do { \
+ int reply_i; \
+ \
+ for (reply_i=0; reply_i<replies; ++reply_i) { \
+ if (reply[reply_i].resp) { \
+ _pam_overwrite(reply[reply_i].resp); \
+ free(reply[reply_i].resp); \
+ } \
+ } \
+ if (reply) \
+ free(reply); \
+} while (0)
+
+#define _pam_overwrite(x) \
+do { \
+ register char *__xx__; \
+ if ((__xx__=(x))) \
+ while (*__xx__) \
+ *__xx__++ = '\0'; \
+} while (0)
+
+/*
+ * Don't just free it, forget it too.
+ */
+
+#define _pam_drop(X) SAFE_FREE(X)
+
+#define x_strdup(s) ( (s) ? strdup(s):NULL )
+#endif
+
+#define PAM_DEBUG_ARG (1<<0)
+#define PAM_USE_AUTHTOK_ARG (1<<1)
+#define PAM_UNKNOWN_OK_ARG (1<<2)
+
+#include "winbind_nss_config.h"
+#include "winbindd_nss.h"
diff --git a/source/nsswitch/winbindd_glue.c b/source/nsswitch/winbindd_glue.c
new file mode 100644
index 00000000000..0c508ccf4b2
--- /dev/null
+++ b/source/nsswitch/winbindd_glue.c
@@ -0,0 +1,442 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon glue functions to connect new cli interface
+ to older style lsa_ and samr_ functions
+
+ Copyright (C) tridge@samba.org 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+/****************************************************************************
+do a LSA Open Policy
+****************************************************************************/
+BOOL wb_lsa_open_policy(char *server, BOOL sec_qos, uint32 des_access,
+ CLI_POLICY_HND *pol)
+{
+ struct nmb_name calling, called;
+ struct ntuser_creds creds;
+ struct in_addr dest_ip;
+ fstring dest_host;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ ZERO_STRUCTP(pol);
+
+ pol->cli = (struct cli_state *)malloc(sizeof(struct cli_state));
+ pol->mem_ctx = talloc_init();
+
+ ZERO_STRUCTP(pol->cli);
+
+ if (!pol->cli || !pol->mem_ctx)
+ return False;
+
+ /* Initialise RPC connection */
+
+ if (!cli_initialise(pol->cli))
+ goto done;
+
+ ZERO_STRUCT(creds);
+ creds.pwd.null_pwd = 1;
+
+ cli_init_creds(pol->cli, &creds);
+
+ /* Establish a SMB connection */
+
+ if (!resolve_srv_name(server, dest_host, &dest_ip)) {
+ goto done;
+ }
+
+ make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ if (!cli_establish_connection(pol->cli, dest_host, &dest_ip, &calling,
+ &called, "IPC$", "IPC", False, True)) {
+ goto done;
+ }
+
+ if (!cli_nt_session_open (pol->cli, PIPE_LSARPC)) {
+ goto done;
+ }
+
+ result = cli_lsa_open_policy(pol->cli, pol->mem_ctx, sec_qos,
+ des_access, &pol->handle);
+
+ done:
+ if (!NT_STATUS_IS_OK(result) && pol->cli) {
+ if (pol->cli->initialised)
+ cli_shutdown(pol->cli);
+ SAFE_FREE(pol->cli);
+ }
+
+ return NT_STATUS_IS_OK(result);
+}
+
+/****************************************************************************
+do a LSA Enumerate Trusted Domain
+****************************************************************************/
+BOOL wb_lsa_enum_trust_dom(CLI_POLICY_HND *hnd, uint32 *enum_ctx,
+ uint32 * num_doms, char ***names, DOM_SID **sids)
+{
+ NTSTATUS ret;
+
+ ret = cli_lsa_enum_trust_dom(hnd->cli, hnd->mem_ctx, &hnd->handle,
+ enum_ctx, num_doms, names, sids);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+/****************************************************************************
+do a LSA Query Info Policy
+****************************************************************************/
+BOOL wb_lsa_query_info_pol(CLI_POLICY_HND *hnd, uint16 info_class,
+ fstring domain_name, DOM_SID *domain_sid)
+{
+ NTSTATUS ret;
+
+ ret = cli_lsa_query_info_policy(hnd->cli, hnd->mem_ctx, &hnd->handle,
+ info_class, domain_name, domain_sid);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+/****************************************************************************
+do a LSA Lookup Names
+****************************************************************************/
+BOOL wb_lsa_lookup_names(CLI_POLICY_HND *hnd, int num_names, char **names,
+ DOM_SID **sids, uint32 **types, int *num_sids)
+{
+ NTSTATUS ret;
+
+ ret = cli_lsa_lookup_names(hnd->cli, hnd->mem_ctx, &hnd->handle,
+ num_names, names, sids, types, num_sids);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+/****************************************************************************
+do a LSA Lookup SIDS
+****************************************************************************/
+BOOL wb_lsa_lookup_sids(CLI_POLICY_HND *hnd, int num_sids, DOM_SID *sids,
+ char ***names, uint32 **types, int *num_names)
+{
+ NTSTATUS ret;
+
+ ret = cli_lsa_lookup_sids(hnd->cli, hnd->mem_ctx, &hnd->handle,
+ num_sids, sids, names, types, num_names);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+/****************************************************************************
+lsa_close glue
+****************************************************************************/
+BOOL wb_lsa_close(CLI_POLICY_HND *hnd)
+{
+ NTSTATUS ret;
+
+ ret = cli_lsa_close(hnd->cli, hnd->mem_ctx, &hnd->handle);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+
+/****************************************************************************
+samr_close glue
+****************************************************************************/
+BOOL wb_samr_close(CLI_POLICY_HND *hnd)
+{
+ NTSTATUS ret;
+
+ ret = cli_samr_close(hnd->cli, hnd->mem_ctx, &hnd->handle);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+
+/****************************************************************************
+samr_connect glue
+****************************************************************************/
+BOOL wb_samr_connect(char *server, uint32 access_mask, CLI_POLICY_HND *pol)
+{
+ struct nmb_name calling, called;
+ struct ntuser_creds creds;
+ struct in_addr dest_ip;
+ fstring dest_host;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ ZERO_STRUCTP(pol);
+
+ pol->cli = (struct cli_state *)malloc(sizeof(struct cli_state));
+
+ ZERO_STRUCTP(pol->cli);
+
+ pol->mem_ctx = talloc_init();
+
+ if (!pol->cli || !pol->mem_ctx)
+ return False;
+
+ /* Initialise RPC connection */
+
+ if (!cli_initialise(pol->cli))
+ goto done;
+
+ ZERO_STRUCT(creds);
+ creds.pwd.null_pwd = 1;
+
+ cli_init_creds(pol->cli, &creds);
+
+ /* Establish a SMB connection */
+
+ if (!resolve_srv_name(server, dest_host, &dest_ip)) {
+ goto done;
+ }
+
+ make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ if (!cli_establish_connection(pol->cli, dest_host, &dest_ip, &calling,
+ &called, "IPC$", "IPC", False, True)) {
+ goto done;
+ }
+
+ if (!cli_nt_session_open (pol->cli, PIPE_SAMR)) {
+ goto done;
+ }
+
+ result = cli_samr_connect(pol->cli, pol->mem_ctx,
+ access_mask, &pol->handle);
+
+ done:
+ if (!NT_STATUS_IS_OK(result) && pol->cli) {
+ if (pol->cli->initialised)
+ cli_shutdown(pol->cli);
+ SAFE_FREE(pol->cli);
+ }
+
+ return NT_STATUS_IS_OK(result);
+}
+
+
+/****************************************************************************
+samr_open_domain glue
+****************************************************************************/
+BOOL wb_samr_open_domain(CLI_POLICY_HND *connect_pol, uint32 ace_perms,
+ DOM_SID *sid, CLI_POLICY_HND *domain_pol)
+{
+ NTSTATUS ret;
+
+ ret = cli_samr_open_domain(connect_pol->cli,
+ connect_pol->mem_ctx,
+ &connect_pol->handle,
+ ace_perms,
+ sid,
+ &domain_pol->handle);
+
+ if NT_STATUS_IS_OK(ret) {
+ domain_pol->cli = connect_pol->cli;
+ domain_pol->mem_ctx = connect_pol->mem_ctx;
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+do a SAMR enumerate groups
+****************************************************************************/
+NTSTATUS wb_samr_enum_dom_groups(CLI_POLICY_HND *pol, uint32 *start_idx,
+ uint32 size, struct acct_info **sam,
+ uint32 *num_sam_groups)
+{
+ return cli_samr_enum_dom_groups(pol->cli, pol->mem_ctx, &pol->handle,
+ start_idx, size, sam, num_sam_groups);
+}
+
+/****************************************************************************
+do a SAMR query userinfo
+****************************************************************************/
+BOOL wb_get_samr_query_userinfo(CLI_POLICY_HND *pol, uint32 info_level,
+ uint32 user_rid, SAM_USERINFO_CTR **ctr)
+{
+ POLICY_HND user_pol;
+ BOOL got_user_pol = False;
+ NTSTATUS result;
+
+ result = cli_samr_open_user(pol->cli, pol->mem_ctx,
+ &pol->handle, MAXIMUM_ALLOWED_ACCESS,
+ user_rid, &user_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_user_pol = True;
+
+ result = cli_samr_query_userinfo(pol->cli, pol->mem_ctx,
+ &user_pol, info_level, ctr);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ done:
+ if (got_user_pol) cli_samr_close(pol->cli, pol->mem_ctx, &user_pol);
+
+ return NT_STATUS_IS_OK(result);
+}
+
+/****************************************************************************
+do a SAMR enumerate groups
+****************************************************************************/
+BOOL wb_samr_open_user(CLI_POLICY_HND *pol, uint32 access_mask, uint32 rid,
+ POLICY_HND *user_pol)
+{
+ NTSTATUS ret;
+
+ ret = cli_samr_open_user(pol->cli, pol->mem_ctx, &pol->handle,
+ access_mask, rid, user_pol);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+BOOL wb_samr_query_usergroups(CLI_POLICY_HND *pol, uint32 *num_groups,
+ DOM_GID **gid)
+{
+ NTSTATUS ret;
+
+ ret = cli_samr_query_usergroups(pol->cli, pol->mem_ctx, &pol->handle,
+ num_groups, gid);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+BOOL wb_get_samr_query_groupinfo(CLI_POLICY_HND *pol, uint32 info_level,
+ uint32 group_rid, GROUP_INFO_CTR *ctr)
+{
+ POLICY_HND group_pol;
+ BOOL got_group_pol = False;
+ NTSTATUS result;
+
+ result = cli_samr_open_group(pol->cli, pol->mem_ctx,
+ &pol->handle, MAXIMUM_ALLOWED_ACCESS,
+ group_rid, &group_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_group_pol = True;
+
+ result = cli_samr_query_groupinfo(pol->cli, pol->mem_ctx,
+ &group_pol, info_level,
+ ctr);
+ done:
+ if (got_group_pol) cli_samr_close(pol->cli, pol->mem_ctx, &group_pol);
+
+ return NT_STATUS_IS_OK(result);
+}
+
+BOOL wb_sam_query_groupmem(CLI_POLICY_HND *pol, uint32 group_rid,
+ uint32 *num_names, uint32 **rid_mem,
+ char ***names, uint32 **name_types)
+{
+ BOOL got_group_pol = False;
+ POLICY_HND group_pol;
+ NTSTATUS result;
+ uint32 i, total_names = 0;
+
+ result = cli_samr_open_group(pol->cli, pol->mem_ctx,
+ &pol->handle, MAXIMUM_ALLOWED_ACCESS,
+ group_rid, &group_pol);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ got_group_pol = True;
+
+ result = cli_samr_query_groupmem(pol->cli, pol->mem_ctx,
+ &group_pol, num_names, rid_mem,
+ name_types);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Call cli_samr_lookup_rids() in bunches of ~1000 rids to avoid
+ crashing NT4. */
+
+#define MAX_LOOKUP_RIDS 900
+
+ *names = talloc(pol->mem_ctx, *num_names * sizeof(char *));
+ *name_types = talloc(pol->mem_ctx, *num_names * sizeof(uint32));
+
+ for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
+ int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
+ uint32 tmp_num_names = 0;
+ char **tmp_names = NULL;
+ uint32 *tmp_types = NULL;
+
+ /* Lookup a chunk of rids */
+
+ result = cli_samr_lookup_rids(pol->cli, pol->mem_ctx,
+ &pol->handle, 1000, /* flags */
+ num_lookup_rids,
+ &(*rid_mem)[i],
+ &tmp_num_names,
+ &tmp_names, &tmp_types);
+ if (!NT_STATUS_IS_OK(result))
+ goto done;
+
+ /* Copy result into array. The talloc system will take
+ care of freeing the temporary arrays later on. */
+
+ memcpy(&(*names)[i], tmp_names, sizeof(char *) *
+ tmp_num_names);
+
+ memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
+ tmp_num_names);
+
+ total_names += tmp_num_names;
+ }
+
+ *num_names = total_names;
+
+ done:
+ if (got_group_pol)
+ cli_samr_close(pol->cli, pol->mem_ctx, &group_pol);
+
+ return NT_STATUS_IS_OK(result);
+}
+
+BOOL wb_samr_query_dom_info(CLI_POLICY_HND *pol, uint16 switch_value,
+ SAM_UNK_CTR *ctr)
+{
+ NTSTATUS ret;
+
+ ret = cli_samr_query_dom_info(pol->cli, pol->mem_ctx,
+ &pol->handle, switch_value, ctr);
+
+ return NT_STATUS_IS_OK(ret);
+}
+
+/* Unlike all the others, the status code of this function is actually used
+ by winbindd. */
+
+NTSTATUS wb_samr_query_dispinfo(CLI_POLICY_HND *pol, uint32 *start_ndx,
+ uint16 info_level, uint32 *num_entries,
+ SAM_DISPINFO_CTR *ctr)
+{
+ return cli_samr_query_dispinfo(pol->cli, pol->mem_ctx,
+ &pol->handle, start_ndx,
+ info_level, num_entries,
+ 0xffff, ctr);
+}
diff --git a/source/nsswitch/winbindd_misc.c b/source/nsswitch/winbindd_misc.c
new file mode 100644
index 00000000000..620dc9e7d9b
--- /dev/null
+++ b/source/nsswitch/winbindd_misc.c
@@ -0,0 +1,174 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+
+ Winbind daemon - miscellaneous other functions
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "winbindd.h"
+
+extern pstring global_myname;
+
+/* Some routines to fetch the trust account password from a HEAD
+ version of Samba. Yuck. )-: */
+
+/************************************************************************
+form a key for fetching a domain trust password from
+************************************************************************/
+static char *trust_keystr(char *domain)
+{
+ static fstring keystr;
+
+ snprintf(keystr,sizeof(keystr),"%s/%s", SECRETS_MACHINE_ACCT_PASS,
+ domain);
+
+ return keystr;
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain
+************************************************************************/
+static BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd,
+ time_t *pass_last_set_time)
+{
+ struct machine_acct_pass *pass;
+ size_t size;
+
+ if (!(pass = secrets_fetch(trust_keystr(domain), &size)) ||
+ size != sizeof(*pass)) return False;
+
+ if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
+ memcpy(ret_pwd, pass->hash, 16);
+ SAFE_FREE(pass);
+ return True;
+}
+
+/* Check the machine account password is valid */
+
+enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *state)
+{
+ NTSTATUS status;
+ uchar trust_passwd[16];
+ struct in_addr *ip_list = NULL;
+ int count;
+ uint16 validation_level;
+ fstring controller, trust_account;
+ int num_retries = 0;
+
+ DEBUG(3, ("[%5d]: check machine account\n", state->pid));
+
+ /* Get trust account password */
+
+ again:
+ if (!_get_trust_account_password(lp_workgroup(), trust_passwd,
+ NULL)) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ /* Get domain controller */
+
+ if (!get_dc_list(True, lp_workgroup(), &ip_list, &count) ||
+ !lookup_pdc_name(global_myname, lp_workgroup(), &ip_list[0],
+ controller)) {
+ DEBUG(0, ("could not find domain controller for "
+ "domain %s\n", lp_workgroup()));
+ status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ goto done;
+ }
+
+ DEBUG(3, ("contacting controller %s to check secret\n", controller));
+
+ /* Contact domain controller to check secret */
+
+ slprintf(trust_account, sizeof(trust_account) - 1, "%s$",
+ global_myname);
+
+#if 0 /* XXX */
+ status = cli_nt_setup_creds(controller, lp_workgroup(), global_myname,
+ trust_account, trust_passwd,
+ SEC_CHAN_WKSTA, &validation_level);
+#endif
+
+ /* There is a race condition between fetching the trust account
+ password and joining the domain so it's possible that the trust
+ account password has been changed on us. We are returned
+ NT_STATUS_ACCESS_DENIED if this happens. */
+
+#define MAX_RETRIES 8
+
+ if ((num_retries < MAX_RETRIES) &&
+ NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
+ num_retries++;
+ goto again;
+ }
+
+ /* Pass back result code - zero for success, other values for
+ specific failures. */
+
+ DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(status) ? "good" : "bad"));
+
+ done:
+ state->response.data.num_entries = NT_STATUS_V(status);
+ return WINBINDD_OK;
+}
+
+enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
+ *state)
+{
+ struct winbindd_domain *domain;
+ int total_entries = 0, extra_data_len = 0;
+ char *ted, *extra_data = NULL;
+
+ DEBUG(3, ("[%5d]: list trusted domains\n", state->pid));
+
+ for(domain = domain_list; domain; domain = domain->next) {
+
+ /* Skip own domain */
+
+ if (strequal(domain->name, lp_workgroup())) continue;
+
+ /* Add domain to list */
+
+ total_entries++;
+ ted = Realloc(extra_data, sizeof(fstring) *
+ total_entries);
+
+ if (!ted) {
+ DEBUG(0,("winbindd_list_trusted_domains: failed to enlarge buffer!\n"));
+ SAFE_FREE(extra_data);
+ return WINBINDD_ERROR;
+ }
+ else extra_data = ted;
+
+ memcpy(&extra_data[extra_data_len], domain->name,
+ strlen(domain->name));
+
+ extra_data_len += strlen(domain->name);
+ extra_data[extra_data_len++] = ',';
+ }
+
+ if (extra_data) {
+ if (extra_data_len > 1) extra_data[extra_data_len - 1] = '\0';
+ state->response.extra_data = extra_data;
+ state->response.length += extra_data_len;
+ }
+
+ return WINBINDD_OK;
+}
diff --git a/source/passdb/machine_sid.c b/source/passdb/machine_sid.c
new file mode 100644
index 00000000000..859f00b4c6e
--- /dev/null
+++ b/source/passdb/machine_sid.c
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Password and authentication handling
+ Copyright (C) Jeremy Allison 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Gerald (Jerry) Carter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Read the machine SID from a file.
+****************************************************************************/
+
+static BOOL read_sid_from_file(int fd, char *sid_file)
+{
+ fstring fline;
+
+ memset(fline, '\0', sizeof(fline));
+
+ if(read(fd, fline, sizeof(fline) -1 ) < 0) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Convert to the machine SID.
+ */
+
+ fline[sizeof(fline)-1] = '\0';
+ if(!string_to_sid( &global_sam_sid, fline)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Generate the global machine sid. Look for the MACHINE.SID file first, if
+ not found then look in smb.conf and use it to create the MACHINE.SID file.
+ Note this function will be replaced soon. JRA.
+****************************************************************************/
+
+BOOL pdb_generate_sam_sid(void)
+{
+ int fd;
+ pstring sid_file;
+ fstring sid_string;
+ SMB_STRUCT_STAT st;
+ BOOL overwrite_bad_sid = False;
+
+ generate_wellknown_sids();
+
+ pstrcpy(sid_file, lp_private_dir());
+
+ if (!directory_exist(sid_file, NULL)) {
+ if (mkdir(sid_file, 0700) != 0) {
+ DEBUG(0,("can't create private directory %s : %s\n",
+ sid_file, strerror(errno)));
+ return False;
+ }
+ }
+
+ pstrcat(sid_file, "/MACHINE.SID");
+
+ if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
+ DEBUG(0,("unable to open or create file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ return False;
+ }
+
+ /*
+ * Check if the file contains data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * We have a valid SID - read it.
+ */
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ /*
+ * JRA. Reversed the sense of this test now that I have
+ * actually done this test *personally*. One more reason
+ * to never trust third party information you have not
+ * independently verified.... sigh. JRA.
+ */
+
+ if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
+ /*
+ * Fix and re-write...
+ */
+ overwrite_bad_sid = True;
+ global_sam_sid.sub_auths[0] = 21;
+ DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
+detected - re-writing to be decimal 21 instead.\n" ));
+ sid_to_string(sid_string, &global_sam_sid);
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
+ DEBUG(0,("unable to seek file file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ } else {
+ close(fd);
+ return True;
+ }
+ } else {
+ /*
+ * The file contains no data - we need to generate our
+ * own sid.
+ * Generate the new sid data & turn it into a string.
+ */
+ int i;
+ uchar raw_sid_data[12];
+ DOM_SID mysid;
+
+ memset((char *)&mysid, '\0', sizeof(DOM_SID));
+ mysid.sid_rev_num = 1;
+ mysid.id_auth[5] = 5;
+ mysid.num_auths = 0;
+ mysid.sub_auths[mysid.num_auths++] = 21;
+
+ generate_random_buffer( raw_sid_data, 12, True);
+ for( i = 0; i < 3; i++)
+ mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
+
+ sid_to_string(sid_string, &mysid);
+ }
+
+ fstrcat(sid_string, "\n");
+
+ /*
+ * Ensure our new SID is valid.
+ */
+
+ if(!string_to_sid( &global_sam_sid, sid_string)) {
+ DEBUG(0,("unable to generate machine SID.\n"));
+ return False;
+ }
+
+ /*
+ * Do an exclusive blocking lock on the file.
+ */
+
+ if(!do_file_lock( fd, 60, F_WRLCK)) {
+ DEBUG(0,("unable to lock file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(!overwrite_bad_sid) {
+ /*
+ * At this point we have a blocking lock on the SID
+ * file - check if in the meantime someone else wrote
+ * SID data into the file. If so - they were here first,
+ * use their data.
+ */
+
+ if(sys_fstat( fd, &st) < 0) {
+ DEBUG(0,("unable to stat file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+
+ if(st.st_size > 0) {
+ /*
+ * Unlock as soon as possible to reduce
+ * contention on the exclusive lock.
+ */
+ do_file_lock( fd, 60, F_UNLCK);
+
+ /*
+ * We have a valid SID - read it.
+ */
+
+ if(!read_sid_from_file( fd, sid_file)) {
+ DEBUG(0,("unable to read file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ close(fd);
+ return False;
+ }
+ close(fd);
+ return True;
+ }
+ }
+
+ /*
+ * The file is still empty and we have an exlusive lock on it,
+ * or we're fixing an earlier mistake.
+ * Write out out SID data into the file.
+ */
+
+ /*
+ * Use chmod here as some (strange) UNIX's don't
+ * have fchmod. JRA.
+ */
+
+ if(chmod(sid_file, 0644) < 0) {
+ DEBUG(0,("unable to set correct permissions on file %s. \
+Error was %s\n", sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
+ DEBUG(0,("unable to write file %s. Error was %s\n",
+ sid_file, strerror(errno) ));
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return False;
+ }
+
+ /*
+ * Unlock & exit.
+ */
+
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return True;
+}
+
+
diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c
new file mode 100644
index 00000000000..d44a6133f37
--- /dev/null
+++ b/source/passdb/pdb_ldap.c
@@ -0,0 +1,1033 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.9.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Shahms King 2001
+ Copyright (C) Jean François Micouleau 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+#ifdef WITH_LDAP_SAM
+/* TODO:
+* persistent connections: if using NSS LDAP, many connections are made
+* however, using only one within Samba would be nice
+*
+* Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
+*
+* Other LDAP based login attributes: accountExpires, etc.
+* (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
+* structures don't have fields for some of these attributes)
+*
+* SSL is done, but can't get the certificate based authentication to work
+* against on my test platform (Linux 2.4, OpenLDAP 2.x)
+*/
+
+/* NOTE: this will NOT work against an Active Directory server
+* due to the fact that the two password fields cannot be retrieved
+* from a server; recommend using security = domain in this situation
+* and/or winbind
+*/
+
+#include <lber.h>
+#include <ldap.h>
+
+#ifndef SAM_ACCOUNT
+#define SAM_ACCOUNT struct sam_passwd
+#endif
+
+struct ldap_enum_info
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+};
+
+static struct ldap_enum_info global_ldap_ent;
+
+
+/*******************************************************************
+ open a connection to the ldap server.
+******************************************************************/
+static BOOL
+ldap_open_connection (LDAP ** ldap_struct)
+{
+ int port;
+ int version, rc;
+ int tls = LDAP_OPT_X_TLS_HARD;
+
+ if (lp_ldap_ssl() == LDAP_SSL_ON && lp_ldap_port() == 389) {
+ port = 636;
+ }
+ else {
+ port = lp_ldap_port();
+ }
+
+ if ((*ldap_struct = ldap_init(lp_ldap_server(), port)) == NULL) {
+ DEBUG(0, ("The LDAP server is not responding !\n"));
+ return (False);
+ }
+
+ /* Connect to older servers using SSL and V2 rather than Start TLS */
+ if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version != LDAP_VERSION2)
+ {
+ version = LDAP_VERSION2;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+ }
+ }
+
+ switch (lp_ldap_ssl())
+ {
+ case LDAP_SSL_START_TLS:
+ if (ldap_get_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ }
+ }
+ if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
+ {
+ DEBUG(0,
+ ("Failed to issue the StartTLS instruction: %s\n",
+ ldap_err2string(rc)));
+ return False;
+ }
+ DEBUG (2, ("StartTLS issued: using a TLS connection\n"));
+ break;
+ case LDAP_SSL_ON:
+ if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Failed to setup a TLS session\n"));
+ }
+ break;
+ case LDAP_SSL_OFF:
+ default:
+ }
+
+ DEBUG(2, ("ldap_open_connection: connection opened\n"));
+ return (True);
+}
+
+/*******************************************************************
+ connect to the ldap server under system privilege.
+******************************************************************/
+static BOOL ldap_connect_system(LDAP * ldap_struct)
+{
+ int rc;
+ static BOOL got_pw = False;
+ static pstring ldap_secret;
+
+ /* get the password if we don't have it already */
+ if (!got_pw && !(got_pw=fetch_ldap_pw(lp_ldap_admin_dn(), ldap_secret, sizeof(pstring))))
+ {
+ DEBUG(0, ("ldap_connect_system: Failed to retrieve password for %s from secrets.tdb\n",
+ lp_ldap_admin_dn()));
+ return False;
+ }
+
+ /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
+ (OpenLDAP) doesnt' seem to support it */
+ if ((rc = ldap_simple_bind_s(ldap_struct, lp_ldap_admin_dn(),
+ ldap_secret)) != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("Bind failed: %s\n", ldap_err2string(rc)));
+ return (False);
+ }
+
+ DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+ return (True);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldap_search_one_user (LDAP * ldap_struct, const char *filter, LDAPMessage ** result)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ int rc;
+
+ DEBUG(2, ("ldap_search_one_user: searching for:[%s]\n", filter));
+
+ rc = ldap_search_s (ldap_struct, lp_ldap_suffix (), scope,
+ filter, NULL, 0, result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldap_search_one_user: Problem during the LDAP search: %s\n",
+ ldap_err2string (rc)));
+ DEBUG(3,("ldap_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(),
+ filter));
+ }
+ return (rc);
+}
+
+/*******************************************************************
+ run the search by name.
+******************************************************************/
+static int ldap_search_one_user_by_name (LDAP * ldap_struct, const char *user,
+ LDAPMessage ** result)
+{
+ pstring filter;
+
+ /*
+ in the filter expression, replace %u with the real name
+ so in ldap filter, %u MUST exist :-)
+ */
+ pstrcpy(filter, lp_ldap_filter());
+
+ /* have to use this here because $ is filtered out
+ * in pstring_sub
+ */
+ all_string_sub(filter, "%u", user, sizeof(pstring));
+
+ return ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by uid.
+******************************************************************/
+static int ldap_search_one_user_by_uid(LDAP * ldap_struct, int uid,
+ LDAPMessage ** result)
+{
+ struct passwd *user;
+ pstring filter;
+
+ /* Get the username from the system and look that up in the LDAP */
+ user = sys_getpwuid(uid);
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
+
+ return ldap_search_one_user(ldap_struct, filter, result);
+}
+
+/*******************************************************************
+ run the search by rid.
+******************************************************************/
+static int ldap_search_one_user_by_rid (LDAP * ldap_struct, uint32 rid,
+ LDAPMessage ** result)
+{
+ pstring filter;
+ int rc;
+
+ /* check if the user rid exsists, if not, try searching on the uid */
+ snprintf(filter, sizeof(filter) - 1, "rid=%i", rid);
+ rc = ldap_search_one_user(ldap_struct, filter, result);
+
+ if (rc != LDAP_SUCCESS)
+ rc = ldap_search_one_user_by_uid(ldap_struct,
+ pdb_user_rid_to_uid(rid), result);
+
+ return rc;
+}
+
+/*******************************************************************
+search an attribute and return the first value found.
+******************************************************************/
+static void get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+ char *attribute, char *value)
+{
+ char **valeurs;
+
+ if ((valeurs = ldap_get_values (ldap_struct, entry, attribute)) != NULL) {
+ pstrcpy(value, valeurs[0]);
+ ldap_value_free(valeurs);
+ DEBUG (2, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
+ }
+ else {
+ value = NULL;
+ DEBUG (2, ("get_single_attribute: [%s] = [NULL]\n", attribute));
+ }
+}
+
+/************************************************************************
+Routine to manage the LDAPMod structure array
+manage memory used by the array, by each struct, and values
+
+************************************************************************/
+static void make_a_mod (LDAPMod *** modlist, int modop, char *attribute, char *value)
+{
+ LDAPMod **mods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (attribute == NULL || *attribute == '\0')
+ return;
+
+ if (value == NULL || *value == '\0')
+ return;
+
+ if (mods == NULL)
+ {
+ mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[0] = NULL;
+ }
+
+ for (i = 0; mods[i] != NULL; ++i) {
+ if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
+ break;
+ }
+
+ if (mods[i] == NULL)
+ {
+ mods = (LDAPMod **) realloc (mods, (i + 2) * sizeof (LDAPMod *));
+ if (mods == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
+ if (mods[i] == NULL)
+ {
+ DEBUG(0, ("make_a_mod: out of memory!\n"));
+ return;
+ }
+ mods[i]->mod_op = modop;
+ mods[i]->mod_values = NULL;
+ mods[i]->mod_type = strdup(attribute);
+ mods[i + 1] = NULL;
+ }
+
+ if (value != NULL)
+ {
+ j = 0;
+ if (mods[i]->mod_values != NULL) {
+ for (; mods[i]->mod_values[j] != NULL; j++);
+ }
+ mods[i]->mod_values = (char **)realloc(mods[i]->mod_values,
+ (j + 2) * sizeof (char *));
+
+ if (mods[i]->mod_values == NULL) {
+ DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
+ return;
+ }
+ mods[i]->mod_values[j] = strdup(value);
+ mods[i]->mod_values[j + 1] = NULL;
+ }
+ *modlist = mods;
+}
+
+/* New Interface is being implemented here */
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_sam_from_buffer in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_sam_from_ldap (SAM_ACCOUNT * sampass,
+ LDAP * ldap_struct, LDAPMessage * entry)
+{
+ time_t logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ static pstring username;
+ static pstring domain;
+ static pstring nt_username;
+ static pstring fullname;
+ static pstring homedir;
+ static pstring dir_drive;
+ static pstring logon_script;
+ static pstring profile_path;
+ static pstring acct_desc;
+ static pstring munged_dial;
+ static pstring workstations;
+ struct passwd *sys_user;
+ uint32 user_rid, group_rid;
+ static uint8 smblmpwd[16];
+ static uint8 smbntpwd[16];
+ uint16 acct_ctrl, logon_divs;
+ uint32 hours_len;
+ uint8 *hours;
+ pstring temp;
+
+ get_single_attribute(ldap_struct, entry, "uid", username);
+ DEBUG(2, ("Entry found for user: %s\n", username));
+
+ pstrcpy(nt_username, username);
+
+ get_single_attribute(ldap_struct, entry, "sambaDomain", domain);
+ if (!domain)
+ pstrcpy(domain, lp_workgroup());
+
+ get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
+ pass_last_set_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logonTime", temp);
+ logon_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "logoffTime", temp);
+ logoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
+ kickoff_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
+ pass_can_change_time = (time_t) strtol(temp, NULL, 16);
+
+ get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
+ pass_must_change_time = (time_t) strtol(temp, NULL, 16);
+
+ /* recommend that 'gecos' and 'displayName' should refer to the same
+ * attribute OID. userFullName depreciated, only used by Samba
+ * primary rules of LDAP: don't make a new attribute when one is already defined
+ * that fits your needs; using gecos then displayName then cn rather than 'userFullName'
+ */
+
+ get_single_attribute(ldap_struct, entry, "gecos", fullname);
+
+ if (!fullname) {
+ get_single_attribute(ldap_struct, entry, "displayName", fullname);
+ get_single_attribute(ldap_struct, entry, "cn", fullname);
+ }
+
+ get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
+ DEBUG(5,("homeDrive is set to %s\n",dir_drive));
+ if (!*dir_drive) {
+ pstrcpy(dir_drive, lp_logon_drive());
+ DEBUG(5,("homeDrive fell back to %s\n",dir_drive));
+ }
+
+ get_single_attribute(ldap_struct, entry, "smbHome", homedir);
+ DEBUG(5,("smbHome is set to %s\n",homedir));
+ if (!*homedir) {
+ pstrcpy(homedir, lp_logon_home());
+ DEBUG(5,("smbHome fell back to %s\n",homedir));
+ }
+
+ get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
+ DEBUG(5,("scriptPath is set to %s\n",logon_script));
+ if (!*logon_script) {
+ pstrcpy(logon_script, lp_logon_script());
+ DEBUG(5,("scriptPath fell back to %s\n",logon_script));
+ }
+
+ get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
+ DEBUG(5,("profilePath is set to %s\n",profile_path));
+ if (!*profile_path) {
+ pstrcpy(profile_path, lp_logon_path());
+ DEBUG(5,("profilePath fell back to %s\n",profile_path));
+ }
+
+ get_single_attribute(ldap_struct, entry, "description", acct_desc);
+ get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
+ get_single_attribute(ldap_struct, entry, "rid", temp);
+ user_rid = (uint32)strtol(temp, NULL, 16);
+ get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
+ group_rid = (uint32)strtol(temp, NULL, 16);
+
+
+ /* These values MAY be in LDAP, but they can also be retrieved through
+ * sys_getpw*() which is how we're doing it (if you use nss_ldap, then
+ * these values will be stored in LDAP as well, but if not, we want the
+ * local values to override the LDAP for this anyway
+ * homeDirectory attribute
+ */
+ sys_user = sys_getpwnam(username);
+ if (sys_user == NULL)
+ return False;
+
+
+ /* FIXME: hours stuff should be cleaner */
+ logon_divs = 168;
+ hours_len = 21;
+ hours = malloc(sizeof(hours) * hours_len);
+ memset(hours, 0xff, hours_len);
+
+ get_single_attribute (ldap_struct, entry, "lmPassword", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "ntPassword", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ memset((char *)temp, '\0', sizeof(temp));
+ get_single_attribute (ldap_struct, entry, "acctFlags", temp);
+ acct_ctrl = pdb_decode_acct_ctrl(temp);
+
+ if (acct_ctrl == 0)
+ acct_ctrl |= ACB_NORMAL;
+
+
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_logons_divs(sampass, logon_divs);
+
+ pdb_set_uid(sampass, sys_user->pw_uid);
+ pdb_set_gid(sampass, sys_user->pw_gid);
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+
+ pdb_set_username(sampass, username);
+
+ pdb_set_domain(sampass, domain);
+ pdb_set_nt_username(sampass, nt_username);
+
+ pdb_set_fullname(sampass, fullname);
+
+ pdb_set_logon_script(sampass, logon_script);
+ pdb_set_profile_path(sampass, profile_path);
+ pdb_set_dir_drive(sampass, dir_drive);
+ pdb_set_homedir(sampass, homedir);
+ pdb_set_acct_desc(sampass, acct_desc);
+ pdb_set_workstations(sampass, workstations);
+ pdb_set_munged_dial(sampass, munged_dial);
+ if (!pdb_set_nt_passwd(sampass, smbntpwd))
+ return False;
+ if (!pdb_set_lanman_passwd(sampass, smblmpwd))
+ return False;
+
+ /* pdb_set_unknown_3(sampass, unknown3); */
+ /* pdb_set_unknown_5(sampass, unknown5); */
+ /* pdb_set_unknown_6(sampass, unknown6); */
+
+ pdb_set_hours(sampass, hours);
+
+ return True;
+}
+
+/**********************************************************************
+Initialize SAM_ACCOUNT from an LDAP query
+(Based on init_buffer_from_sam in pdb_tdb.c)
+*********************************************************************/
+static BOOL init_ldap_from_sam (LDAPMod *** mods, int ldap_state, SAM_ACCOUNT * sampass)
+{
+ pstring temp;
+
+ *mods = NULL;
+
+ /*
+ * took out adding "objectclass: sambaAccount"
+ * do this on a per-mod basis
+ */
+
+
+ make_a_mod(mods, ldap_state, "uid", pdb_get_username(sampass));
+ DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
+
+ /* not sure about using this for the nt_username */
+ make_a_mod(mods, ldap_state, "sambaDomain", pdb_get_domain(sampass));
+
+ slprintf(temp, sizeof(temp) - 1, "%i", pdb_get_uid(sampass));
+ make_a_mod(mods, ldap_state, "uidNumber", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdLastSet", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
+ make_a_mod(mods, ldap_state, "logonTime", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
+ make_a_mod(mods, ldap_state, "logoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
+ make_a_mod(mods, ldap_state, "kickoffTime", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdCanChange", temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
+ make_a_mod(mods, ldap_state, "pwdMustChange", temp);
+
+ /* displayName, cn, and gecos should all be the same
+ * most easily accomplished by giving them the same OID
+ * gecos isn't set here b/c it should be handled by the
+ * add-user script
+ */
+
+ make_a_mod(mods, ldap_state, "displayName", pdb_get_fullname(sampass));
+ make_a_mod(mods, ldap_state, "cn", pdb_get_fullname(sampass));
+
+ make_a_mod(mods, ldap_state, "smbHome", pdb_get_homedir(sampass));
+ make_a_mod(mods, ldap_state, "homeDrive", pdb_get_dirdrive(sampass));
+ make_a_mod(mods, ldap_state, "scriptPath", pdb_get_logon_script(sampass));
+ make_a_mod(mods, ldap_state, "profilePath", pdb_get_profile_path(sampass));
+ make_a_mod(mods, ldap_state, "description", pdb_get_acct_desc(sampass));
+ make_a_mod(mods, ldap_state, "userWorkstations", pdb_get_workstations(sampass));
+
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->user_rid);
+ make_a_mod(mods, ldap_state, "rid", temp);
+
+ slprintf(temp, sizeof(temp) - 1, "%i", sampass->group_rid);
+ make_a_mod(mods, ldap_state, "primaryGroupID", temp);
+
+ /* FIXME: Hours stuff goes in LDAP */
+ pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_state, "lmPassword", temp);
+ pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
+ make_a_mod (mods, ldap_state, "ntPassword", temp);
+ make_a_mod (mods, ldap_state, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ return True;
+}
+
+/**********************************************************************
+Connect to LDAP server for password enumeration
+*********************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ int rc;
+ pstring filter;
+
+ if (!ldap_open_connection(&global_ldap_ent.ldap_struct))
+ {
+ return False;
+ }
+ if (!ldap_connect_system(global_ldap_ent.ldap_struct))
+ {
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ return False;
+ }
+
+ pstrcpy(filter, lp_ldap_filter());
+ all_string_sub(filter, "%u", "*", sizeof(pstring));
+
+ rc = ldap_search_s(global_ldap_ent.ldap_struct, lp_ldap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0,
+ &global_ldap_ent.result);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
+ DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+ ldap_msgfree(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ return False;
+ }
+
+ DEBUG(2, ("pdb_setsampwent: %d entries in the base!\n",
+ ldap_count_entries(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result)));
+
+ global_ldap_ent.entry = ldap_first_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.result);
+
+ return True;
+}
+
+/**********************************************************************
+End enumeration of the LDAP password list
+*********************************************************************/
+void pdb_endsampwent(void)
+{
+ if (global_ldap_ent.ldap_struct && global_ldap_ent.result)
+ {
+ ldap_msgfree(global_ldap_ent.result);
+ ldap_unbind(global_ldap_ent.ldap_struct);
+ global_ldap_ent.ldap_struct = NULL;
+ global_ldap_ent.result = NULL;
+ }
+}
+
+/**********************************************************************
+Get the next entry in the LDAP password database
+*********************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT * user)
+{
+ if (!global_ldap_ent.entry)
+ return False;
+
+ global_ldap_ent.entry = ldap_next_entry(global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+
+ if (global_ldap_ent.entry != NULL)
+ {
+ return init_sam_from_ldap(user, global_ldap_ent.ldap_struct,
+ global_ldap_ent.entry);
+ }
+ return False;
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by username
+*********************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, char *sname)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_name(ldap_struct, sname, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this user [%s] count=%d\n", sname,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by rid
+*********************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_rid(ldap_struct, rid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this rid [%i] count=%d\n", rid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+/**********************************************************************
+ Get SAM_ACCOUNT entry from LDAP by uid
+*********************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+
+ if (!ldap_open_connection(&ldap_struct))
+ return False;
+
+ if (!ldap_connect_system(ldap_struct))
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ if (ldap_search_one_user_by_uid(ldap_struct, uid, &result) !=
+ LDAP_SUCCESS)
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (ldap_count_entries(ldap_struct, result) < 1)
+ {
+ DEBUG(0,
+ ("We don't find this uid [%i] count=%d\n", uid,
+ ldap_count_entries(ldap_struct, result)));
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ entry = ldap_first_entry(ldap_struct, result);
+ if (entry)
+ {
+ init_sam_from_ldap(user, ldap_struct, entry);
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return True;
+ }
+ else
+ {
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+}
+
+
+/**********************************************************************
+Delete entry from LDAP for username
+*********************************************************************/
+BOOL pdb_delete_sam_account(char *sname)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *entry;
+ LDAPMessage *result;
+
+ if (!ldap_open_connection (&ldap_struct))
+ return False;
+
+ DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
+
+ if (!ldap_connect_system (ldap_struct)) {
+ ldap_unbind (ldap_struct);
+ DEBUG(0, ("Failed to delete user %s from LDAP.\n", sname));
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name (ldap_struct, sname, &result);
+ if (ldap_count_entries (ldap_struct, result) == 0) {
+ DEBUG (0, ("User doesn't exit!\n"));
+ ldap_msgfree (result);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ entry = ldap_first_entry (ldap_struct, result);
+ dn = ldap_get_dn (ldap_struct, entry);
+
+ rc = ldap_delete_s (ldap_struct, dn);
+
+ ldap_memfree (dn);
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error;
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG (0,("failed to delete user with uid = %s with: %s\n\t%s\n",
+ sname, ldap_err2string (rc), ld_error));
+ free (ld_error);
+ ldap_unbind (ldap_struct);
+ return False;
+ }
+
+ DEBUG (2,("successfully deleted uid = %s from the LDAP database\n", sname));
+ ldap_unbind (ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Update SAM_ACCOUNT
+*********************************************************************/
+BOOL pdb_update_sam_account(SAM_ACCOUNT * newpwd, BOOL override)
+{
+ int rc;
+ char *dn;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ LDAPMessage *entry;
+ LDAPMod **mods;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ return False;
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ rc = ldap_search_one_user_by_name(ldap_struct,
+ pdb_get_username(newpwd), &result);
+
+ if (ldap_count_entries(ldap_struct, result) == 0)
+ {
+ DEBUG(0, ("No user to modify!\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ init_ldap_from_sam(&mods, LDAP_MOD_REPLACE, newpwd);
+
+ entry = ldap_first_entry(ldap_struct, result);
+ dn = ldap_get_dn(ldap_struct, entry);
+
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+ ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,
+ ("failed to modify user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string(rc),
+ ld_error));
+ free(ld_error);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,
+ ("successfully modified uid = %s in the LDAP database\n",
+ pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+/**********************************************************************
+Add SAM_ACCOUNT to LDAP
+*********************************************************************/
+BOOL pdb_add_sam_account(SAM_ACCOUNT * newpwd)
+{
+ int rc;
+ pstring filter;
+ LDAP *ldap_struct;
+ LDAPMessage *result;
+ pstring dn;
+ LDAPMod **mods;
+ int ldap_op = LDAP_MOD_ADD;
+
+ if (!ldap_open_connection(&ldap_struct)) /* open a connection to the server */
+ {
+ return False;
+ }
+
+ if (!ldap_connect_system(ldap_struct)) /* connect as system account */
+ {
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ if (pdb_get_username(newpwd) != NULL) {
+ slprintf (dn, sizeof (dn) - 1, "uid=%s,%s",
+ pdb_get_username(newpwd), lp_ldap_suffix ());
+ }
+ else
+ {
+ return False;
+ }
+
+
+ rc = ldap_search_one_user_by_name (ldap_struct, pdb_get_username(newpwd), &result);
+
+ if (ldap_count_entries(ldap_struct, result) != 0)
+ {
+ DEBUG(0,("User already in the base, with samba properties\n"));
+ ldap_msgfree(result);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+ ldap_msgfree(result);
+
+ slprintf (filter, sizeof (filter) - 1, "uid=%s", pdb_get_username(newpwd));
+ rc = ldap_search_one_user(ldap_struct, filter, &result);
+ if (ldap_count_entries(ldap_struct, result) == 1)
+ {
+ char *tmp;
+ LDAPMessage *entry;
+ DEBUG(3,("User exists without samba properties: adding them\n"));
+ ldap_op = LDAP_MOD_REPLACE;
+ entry = ldap_first_entry (ldap_struct, result);
+ tmp = ldap_get_dn (ldap_struct, entry);
+ slprintf (dn, sizeof (dn) - 1, "%s", tmp);
+ ldap_memfree (tmp);
+ }
+ else
+ {
+ DEBUG (3, ("More than one user with that uid exists: bailing out!\n"));
+ return False;
+ }
+
+ ldap_msgfree(result);
+
+ init_ldap_from_sam(&mods, ldap_op, newpwd);
+ make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
+
+ if (ldap_op == LDAP_MOD_REPLACE) {
+ rc = ldap_modify_s(ldap_struct, dn, mods);
+ }
+ else {
+ rc = ldap_add_s(ldap_struct, dn, mods);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ {
+ char *ld_error;
+
+ ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(0,("failed to modify user with uid = %s with: %s\n\t%s\n",
+ pdb_get_username(newpwd), ldap_err2string (rc), ld_error));
+ free(ld_error);
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return False;
+ }
+
+ DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
+ ldap_mods_free(mods, 1);
+ ldap_unbind(ldap_struct);
+ return True;
+}
+
+#else
+void dummy_function(void);
+void
+dummy_function (void)
+{
+} /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/pdb_nisplus.c b/source/passdb/pdb_nisplus.c
new file mode 100644
index 00000000000..a86d5ecb680
--- /dev/null
+++ b/source/passdb/pdb_nisplus.c
@@ -0,0 +1,1404 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se>
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
+ * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_NISPLUS_SAM
+
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
+
+#if defined(GROUP)
+#undef GROUP
+#endif
+
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
+
+#endif
+
+#include <rpcsvc/nis.h>
+
+extern int DEBUGLEVEL;
+extern pstring samlogon_user;
+extern BOOL sam_logon_in_ssb;
+
+struct nisp_enum_info
+{
+ nis_result *result;
+ int enum_entry;
+};
+
+static struct nisp_enum_info global_nisp_ent;
+static VOLATILE sig_atomic_t gotalarm;
+
+/***************************************************************
+
+ the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
+
+ name=S,nogw=r
+ uid=S,nogw=r
+ user_rid=S,nogw=r
+ smb_grpid=,nw+r
+ group_rid=,nw+r
+ acb=,nw+r
+
+ lmpwd=C,nw=,g=r,o=rm
+ ntpwd=C,nw=,g=r,o=rm
+
+ logon_t=,nw+r
+ logoff_t=,nw+r
+ kick_t=,nw+r
+ pwdlset_t=,nw+r
+ pwdlchg_t=,nw+r
+ pwdmchg_t=,nw+r
+
+ full_name=,nw+r
+ home_dir=,nw+r
+ dir_drive=,nw+r
+ logon_script=,nw+r
+ profile_path=,nw+r
+ acct_desc=,nw+r
+ workstations=,nw+r
+
+ hours=,nw+r
+
+****************************************************************/
+
+#define NPF_NAME 0
+#define NPF_UID 1
+#define NPF_USER_RID 2
+#define NPF_SMB_GRPID 3
+#define NPF_GROUP_RID 4
+#define NPF_ACB 5
+#define NPF_LMPWD 6
+#define NPF_NTPWD 7
+#define NPF_LOGON_T 8
+#define NPF_LOGOFF_T 9
+#define NPF_KICK_T 10
+#define NPF_PWDLSET_T 11
+#define NPF_PWDCCHG_T 12
+#define NPF_PWDMCHG_T 13
+#define NPF_FULL_NAME 14
+#define NPF_HOME_DIR 15
+#define NPF_DIR_DRIVE 16
+#define NPF_LOGON_SCRIPT 17
+#define NPF_PROFILE_PATH 18
+#define NPF_ACCT_DESC 19
+#define NPF_WORKSTATIONS 20
+#define NPF_HOURS 21
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ make_nisname_from_user_rid
+ ****************************************************************/
+static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_uid
+ ****************************************************************/
+static char *make_nisname_from_uid(int uid, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
+ slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/***************************************************************
+ make_nisname_from_name
+ ****************************************************************/
+static char *make_nisname_from_name(char *user_name, char *pfile)
+{
+ static pstring nisname;
+
+ safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
+ safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
+ safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
+ safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
+
+ return nisname;
+}
+
+/*************************************************************************
+ gets a NIS+ attribute
+ *************************************************************************/
+static void get_single_attribute(nis_object *new_obj, int col,
+ char *val, int len)
+{
+ int entry_len;
+
+ if (new_obj == NULL || val == NULL) return;
+
+ entry_len = ENTRY_LEN(new_obj, col);
+ if (len > entry_len)
+ {
+ len = entry_len;
+ }
+
+ safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ object.
+ ************************************************************************/
+static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, nis_object *obj)
+{
+ char *ptr;
+ pstring full_name; /* this must be translated to dos code page */
+ pstring acct_desc; /* this must be translated to dos code page */
+ pstring home_dir; /* set default value from smb.conf for user */
+ pstring home_drive; /* set default value from smb.conf for user */
+ pstring logon_script; /* set default value from smb.conf for user */
+ pstring profile_path; /* set default value from smb.conf for user */
+ pstring hours;
+ int hours_len;
+ unsigned char smbpwd[16];
+ unsigned char smbntpwd[16];
+
+
+ /*
+ * time values. note: this code assumes 32bit time_t!
+ */
+
+ /* Don't change these timestamp settings without a good reason. They are
+ important for NT member server compatibility. */
+
+ pdb_set_logon_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGON_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_logoff_time(pw_buf, get_time_t_max());
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_LOGOFF_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_kickoff_time(pw_buf, get_time_t_max());
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_KICK_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_last_set_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDLSET_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_can_change_time(pw_buf, (time_t)0);
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDCCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
+ ptr = (uchar *)ENTRY_VAL(obj, NPF_PWDMCHG_T);
+ if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
+ int i;
+ ptr += 4;
+ for(i = 0; i < 8; i++) {
+ if(ptr[i] == '\0' || !isxdigit(ptr[i]))
+ break;
+ }
+ if(i == 8) {
+ pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
+ }
+ }
+
+ /* string values */
+ pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
+ pdb_set_domain(pw_buf, lp_workgroup());
+ /* pdb_set_nt_username() -- cant set it here... */
+
+ get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
+ unix_to_dos(full_name, True);
+ pdb_set_fullname(pw_buf, full_name);
+
+ pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
+ NPF_ACB)));
+
+ get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
+ unix_to_dos(acct_desc, True);
+ pdb_set_acct_desc(pw_buf, acct_desc);
+
+ pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
+ pdb_set_munged_dial(pw_buf, NULL);
+
+ pdb_set_uid(pw_buf, atoi(ENTRY_VAL(obj, NPF_UID)));
+ pdb_set_gid(pw_buf, atoi(ENTRY_VAL(obj, NPF_SMB_GRPID)));
+ pdb_set_user_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_USER_RID)));
+ pdb_set_group_rid(pw_buf, atoi(ENTRY_VAL(obj, NPF_GROUP_RID)));
+
+ /* values, must exist for user */
+ if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
+ /* FIXME!! This doesn't belong here.
+ Should be set in net_sam_logon()
+ --jerry */
+ pstrcpy(samlogon_user, pdb_get_username(pw_buf));
+
+ get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
+ if( !(home_dir && *home_dir) )
+ pstrcpy(home_dir, lp_logon_home());
+ pdb_set_homedir(pw_buf, home_dir);
+
+ get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
+ if( !(home_drive && *home_drive) )
+ pstrcpy(home_drive, lp_logon_drive());
+ pdb_set_dir_drive(pw_buf, home_drive);
+
+ get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
+ sizeof(pstring));
+ if( !(logon_script && *logon_script) )
+ pstrcpy(logon_script, lp_logon_script());
+ pdb_set_logon_script(pw_buf, logon_script);
+
+ get_single_attribute(obj, NPF_PROFILE_PATH, profile_path,
+ sizeof(pstring));
+ if( !(profile_path && *profile_path) )
+ pstrcpy(profile_path, lp_logon_path());
+ pdb_set_profile_path(pw_buf, profile_path);
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS);
+ }
+
+ /* Check the lanman password column. */
+ ptr = (char *)ENTRY_VAL(obj, NPF_LMPWD);
+ pdb_set_lanman_passwd(pw_buf, NULL);
+
+ if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
+ pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
+ } else {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
+ DEBUG(0, ("malformed LM pwd entry: %s.\n",
+ pdb_get_username(pw_buf)));
+ return False;
+ }
+ pdb_set_lanman_passwd(pw_buf, smbpwd);
+ }
+
+ /* Check the NT password column. */
+ ptr = ENTRY_VAL(obj, NPF_NTPWD);
+ pdb_set_nt_passwd(pw_buf, NULL);
+
+ if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
+ strncasecmp(ptr, "NO PASSWORD", 11)) {
+ if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
+ DEBUG(0, ("malformed NT pwd entry:
+ uid = %d.\n",
+ pdb_get_uid(pw_buf)));
+ return False;
+ }
+ pdb_set_nt_passwd(pw_buf, smbntpwd);
+ }
+
+ pdb_set_unknown_3(pw_buf, 0xffffff); /* don't know */
+ pdb_set_logons_divs(pw_buf, 168); /* hours per week */
+
+ if( (hours_len = ENTRY_LEN(obj, NPF_HOURS)) == 21 ) {
+ memcpy(hours, ENTRY_VAL(obj, NPF_HOURS), hours_len);
+ } else {
+ hours_len = 21; /* 21 times 8 bits = 168 */
+ /* available at all hours */
+ memset(hours, 0xff, hours_len);
+ }
+ pdb_set_hours_len(pw_buf, hours_len);
+ pdb_set_hours(pw_buf, hours);
+
+ pdb_set_unknown_5(pw_buf, 0x00020000); /* don't know */
+ pdb_set_unknown_6(pw_buf, 0x000004ec); /* don't know */
+
+ return True;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisresult(SAM_ACCOUNT *pw_buf, nis_result *result)
+{
+ if (pw_buf == NULL || result == NULL) return False;
+
+ if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
+ {
+ DEBUG(0, ("NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("WARNING: Multiple entries for user in NIS+ table!\n"));
+ }
+
+ /* Grab the first hit. */
+ return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
+}
+
+/*************************************************************************
+ sets a NIS+ attribute
+ *************************************************************************/
+static void set_single_attribute(nis_object *new_obj, int col,
+ char *val, int len, int flags)
+{
+ if (new_obj == NULL) return;
+
+ ENTRY_VAL(new_obj, col) = val;
+ ENTRY_LEN(new_obj, col) = len+1;
+
+ if (flags != 0)
+ {
+ new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
+ }
+}
+
+/***************************************************************
+ copy or modify nis object. this object is used to add or update
+ nisplus table entry.
+ ****************************************************************/
+static BOOL init_nisp_from_sam(nis_object *obj, SAM_ACCOUNT *sampass,
+ nis_object *old)
+{
+ /*
+ * Fill nis_object for entry add or update.
+ * if we are updateing, we have to find out differences and set
+ * EN_MODIFIED flag. also set need_to_modify to trigger
+ * nis_modify_entry() call in pdb_update_sam_account().
+ *
+ * TODO:
+ * get data from SAM
+ * if (modify) get data from nis_object, compare and store if
+ * different + set EN_MODIFIED and need_to_modify
+ * else
+ * store
+ */
+ BOOL need_to_modify = False;
+ char *name; /* from SAM */
+ /* these must be static or allocate and free entry columns! */
+ static fstring uid; /* from SAM */
+ static fstring user_rid; /* from SAM */
+ static fstring gid; /* from SAM */
+ static fstring group_rid; /* from SAM */
+ char *acb; /* from SAM */
+ static fstring smb_passwd; /* from SAM */
+ static fstring smb_nt_passwd; /* from SAM */
+ static fstring logon_t; /* from SAM */
+ static fstring logoff_t; /* from SAM */
+ static fstring kickoff_t; /* from SAM */
+ static fstring pwdlset_t; /* from SAM */
+ static fstring pwdlchg_t; /* from SAM */
+ static fstring pwdmchg_t; /* from SAM */
+ static fstring full_name; /* from SAM */
+ static fstring acct_desc; /* from SAM */
+ static char empty[1]; /* just an empty string */
+
+
+ name = pdb_get_username(sampass);
+ slprintf(uid, sizeof(uid)-1, "%u", pdb_get_uid(sampass));
+ slprintf(user_rid, sizeof(user_rid)-1, "%u",
+ pdb_get_user_rid(sampass)? pdb_get_user_rid(sampass):
+ pdb_uid_to_user_rid(pdb_get_uid(sampass)));
+ slprintf(gid, sizeof(gid)-1, "%u", pdb_get_gid(sampass));
+ slprintf(group_rid, sizeof(group_rid)-1, "%u",
+ pdb_get_group_rid(sampass)? pdb_get_group_rid(sampass):
+ pdb_gid_to_group_rid(pdb_get_gid(sampass)));
+ acb = pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sampass),
+ NEW_PW_FORMAT_SPACE_PADDED_LEN);
+ pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd(sampass),
+ pdb_get_acct_ctrl(sampass));
+ slprintf(logon_t, 13, "LNT-%08X",
+ (uint32)pdb_get_logon_time(sampass));
+ slprintf(logoff_t, 13, "LOT-%08X",
+ (uint32)pdb_get_logoff_time(sampass));
+ slprintf(kickoff_t, 13, "KOT-%08X",
+ (uint32)pdb_get_kickoff_time(sampass));
+ slprintf(pwdlset_t, 13, "LCT-%08X",
+ (uint32)pdb_get_pass_last_set_time(sampass));
+ slprintf(pwdlchg_t, 13, "CCT-%08X",
+ (uint32)pdb_get_pass_can_change_time(sampass));
+ slprintf(pwdmchg_t, 13, "MCT-%08X",
+ (uint32)pdb_get_pass_must_change_time(sampass));
+ safe_strcpy(full_name, pdb_get_fullname(sampass), sizeof(full_name)-1);
+ dos_to_unix(full_name, True);
+ safe_strcpy(acct_desc, pdb_get_acct_desc(sampass), sizeof(acct_desc)-1);
+ dos_to_unix(acct_desc, True);
+
+ if( old ) {
+ /* name */
+ if(strcmp(ENTRY_VAL(old, NPF_NAME), name))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NAME, name, strlen(name),
+ EN_MODIFIED);
+ }
+
+
+ /* uid */
+ if(pdb_get_uid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_UID) || strcmp(ENTRY_VAL(old, NPF_UID), uid))
+ {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_UID, uid,
+ strlen(uid), EN_MODIFIED);
+ }
+ }
+
+ /* user_rid */
+ if (pdb_get_user_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_USER_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_USER_RID), user_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), EN_MODIFIED);
+ }
+ }
+
+ /* smb_grpid */
+ if (pdb_get_gid(sampass) != -1) {
+ if(!ENTRY_VAL(old, NPF_SMB_GRPID) ||
+ strcmp(ENTRY_VAL(old, NPF_SMB_GRPID), gid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_SMB_GRPID, gid,
+ strlen(gid), EN_MODIFIED);
+ }
+ }
+
+ /* group_rid */
+ if (pdb_get_group_rid(sampass)) {
+ if(!ENTRY_VAL(old, NPF_GROUP_RID) ||
+ strcmp(ENTRY_VAL(old, NPF_GROUP_RID), group_rid) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), EN_MODIFIED);
+ }
+ }
+
+ /* acb */
+ if (!ENTRY_VAL(old, NPF_ACB) ||
+ strcmp(ENTRY_VAL(old, NPF_ACB), acb)) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), EN_MODIFIED);
+ }
+
+ /* lmpwd */
+ if(!ENTRY_VAL(old, NPF_LMPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_LMPWD), smb_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* ntpwd */
+ if(!ENTRY_VAL(old, NPF_NTPWD) ||
+ strcmp(ENTRY_VAL(old, NPF_NTPWD), smb_nt_passwd) ) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT|EN_MODIFIED);
+ }
+
+ /* logon_t */
+ if( pdb_get_logon_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGON_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGON_T), logon_t ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), EN_MODIFIED);
+ }
+
+ /* logoff_t */
+ if( pdb_get_logoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_LOGOFF_T) ||
+ strcmp(ENTRY_VAL(old, NPF_LOGOFF_T), logoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), EN_MODIFIED);
+ }
+
+ /* kick_t */
+ if( pdb_get_kickoff_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_KICK_T) ||
+ strcmp(ENTRY_VAL(old, NPF_KICK_T), kickoff_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t), EN_MODIFIED);
+ }
+
+ /* pwdlset_t */
+ if( pdb_get_pass_last_set_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDLSET_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDLSET_T), pwdlset_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), EN_MODIFIED);
+ }
+
+ /* pwdlchg_t */
+ if( pdb_get_pass_can_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDCCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDCCHG_T), pwdlchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), EN_MODIFIED);
+ }
+
+ /* pwdmchg_t */
+ if( pdb_get_pass_must_change_time(sampass) &&
+ (!ENTRY_VAL(old, NPF_PWDMCHG_T) ||
+ strcmp(ENTRY_VAL(old, NPF_PWDMCHG_T), pwdmchg_t))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), EN_MODIFIED);
+ }
+
+ /* full_name */
+ /* must support set, unset and change */
+ if ( (pdb_get_fullname(sampass) &&
+ !ENTRY_VAL(old, NPF_FULL_NAME)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ !pdb_get_fullname(sampass)) ||
+ (ENTRY_VAL(old, NPF_FULL_NAME) &&
+ pdb_get_fullname(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_FULL_NAME), full_name ))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_FULL_NAME, full_name,
+ strlen(full_name), EN_MODIFIED);
+ }
+
+ /* home_dir */
+ /* must support set, unset and change */
+ if( (pdb_get_homedir(sampass) &&
+ !ENTRY_VAL(old, NPF_HOME_DIR)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ !pdb_get_homedir(sampass)) ||
+ (ENTRY_VAL(old, NPF_HOME_DIR) &&
+ pdb_get_homedir(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_HOME_DIR),
+ pdb_get_homedir(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_HOME_DIR, pdb_get_homedir(sampass),
+ strlen(pdb_get_homedir(sampass)), EN_MODIFIED);
+ }
+
+ /* dir_drive */
+ /* must support set, unset and change */
+ if( (pdb_get_dirdrive(sampass) &&
+ !ENTRY_VAL(old, NPF_DIR_DRIVE)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ !pdb_get_dirdrive(sampass)) ||
+ (ENTRY_VAL(old, NPF_DIR_DRIVE) &&
+ pdb_get_dirdrive(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_DIR_DRIVE),
+ pdb_get_dirdrive(sampass)))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_DIR_DRIVE, pdb_get_dirdrive(sampass),
+ strlen(pdb_get_dirdrive(sampass)), EN_MODIFIED);
+ }
+
+ /* logon_script */
+ /* must support set, unset and change */
+ if( (pdb_get_logon_script(sampass) &&
+ !ENTRY_VAL(old, NPF_LOGON_SCRIPT) ||
+ (ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ !pdb_get_logon_script(sampass)) ||
+ ( ENTRY_VAL(old, NPF_LOGON_SCRIPT) &&
+ pdb_get_logon_script(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_LOGON_SCRIPT),
+ pdb_get_logon_script(sampass))))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ pdb_get_logon_script(sampass),
+ strlen(pdb_get_logon_script(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* profile_path */
+ /* must support set, unset and change */
+ if( (pdb_get_profile_path(sampass) &&
+ !ENTRY_VAL(old, NPF_PROFILE_PATH)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ !pdb_get_profile_path(sampass)) ||
+ (ENTRY_VAL(old, NPF_PROFILE_PATH) &&
+ pdb_get_profile_path(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_PROFILE_PATH),
+ pdb_get_profile_path(sampass) ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ pdb_get_profile_path(sampass),
+ strlen(pdb_get_profile_path(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* acct_desc */
+ /* must support set, unset and change */
+ if( (pdb_get_acct_desc(sampass) &&
+ !ENTRY_VAL(old, NPF_ACCT_DESC)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ !pdb_get_acct_desc(sampass)) ||
+ (ENTRY_VAL(old, NPF_ACCT_DESC) &&
+ pdb_get_acct_desc(sampass) &&
+ strcmp( ENTRY_VAL(old, NPF_ACCT_DESC), acct_desc ) )) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_ACCT_DESC, acct_desc,
+ strlen(acct_desc), EN_MODIFIED);
+ }
+
+ /* workstations */
+ /* must support set, unset and change */
+ if ( (pdb_get_workstations(sampass) &&
+ !ENTRY_VAL(old, NPF_WORKSTATIONS) ) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ !pdb_get_workstations(sampass)) ||
+ (ENTRY_VAL(old, NPF_WORKSTATIONS) &&
+ pdb_get_workstations(sampass)) &&
+ strcmp( ENTRY_VAL(old, NPF_WORKSTATIONS),
+ pdb_get_workstations(sampass))) {
+ need_to_modify = True;
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ pdb_get_workstations(sampass),
+ strlen(pdb_get_workstations(sampass)),
+ EN_MODIFIED);
+ }
+
+ /* hours */
+ if ((pdb_get_hours_len(sampass) != ENTRY_LEN(old, NPF_HOURS)) ||
+ memcmp(pdb_get_hours(sampass), ENTRY_VAL(old, NPF_HOURS),
+ ENTRY_LEN(old, NPF_HOURS))) {
+ need_to_modify = True;
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS, pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, EN_MODIFIED);
+ }
+ } else {
+ char *homedir, *dirdrive, *logon_script, *profile_path, *workstations;
+
+ *empty = '\0'; /* empty string */
+
+ set_single_attribute(obj, NPF_NAME, name, strlen(name), 0);
+ set_single_attribute(obj, NPF_UID, uid, strlen(uid), 0);
+ set_single_attribute(obj, NPF_USER_RID, user_rid,
+ strlen(user_rid), 0);
+ set_single_attribute(obj, NPF_SMB_GRPID, gid, strlen(gid), 0);
+ set_single_attribute(obj, NPF_GROUP_RID, group_rid,
+ strlen(group_rid), 0);
+ set_single_attribute(obj, NPF_ACB, acb, strlen(acb), 0);
+ set_single_attribute(obj, NPF_LMPWD, smb_passwd,
+ strlen(smb_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_NTPWD, smb_nt_passwd,
+ strlen(smb_nt_passwd), EN_CRYPT);
+ set_single_attribute(obj, NPF_LOGON_T, logon_t,
+ strlen(logon_t), 0);
+ set_single_attribute(obj, NPF_LOGOFF_T, logoff_t,
+ strlen(logoff_t), 0);
+ set_single_attribute(obj, NPF_KICK_T, kickoff_t,
+ strlen(kickoff_t),0);
+ set_single_attribute(obj, NPF_PWDLSET_T, pwdlset_t,
+ strlen(pwdlset_t), 0);
+ set_single_attribute(obj, NPF_PWDCCHG_T, pwdlchg_t,
+ strlen(pwdlchg_t), 0);
+ set_single_attribute(obj, NPF_PWDMCHG_T, pwdmchg_t,
+ strlen(pwdmchg_t), 0);
+ set_single_attribute(obj, NPF_FULL_NAME ,
+ full_name, strlen(full_name), 0);
+
+ if(!(homedir = pdb_get_homedir(sampass)))
+ homedir = empty;
+
+ set_single_attribute(obj, NPF_HOME_DIR,
+ homedir, strlen(homedir), 0);
+
+ if(!(dirdrive = pdb_get_dirdrive(sampass)))
+ dirdrive = empty;
+
+ set_single_attribute(obj, NPF_DIR_DRIVE,
+ dirdrive, strlen(dirdrive), 0);
+
+ if(!(logon_script = pdb_get_logon_script(sampass)))
+ logon_script = empty;
+
+ set_single_attribute(obj, NPF_LOGON_SCRIPT,
+ logon_script, strlen(logon_script), 0);
+
+ if(!(profile_path = pdb_get_profile_path(sampass)))
+ profile_path = empty;
+
+ set_single_attribute(obj, NPF_PROFILE_PATH,
+ profile_path, strlen(profile_path), 0);
+
+ set_single_attribute(obj, NPF_ACCT_DESC,
+ acct_desc, strlen(acct_desc), 0);
+
+ if(!(workstations = pdb_get_workstations(sampass)))
+ workstations = empty;
+
+ set_single_attribute(obj, NPF_WORKSTATIONS,
+ workstations, strlen(workstations), 0);
+
+ /* set_single_attribute will add 1 for len ... */
+ set_single_attribute(obj, NPF_HOURS,
+ pdb_get_hours(sampass),
+ pdb_get_hours_len(sampass)-1, 0);
+ }
+
+ return need_to_modify;
+}
+
+/***************************************************************
+ calls nis_list, returns results.
+ ****************************************************************/
+static nis_result *nisp_get_nis_list(char *nis_name, uint_t flags)
+{
+ nis_result *result;
+ int i;
+
+ if( ! flags)
+ flags = FOLLOW_LINKS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP;
+
+ for(i = 0; i<2;i++ ) {
+ alarm(60); /* hopefully ok for long searches */
+ result = nis_list(nis_name, flags,NULL,NULL);
+
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
+
+ if (gotalarm)
+ {
+ DEBUG(0,("NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+ if( !(flags & MASTER_ONLY) && NIS_RES_NUMOBJ(result) <= 0 ) {
+ /* nis replicas are not in sync perhaps?
+ * this can happen, if account was just added.
+ */
+ DEBUG(10,("will try master only\n"));
+ nis_freeresult(result);
+ flags |= MASTER_ONLY;
+ } else
+ break;
+ }
+ return result;
+}
+
+/***************************************************************
+ Start to enumerate the nisplus passwd list.
+ ****************************************************************/
+BOOL pdb_setsampwent(BOOL update)
+{
+ char *sp, * p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ pdb_endsampwent(); /* just in case */
+ global_nisp_ent.result = nisp_get_nis_list( pfiletmp, 0 );
+ global_nisp_ent.enum_entry = 0;
+ return global_nisp_ent.result != NULL ? True : False;
+}
+
+/***************************************************************
+ End enumeration of the nisplus passwd list.
+****************************************************************/
+void pdb_endsampwent(void)
+{
+ if( global_nisp_ent.result )
+ nis_freeresult(global_nisp_ent.result);
+ global_nisp_ent.result = NULL;
+ global_nisp_ent.enum_entry = 0;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+ *************************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ int enum_entry = (int)(global_nisp_ent.enum_entry);
+ nis_result *result = global_nisp_ent.result;
+
+ if (user==NULL) {
+ DEBUG(0,("SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ if (result == NULL ||
+ enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ(result) - 1))
+ {
+ return False;
+ }
+
+ if(!make_sam_from_nisp_object(user, &NIS_RES_OBJECT(result)[enum_entry]) )
+ {
+ DEBUG(0,("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
+ return False;
+ }
+ (int)(global_nisp_ent.enum_entry)++;
+ return True;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT * user, char *sname)
+{
+ /* Static buffers we will return. */
+ nis_result *result = NULL;
+ pstring nisname;
+ BOOL ret;
+ char *pfile = lp_smb_passwd_file();
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+ DEBUG(10, ("search by nisname: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwrid(SAM_ACCOUNT * user, uint32 rid)
+{
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+ char *sp, *p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if (!*p)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ nisname = make_nisname_from_user_rid(rid, pfiletmp);
+
+ DEBUG(10, ("search by rid: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to search the nisplus passwd file for an entry matching the username
+ *************************************************************************/
+BOOL pdb_getsampwuid(SAM_ACCOUNT * user, uid_t uid)
+{
+ nis_result *result;
+ char *nisname;
+ BOOL ret;
+ char *sp, *p = lp_smb_passwd_file();
+ pstring pfiletmp;
+
+ if (!*p)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+
+ if( (sp = strrchr( p, '/' )) )
+ safe_strcpy(pfiletmp, sp+1, sizeof(pfiletmp)-1);
+ else
+ safe_strcpy(pfiletmp, p, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ nisname = make_nisname_from_uid(uid, pfiletmp);
+
+ DEBUG(10, ("search by uid: %s\n", nisname));
+
+ /* Search the table. */
+
+ if(!(result = nisp_get_nis_list(nisname, 0)))
+ {
+ return False;
+ }
+
+ ret = make_sam_from_nisresult(user, result);
+ nis_freeresult(result);
+
+ return ret;
+}
+
+/*************************************************************************
+ Routine to remove entry from the nisplus smbpasswd table
+ *************************************************************************/
+BOOL pdb_delete_sam_account(char *sname)
+{
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ nis_result *result, *delresult;
+ nis_object *obj;
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir", sname, pfile);
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s", sname, obj->zo_name,
+ obj->zo_domain);
+
+ DEBUG(10, ("removing name: %s\n", nisname));
+ delresult = nis_remove_entry(nisname, obj,
+ MASTER_ONLY|REM_MULTIPLE|ALL_RESULTS|FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+
+ nis_freeresult(result);
+
+ if(delresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(delresult->status)));
+ nis_freeresult(delresult);
+ return False;
+ }
+ nis_freeresult(delresult);
+ return True;
+}
+
+/************************************************************************
+ Routine to add an entry to the nisplus passwd file.
+*************************************************************************/
+BOOL pdb_add_sam_account(SAM_ACCOUNT * newpwd)
+{
+ int local_user = 0;
+ char *pfile;
+ pstring pfiletmp;
+ char *nisname;
+ nis_result *result = NULL,
+ *tblresult = NULL;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+
+ /*
+ * 1. find user domain.
+ * a. try nis search in passwd.org_dir - if found use domain from result.
+ * b. try getpwnam. this may be needed if user is defined
+ * in /etc/passwd file (or elsewere) and not in passwd.org_dir.
+ * if found, use host default domain.
+ * c. exit with False - no such user.
+ *
+ * 2. add user
+ * a. find smbpasswd table
+ * search pfile in user domain if not found, try host default
+ * domain.
+ * b. smbpasswd domain is found, fill data and add entry.
+ *
+ * pfile should contain ONLY table name, org_dir will be concated.
+ * so, at first we will clear path prefix from pfile, and
+ * then we will use pfiletmp as playground to put together full
+ * nisname string.
+ * such approach will make it possible to specify samba private dir
+ * AND still use NIS+ table. as all domain related data is normally
+ * stored in org_dir.DOMAIN, this should be ok do do.
+ */
+
+ pfile = lp_smb_passwd_file();
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ /*
+ * Check if user is already there.
+ */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+
+ if(pdb_get_username(newpwd) != NULL) {
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ pfiletmp);
+ } else {
+ return False;
+ }
+
+ if(!(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+ if (result->status != NIS_SUCCESS &&
+ result->status != NIS_NOTFOUND) {
+ DEBUG(3, ( "nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
+ {
+ DEBUG(3, ("User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(result); /* no such user, free results */
+
+ /*
+ * check for user in unix password database. we need this to get
+ * domain, where smbpasswd entry should be stored.
+ */
+
+ nisname = make_nisname_from_name(pdb_get_username(newpwd),
+ "passwd.org_dir");
+
+ result = nisp_get_nis_list(nisname,
+ MASTER_ONLY|FOLLOW_LINKS|FOLLOW_PATH|\
+ EXPAND_NAME|HARD_LOOKUP);
+
+ if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(3, ("nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(result);
+
+ if (!sys_getpwnam(pdb_get_username(newpwd))) {
+ /* no such user in system! */
+ return False;
+ }
+ /*
+ * user is defined, but not in passwd.org_dir.
+ */
+ local_user = 1;
+ } else {
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(result)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ nis_freeresult(result); /* not needed any more */
+
+ tblresult = nisp_get_nis_list(pfiletmp,
+ MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ }
+
+ if (local_user || tblresult->status != NIS_SUCCESS)
+ {
+ /*
+ * no user domain or
+ * smbpasswd table not found in user domain, fallback to
+ * default domain.
+ */
+ if (!local_user) /* free previous failed search result */
+ nis_freeresult(tblresult);
+
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".org_dir",
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ tblresult = nis_lookup(pfiletmp, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP);
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ /* still nothing. bail out */
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "nis_lookup failure: %s\n",
+ nis_sperrno(tblresult->status)));
+ return False;
+ }
+ /* we need full name for nis_add_entry() */
+ safe_strcpy(pfiletmp, pfile, sizeof(pfiletmp)-1);
+ safe_strcat(pfiletmp, ".", sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ safe_strcat(pfiletmp, NIS_RES_OBJECT(tblresult)->zo_domain,
+ sizeof(pfiletmp)-strlen(pfiletmp)-1);
+ }
+
+ memset((char *)&new_obj, 0, sizeof (new_obj));
+ /* fill entry headers */
+ /* we do not free these. */
+ new_obj.zo_name = NIS_RES_OBJECT(tblresult)->zo_name;
+ new_obj.zo_owner = NIS_RES_OBJECT(tblresult)->zo_owner;
+ new_obj.zo_group = NIS_RES_OBJECT(tblresult)->zo_group;
+ new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
+ /* uints */
+ new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
+ new_obj.zo_ttl = NIS_RES_OBJECT(tblresult)->zo_ttl;
+
+ new_obj.zo_data.zo_type = ENTRY_OBJ;
+ new_obj.EN_data.en_type =
+ NIS_RES_OBJECT(tblresult)->TA_data.ta_type;
+
+ ta_maxcol = NIS_RES_OBJECT(tblresult)->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(tblresult);
+ return False;
+ }
+
+ memset((char *)ecol, 0, ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ init_nisp_from_sam(&new_obj, newpwd, NULL);
+
+ DEBUG(10, ( "add NIS+ entry: %s\n", nisname));
+ result = nis_add_entry(pfiletmp, &new_obj, 0);
+
+ free(ecol); /* free allocated entry space */
+
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ nis_freeresult(tblresult);
+ nis_freeresult(result);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to modify the nisplus passwd entry.
+************************************************************************/
+BOOL pdb_update_sam_account(SAM_ACCOUNT * newpwd, BOOL override)
+{
+ nis_result *result, *addresult;
+ nis_object *obj;
+ nis_object new_obj;
+ entry_col *ecol;
+ int ta_maxcol;
+ char *pfile = lp_smb_passwd_file();
+ pstring nisname;
+ int i;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("no SMB password file set\n"));
+ return False;
+ }
+ if( strrchr( pfile, '/') )
+ pfile = strrchr( pfile, '/') + 1;
+
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.org_dir",
+ pdb_get_username(newpwd), pfile);
+
+ DEBUG(10, ("search by name: %s\n", nisname));
+
+ /* Search the table. */
+
+ if( !(result = nisp_get_nis_list(nisname, MASTER_ONLY|FOLLOW_LINKS|\
+ FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP))) {
+ return False;
+ }
+
+ if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
+ /* User not found. */
+ DEBUG(0,("user not found in NIS+\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ obj = NIS_RES_OBJECT(result);
+ DEBUG(6,("entry found in %s\n", obj->zo_domain));
+
+ /* we must create new stub object with EN_MODIFIED flag.
+ this is because obj from result is going to be freed and
+ we do not want to break it or cause memory leaks or corruption.
+ */
+
+ memmove((char *)&new_obj, obj, sizeof (new_obj));
+ ta_maxcol = obj->TA_data.ta_maxcol;
+
+ if(!(ecol = (entry_col*)malloc(ta_maxcol*sizeof(entry_col)))) {
+ DEBUG(0, ("memory allocation failure\n"));
+ nis_freeresult(result);
+ return False;
+ }
+
+ memmove((char *)ecol, obj->EN_data.en_cols.en_cols_val,
+ ta_maxcol*sizeof (entry_col));
+ new_obj.EN_data.en_cols.en_cols_val = ecol;
+ new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
+
+ if ( init_nisp_from_sam(&new_obj, newpwd, obj) == True ) {
+ slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s.%s",
+ pdb_get_username(newpwd), pfile, obj->zo_domain);
+
+ DEBUG(10, ("NIS+ table update: %s\n", nisname));
+ addresult =
+ nis_modify_entry(nisname, &new_obj,
+ MOD_SAMEOBJ | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ if(addresult->status != NIS_SUCCESS) {
+ DEBUG(0, ("NIS+ table update failed: %s %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ free(ecol);
+ return False;
+ }
+
+ DEBUG(6,("password changed\n"));
+ nis_freeresult(addresult);
+ } else {
+ DEBUG(6,("nothing to change!\n"));
+ }
+
+ free(ecol);
+ nis_freeresult(result);
+
+ return True;
+}
+
+#else
+ void nisplus_dummy_function(void);
+ void nisplus_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_NISPLUSSAM */
+
diff --git a/source/passdb/pdb_smbpasswd.c b/source/passdb/pdb_smbpasswd.c
new file mode 100644
index 00000000000..45c983b1ca6
--- /dev/null
+++ b/source/passdb/pdb_smbpasswd.c
@@ -0,0 +1,1520 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Modified by Jeremy Allison 1995.
+ * Modified by Gerald (Jerry) Carter 2000-2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_SMBPASSWD_SAM
+
+
+/*
+ smb_passwd is analogous to sam_passwd used everywhere
+ else. However, smb_passwd is limited to the information
+ stored by an smbpasswd entry
+ */
+
+struct smb_passwd
+{
+ uid_t smb_userid; /* this is actually the unix uid_t */
+ char *smb_name; /* username string */
+
+ unsigned char *smb_passwd; /* Null if no password */
+ unsigned char *smb_nt_passwd; /* Null if no password */
+
+ uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+ time_t pass_last_set_time; /* password last set time */
+};
+
+
+extern pstring samlogon_user;
+extern BOOL sam_logon_in_ssb;
+extern struct passdb_ops pdb_ops;
+
+/* used for maintain locks on the smbpasswd file */
+static int pw_file_lock_depth;
+static void *global_vp;
+
+
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ if(*plock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ (*plock_depth)++;
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_unlock(int fd, int *plock_depth)
+{
+ BOOL ret=True;
+
+ if(*plock_depth == 1)
+ ret = do_file_lock(fd, 5, F_UNLCK);
+
+ if (*plock_depth > 0)
+ (*plock_depth)--;
+
+ if(!ret)
+ DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+
+/**************************************************************
+ Intialize a smb_passwd struct
+ *************************************************************/
+
+static void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL)
+ return;
+ ZERO_STRUCTP (user);
+
+ user->pass_last_set_time = (time_t)0;
+}
+
+/***************************************************************
+ Internal fn to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module. Checks for atomic
+ rename of smbpasswd file on update or create once the lock has
+ been granted to prevent race conditions. JRA.
+****************************************************************/
+
+static void *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
+{
+ FILE *fp = NULL;
+ const char *open_mode = NULL;
+ int race_loop = 0;
+ int lock_type = F_RDLCK;
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+
+ switch(type) {
+ case PWF_READ:
+ open_mode = "rb";
+ lock_type = F_RDLCK;
+ break;
+ case PWF_UPDATE:
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ case PWF_CREATE:
+ /*
+ * Ensure atomic file creation.
+ */
+ {
+ int i, fd = -1;
+
+ for(i = 0; i < 5; i++) {
+ if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
+ break;
+ sys_usleep(200); /* Spin, spin... */
+ }
+ if(fd == -1) {
+ DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
+ return NULL;
+ }
+ close(fd);
+ open_mode = "r+b";
+ lock_type = F_WRLCK;
+ break;
+ }
+ }
+
+ for(race_loop = 0; race_loop < 5; race_loop++) {
+ DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+ if((fp = sys_fopen(pfile, open_mode)) == NULL) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
+ return NULL;
+ }
+
+ if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
+ fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Only check for replacement races on update or create.
+ * For read we don't mind if the data is one record out of date.
+ */
+
+ if(type == PWF_READ) {
+ break;
+ } else {
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+
+ /*
+ * Avoid the potential race condition between the open and the lock
+ * by doing a stat on the filename and an fstat on the fd. If the
+ * two inodes differ then someone did a rename between the open and
+ * the lock. Back off and try the open again. Only do this 5 times to
+ * prevent infinate loops. JRA.
+ */
+
+ if (sys_stat(pfile,&sbuf1) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (sys_fstat(fileno(fp),&sbuf2) != 0) {
+ DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ if( sbuf1.st_ino == sbuf2.st_ino) {
+ /* No race. */
+ break;
+ }
+
+ /*
+ * Race occurred - back off and try again...
+ */
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ }
+ }
+
+ if(race_loop == 5) {
+ DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+ /* Make sure it is only rw by the owner */
+ if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+ DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
+Error was %s\n.", pfile, strerror(errno) ));
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* We have a lock on the file. */
+ return (void *)fp;
+}
+
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+static void endsmbfilepwent(void *vp, int *lock_depth)
+{
+ FILE *fp = (FILE *)vp;
+
+ pw_file_unlock(fileno(fp), lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+
+static struct smb_passwd *getsmbfilepwent(void *vp)
+{
+ /* Static buffers we will return. */
+ static struct smb_passwd pw_buf;
+ static pstring user_name;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+ FILE *fp = (FILE *)vp;
+ char linebuf[256];
+ unsigned char c;
+ unsigned char *p;
+ long uidval;
+ size_t linebuf_len;
+
+ if(fp == NULL) {
+ DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
+ return NULL;
+ }
+
+ pdb_init_smb(&pw_buf);
+
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, 256, fp);
+ if (ferror(fp)) {
+ return NULL;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ if ((linebuf_len = strlen(linebuf)) == 0)
+ continue;
+
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n')
+ break;
+ }
+ } else
+ linebuf[linebuf_len - 1] = '\0';
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+ break;
+ }
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ * [Account type] is an ascii encoding of the type of account.
+ * LCT-(8 hex digits) is the time_t value of the last change time.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+ continue;
+ }
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+ continue;
+ }
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+
+ p++; /* Go past ':' */
+
+ if(*p == '-') {
+ DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
+ continue;
+ }
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
+ continue;
+ }
+
+ uidval = atoi((char *) p);
+
+ while (*p && isdigit(*p))
+ p++;
+
+ if (*p != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
+ continue;
+ }
+
+ pw_buf.smb_name = user_name;
+ pw_buf.smb_userid = uidval;
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+
+ /* Skip the ':' */
+ p++;
+
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
+ pw_buf.smb_nt_passwd = NULL;
+ pw_buf.smb_passwd = NULL;
+ pw_buf.acct_ctrl |= ACB_DISABLED;
+ return &pw_buf;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
+ continue;
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
+ continue;
+ }
+
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+ pw_buf.smb_passwd = NULL;
+ pw_buf.acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ if (!pdb_gethexpwd((char *)p, smbpwd)) {
+ DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
+ continue;
+ }
+ pw_buf.smb_passwd = smbpwd;
+ }
+
+ /*
+ * Now check if the NT compatible password is
+ * available.
+ */
+ pw_buf.smb_nt_passwd = NULL;
+
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if(pdb_gethexpwd((char *)p,smbntpwd))
+ pw_buf.smb_nt_passwd = smbntpwd;
+ }
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+ }
+
+ DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+ user_name, uidval));
+
+ if (*p == '[')
+ {
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+ pw_buf.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+ /* Must have some account type set. */
+ if(pw_buf.acct_ctrl == 0)
+ pw_buf.acct_ctrl = ACB_NORMAL;
+
+ /* Now try and get the last change time. */
+ if(end_p)
+ p = end_p + 1;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ pw_buf.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+ }
+ }
+ }
+ } else {
+ /* 'Old' style file. Fake up based on user name. */
+ /*
+ * Currently trust accounts are kept in the same
+ * password file as 'normal accounts'. If this changes
+ * we will have to fix this code. JRA.
+ */
+ if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
+ pw_buf.acct_ctrl &= ~ACB_NORMAL;
+ pw_buf.acct_ctrl |= ACB_WSTRUST;
+ }
+ }
+
+ return &pw_buf;
+ }
+
+ DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+ return NULL;
+}
+
+/************************************************************************
+ Create a new smbpasswd entry - malloced space returned.
+*************************************************************************/
+
+static char *format_new_smbpasswd_entry(struct smb_passwd *newpwd)
+{
+ int new_entry_length;
+ char *new_entry;
+ char *p;
+ int i;
+
+ new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
+
+ if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
+ DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
+ return NULL;
+ }
+
+ slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
+ p = &new_entry[strlen(new_entry)];
+
+ if(newpwd->smb_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
+ }
+ } else {
+ i=0;
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ if(newpwd->smb_nt_passwd != NULL) {
+ for( i = 0; i < 16; i++) {
+ slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(newpwd->acct_ctrl & ACB_PWNOTREQ)
+ safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ else
+ safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
+ }
+
+ p += 32;
+
+ *p++ = ':';
+
+ /* Add the account encoding and the last change time. */
+ slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
+ pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)newpwd->pass_last_set_time);
+
+ return new_entry;
+}
+
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static BOOL add_smbfilepwd_entry(struct smb_passwd *newpwd)
+{
+ char *pfile = lp_smb_passwd_file();
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ int wr_len;
+ int fd;
+ size_t new_entry_length;
+ char *new_entry;
+ SMB_OFF_T offpos;
+
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
+
+ if (fp == NULL && errno == ENOENT) {
+ /* Try again - create. */
+ fp = startsmbfilepwent(pfile, PWF_CREATE, &pw_file_lock_depth);
+ }
+
+ if (fp == NULL) {
+ DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(fp)) != NULL)
+ {
+ if (strequal(newpwd->smb_name, pwd->smb_name))
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+ }
+
+ /* Ok - entry doesn't exist. We can add it */
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ /*
+ * The add user write needs to be atomic - so get the fd from
+ * the fp and do a raw write() call.
+ */
+ fd = fileno(fp);
+
+ if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
+ fd, new_entry_length, new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
+Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
+
+ /* Remove the entry we just wrote. */
+ if(sys_ftruncate(fd, offpos) == -1)
+ {
+ DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ newpwd->smb_name, strerror(errno)));
+ }
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return True;
+}
+
+/************************************************************************
+ Routine to search the smbpasswd file for an entry matching the username.
+ and then modify its password entry. We can't use the startsmbpwent()/
+ getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
+ in the actual file to decide how much room we have to write data.
+ override = False, normal
+ override = True, override XXXXXXXX'd out password or NO PASS
+************************************************************************/
+
+static BOOL mod_smbfilepwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ /* Static buffers we will return. */
+ static pstring user_name;
+
+ char linebuf[256];
+ char readbuf[1024];
+ unsigned char c;
+ fstring ascii_p16;
+ fstring encode_bits;
+ unsigned char *p = NULL;
+ size_t linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ char *pfile = lp_smb_passwd_file();
+ BOOL found_entry = False;
+ BOOL got_pass_last_set_time = False;
+
+ SMB_OFF_T pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile) {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, "r+");
+
+ if (fp == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ lockfd = fileno(fp);
+
+ if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp)) {
+ pwd_seekpos = sys_ftell(fp);
+
+ linebuf[0] = '\0';
+
+ fgets(linebuf, sizeof(linebuf), fp);
+ if (ferror(fp)) {
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') {
+ break;
+ }
+ }
+ } else {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp)) {
+ DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0') {
+ DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+
+ if (p == NULL) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name)) {
+ found_entry = True;
+ break;
+ }
+ }
+
+ if (!found_entry) {
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ while (*p && isdigit(*p))
+ p++;
+ if (*p != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+ p++;
+
+ /* Record exact password position */
+ pwd_seekpos += PTR_DIFF(p, linebuf);
+
+ if (!override && (*p == '*' || *p == 'X')) {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
+ pw_file_unlock(lockfd, &pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (!override && (*p == '*' || *p == 'X')) {
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Now check if the NT compatible password is
+ available. */
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ if (p[32] != ':') {
+ DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /*
+ * Now check if the account info and the password last
+ * change time is available.
+ */
+ p += 33; /* Move to the first character of the line after
+ the NT password. */
+
+ /*
+ * If both NT and lanman passwords are provided - reset password
+ * not required flag.
+ */
+
+ if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
+ /* Reqiure password in the future (should ACB_DISABLED also be reset?) */
+ pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
+ }
+
+ if (*p == '[') {
+
+ i = 0;
+ encode_bits[i++] = *p++;
+ while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
+ encode_bits[i++] = *p++;
+
+ encode_bits[i++] = ']';
+ encode_bits[i++] = '\0';
+
+ if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+ /*
+ * We are using a new format, space padded
+ * acct ctrl field. Encode the given acct ctrl
+ * bits into it.
+ */
+ fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+ } else {
+ /*
+ * If using the old format and the ACB_DISABLED or
+ * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
+ * here as we have no space to encode the change.
+ */
+ if(pwd->acct_ctrl & (ACB_DISABLED|ACB_PWNOTREQ)) {
+ pwd->smb_passwd = NULL;
+ pwd->smb_nt_passwd = NULL;
+ }
+ }
+
+ /* Go past the ']' */
+ if(linebuf_len > PTR_DIFF(p, linebuf))
+ p++;
+
+ if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+ p++;
+
+ /* We should be pointing at the LCT entry. */
+ if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
+
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i]))
+ break;
+ }
+ if(i == 8) {
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+ got_pass_last_set_time = True;
+ } /* i == 8 */
+ } /* *p && StrnCaseCmp() */
+ } /* p == ':' */
+ } /* p == '[' */
+
+ /* Entry is correctly formed. */
+
+ /* Create the 32 byte representation of the new p16 */
+ if(pwd->smb_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ wr_len = 66;
+ if (pwd->smb_nt_passwd != NULL) {
+ for (i = 0; i < 16; i++) {
+ slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ } else {
+ if(pwd->acct_ctrl & ACB_PWNOTREQ)
+ fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
+ else
+ fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ }
+ ascii_p16[65] = ':';
+ ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+ /* Add on the account info bits and the time of last
+ password change. */
+
+ pwd->pass_last_set_time = time(NULL);
+
+ if(got_pass_last_set_time) {
+ slprintf(&ascii_p16[strlen(ascii_p16)],
+ sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+ "%s:LCT-%08X:",
+ encode_bits, (uint32)pwd->pass_last_set_time );
+ wr_len = strlen(ascii_p16);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbfilepwd_entry: "));
+ dump_data(100, ascii_p16, wr_len);
+#endif
+
+ if(wr_len > sizeof(linebuf)) {
+ DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return (False);
+ }
+
+ /*
+ * Do an atomic write into the file at the position defined by
+ * seekpos.
+ */
+
+ /* The mod user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+
+ fd = fileno(fp);
+
+ if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ /* Sanity check - ensure the areas we are writing are framed by ':' */
+ if (read(fd, linebuf, wr_len+1) != wr_len+1) {
+ DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
+ DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
+ DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ if (write(fd, ascii_p16, wr_len) != wr_len) {
+ DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return False;
+ }
+
+ pw_file_unlock(lockfd,&pw_file_lock_depth);
+ fclose(fp);
+ return True;
+}
+
+/************************************************************************
+ Routine to delete an entry in the smbpasswd file by name.
+*************************************************************************/
+
+static BOOL del_smbfilepwd_entry(const char *name)
+{
+ char *pfile = lp_smb_passwd_file();
+ pstring pfile2;
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
+ FILE *fp_write = NULL;
+ int pfile2_lockdepth = 0;
+
+ slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
+
+ /*
+ * Open the smbpassword file - for update. It needs to be update
+ * as we need any other processes to wait until we have replaced
+ * it.
+ */
+
+ if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ return False;
+ }
+
+ /*
+ * Create the replacement password file.
+ */
+ if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+ DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ return False;
+ }
+
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+
+ while ((pwd = getsmbfilepwent(fp)) != NULL) {
+ char *new_entry;
+ size_t new_entry_length;
+
+ if (strequal(name, pwd->smb_name)) {
+ DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
+ continue;
+ }
+
+ /*
+ * We need to copy the entry out into the second file.
+ */
+
+ if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ return False;
+ }
+
+ new_entry_length = strlen(new_entry);
+
+ if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
+ unlink(pfile2);
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write, &pfile2_lockdepth);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ }
+
+ /*
+ * Ensure pfile2 is flushed before rename.
+ */
+
+ if(fflush(fp_write) != 0)
+ {
+ DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return False;
+ }
+
+ /*
+ * Do an atomic rename - then release the locks.
+ */
+
+ if(rename(pfile2,pfile) != 0) {
+ unlink(pfile2);
+ }
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+ endsmbfilepwent(fp_write,&pfile2_lockdepth);
+ return True;
+}
+
+/*********************************************************************
+ Create a smb_passwd struct from a SAM_ACCOUNT.
+ We will not allocate any new memory. The smb_passwd struct
+ should only stay around as long as the SAM_ACCOUNT does.
+ ********************************************************************/
+static BOOL build_smb_pass (struct smb_passwd *smb_pw, SAM_ACCOUNT *sampass)
+{
+ if (sampass == NULL)
+ return False;
+
+ ZERO_STRUCTP(smb_pw);
+
+ smb_pw->smb_userid=pdb_get_uid(sampass);
+ smb_pw->smb_name=pdb_get_username(sampass);
+
+ smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
+ smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
+
+ smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
+ smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
+
+ return True;
+}
+
+/*********************************************************************
+ Create a SAM_ACCOUNT from a smb_passwd struct
+ ********************************************************************/
+static BOOL build_sam_account(SAM_ACCOUNT *sam_pass, struct smb_passwd *pw_buf)
+{
+ struct passwd *pwfile;
+
+ if (sam_pass==NULL) {
+ DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
+ return False;
+ }
+
+ /* Verify in system password file...
+ FIXME!!! This is where we should look up an internal
+ mapping of allocated uid for machine accounts as well
+ --jerry */
+ pwfile = sys_getpwnam(pw_buf->smb_name);
+ if (pwfile == NULL) {
+ DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s not in unix passwd database!\n", pw_buf->smb_name));
+ return False;
+ }
+
+ /* FIXME!! This doesn't belong here. Should be set in net_sam_logon()
+ --jerry */
+ pstrcpy(samlogon_user, pw_buf->smb_name);
+
+ pdb_set_uid (sam_pass, pwfile->pw_uid);
+ pdb_set_gid (sam_pass, pwfile->pw_gid);
+ pdb_set_fullname(sam_pass, pwfile->pw_gecos);
+
+ pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
+
+ /* should check the group mapping here instead of static mappig. JFM */
+ pdb_set_group_rid(sam_pass, pdb_gid_to_group_rid(pwfile->pw_gid));
+
+ pdb_set_username (sam_pass, pw_buf->smb_name);
+ pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
+ pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
+ pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
+ pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
+ pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time);
+ pdb_set_domain (sam_pass, lp_workgroup());
+
+ pdb_set_dir_drive (sam_pass, lp_logon_drive());
+
+ /* the smbpasswd format doesn't have a must change time field, so
+ we can't get this right. The best we can do is to set this to
+ some time in the future. 21 days seems as reasonable as any other value :)
+ */
+ pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
+
+ /* check if this is a user account or a machine account */
+ if (samlogon_user[strlen(samlogon_user)-1] != '$')
+ {
+ pstring str;
+ gid_t gid = getegid();
+
+ sam_logon_in_ssb = True;
+
+ pstrcpy(str, lp_logon_script());
+ standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
+ pdb_set_logon_script(sam_pass, str);
+
+ pstrcpy(str, lp_logon_path());
+ standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
+ pdb_set_profile_path(sam_pass, str);
+
+ pstrcpy(str, lp_logon_home());
+ standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
+ pdb_set_homedir(sam_pass, str);
+
+ sam_logon_in_ssb = False;
+ } else {
+ /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
+ pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS);
+ }
+
+ return True;
+}
+/*****************************************************************
+ Functions to be implemented by the new passdb API
+ ****************************************************************/
+BOOL pdb_setsampwent (BOOL update)
+{
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+
+ /* did we fail? Should we try to create it? */
+ if (!global_vp && update && errno == ENOENT)
+ {
+ FILE *fp;
+ /* slprintf(msg_str,msg_str_len-1,
+ "smbpasswd file did not exist - attempting to create it.\n"); */
+ DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
+ fp = sys_fopen(lp_smb_passwd_file(), "w");
+ if (fp)
+ {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ }
+
+ global_vp = startsmbfilepwent(lp_smb_passwd_file(),
+ update ? PWF_UPDATE : PWF_READ,
+ &pw_file_lock_depth);
+ }
+
+ return (global_vp != NULL);
+}
+
+void pdb_endsampwent (void)
+{
+ endsmbfilepwent(global_vp, &pw_file_lock_depth);
+}
+
+/*****************************************************************
+ ****************************************************************/
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ struct smb_passwd *pw_buf=NULL;
+ BOOL done = False;
+ DEBUG(5,("pdb_getsampwent\n"));
+
+ if (user==NULL) {
+ DEBUG(5,("pdb_getsampwent: user is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwent\n");
+#endif
+ return False;
+ }
+
+ while (!done)
+ {
+ /* do we have an entry? */
+ pw_buf = getsmbfilepwent(global_vp);
+ if (pw_buf == NULL)
+ return False;
+
+ /* build the SAM_ACCOUNT entry from the smb_passwd struct.
+ We loop in case the user in the pdb does not exist in
+ the local system password file */
+ if (build_sam_account(user, pw_buf))
+ done = True;
+ }
+
+ DEBUG(5,("pdb_getsampwent:done\n"));
+
+ /* success */
+ return True;
+}
+
+
+/****************************************************************
+ Search smbpasswd file by iterating over the entries. Do not
+ call getpwnam() for unix account information until we have found
+ the correct entry
+ ***************************************************************/
+BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, char *username)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+ char *domain = NULL;
+ char *user = NULL;
+ fstring name;
+
+ DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
+
+
+ /* break the username from the domain if we have
+ been given a string in the form 'DOMAIN\user' */
+ fstrcpy (name, username);
+ if ((user=strchr_m(name, '\\')) != NULL) {
+ domain = name;
+ *user = '\0';
+ user++;
+ }
+
+ /* if a domain was specified and it wasn't ours
+ then there is no chance of matching */
+ if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
+ return False;
+
+ /* startsmbfilepwent() is used here as we don't want to lookup
+ the UNIX account in the local system password file until
+ we have a match. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ /* if we have a domain name, then we should map it to a UNIX
+ username first */
+ if ( domain )
+ map_username(user);
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
+ /* do nothing....another loop */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwnam\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", uid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwuid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account(sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
+{
+ struct smb_passwd *smb_pw;
+ void *fp = NULL;
+
+ DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
+
+ if (fp == NULL) {
+ DEBUG(0, ("unable to open passdb database.\n"));
+ return False;
+ }
+
+ while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+ /* do nothing */ ;
+
+ endsmbfilepwent(fp, &pw_file_lock_depth);
+
+
+ /* did we locate the username in smbpasswd */
+ if (smb_pw == NULL)
+ return False;
+
+ DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
+
+ if (!sam_acct) {
+ DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
+#if 0
+ smb_panic("NULL pointer passed to pdb_getsampwrid\n");
+#endif
+ return False;
+ }
+
+ /* now build the SAM_ACCOUNT */
+ if (!build_sam_account (sam_acct, smb_pw))
+ return False;
+
+ /* success */
+ return True;
+}
+
+BOOL pdb_add_sam_account(SAM_ACCOUNT *sampass)
+{
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ build_smb_pass(&smb_pw, sampass);
+
+ /* add the entry */
+ if(!add_smbfilepwd_entry(&smb_pw))
+ return False;
+
+ return True;
+}
+
+BOOL pdb_update_sam_account(SAM_ACCOUNT *sampass, BOOL override)
+{
+ struct smb_passwd smb_pw;
+
+ /* convert the SAM_ACCOUNT */
+ build_smb_pass(&smb_pw, sampass);
+
+ /* update the entry */
+ if(!mod_smbfilepwd_entry(&smb_pw, override))
+ return False;
+
+ return True;
+}
+
+BOOL pdb_delete_sam_account (char* username)
+{
+ return del_smbfilepwd_entry(username);
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void smbpass_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WTH_SMBPASSWD_SAM*/
diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c
new file mode 100644
index 00000000000..43eefa5c7a7
--- /dev/null
+++ b/source/passdb/pdb_tdb.c
@@ -0,0 +1,830 @@
+/*
+ * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Simo Sorce 2000
+ * Copyright (C) Gerald Carter 2000
+ * Copyright (C) Jeremy Allison 2001
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_TDB_SAM
+
+#define PDB_VERSION "20010830"
+#define PASSDB_FILE_NAME "/passdb.tdb"
+#define TDB_FORMAT_STRING "ddddddBBBBBBBBBBBBddBBwdwdBdd"
+#define USERPREFIX "USER_"
+#define RIDPREFIX "RID_"
+
+extern int DEBUGLEVEL;
+extern pstring samlogon_user;
+extern BOOL sam_logon_in_ssb;
+
+struct tdb_enum_info {
+ TDB_CONTEXT *passwd_tdb;
+ TDB_DATA key;
+};
+
+static struct tdb_enum_info global_tdb_ent;
+/*static SAM_ACCOUNT global_sam_pass;*/
+
+/**********************************************************************
+ Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
+ *********************************************************************/
+
+static BOOL init_sam_from_buffer (SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
+{
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username;
+ char *domain;
+ char *nt_username;
+ char *dir_drive;
+ char *unknown_str;
+ char *munged_dial;
+ char *fullname;
+ char *homedir;
+ char *logon_script;
+ char *profile_path;
+ char *acct_desc;
+ char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint32 /* uid, gid,*/ user_rid, group_rid, unknown_3, hours_len, unknown_5, unknown_6;
+ uint16 acct_ctrl, logon_divs;
+ uint8 *hours;
+ static uint8 *lm_pw_ptr, *nt_pw_ptr;
+ uint32 len = 0;
+ uint32 lmpwlen, ntpwlen, hourslen;
+ BOOL ret = True;
+
+ /* unpack the buffer into variables */
+ len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING,
+ &logon_time,
+ &logoff_time,
+ &kickoff_time,
+ &pass_last_set_time,
+ &pass_can_change_time,
+ &pass_must_change_time,
+ &username_len, &username,
+ &domain_len, &domain,
+ &nt_username_len, &nt_username,
+ &fullname_len, &fullname,
+ &homedir_len, &homedir,
+ &dir_drive_len, &dir_drive,
+ &logon_script_len, &logon_script,
+ &profile_path_len, &profile_path,
+ &acct_desc_len, &acct_desc,
+ &workstations_len, &workstations,
+ &unknown_str_len, &unknown_str,
+ &munged_dial_len, &munged_dial,
+ &user_rid,
+ &group_rid,
+ &lmpwlen, &lm_pw_ptr,
+ &ntpwlen, &nt_pw_ptr,
+ &acct_ctrl,
+ &unknown_3,
+ &logon_divs,
+ &hours_len,
+ &hourslen, &hours,
+ &unknown_5,
+ &unknown_6);
+
+ if (len == -1) {
+ ret = False;
+ goto done;
+ }
+
+ pdb_set_logon_time(sampass, logon_time);
+ pdb_set_logoff_time(sampass, logoff_time);
+ pdb_set_kickoff_time(sampass, kickoff_time);
+ pdb_set_pass_can_change_time(sampass, pass_can_change_time);
+ pdb_set_pass_must_change_time(sampass, pass_must_change_time);
+ pdb_set_pass_last_set_time(sampass, pass_last_set_time);
+
+ pdb_set_username (sampass, username_len?username:NULL);
+ pdb_set_domain (sampass, domain_len?domain:NULL);
+ pdb_set_nt_username (sampass, nt_username_len?nt_username:NULL);
+ pdb_set_fullname (sampass, fullname_len?fullname:NULL);
+ pdb_set_homedir (sampass, homedir_len?homedir:NULL);
+ pdb_set_dir_drive (sampass, dir_drive_len?dir_drive:NULL);
+ pdb_set_logon_script (sampass, logon_script_len?logon_script:NULL);
+ pdb_set_profile_path (sampass, profile_path_len?profile_path:NULL);
+ pdb_set_acct_desc (sampass, acct_desc_len?acct_desc:NULL);
+ pdb_set_workstations (sampass, workstations_len?workstations:NULL);
+ pdb_set_munged_dial (sampass, munged_dial_len?munged_dial:NULL);
+ pdb_set_lanman_passwd(sampass, lmpwlen?lm_pw_ptr:NULL);
+ pdb_set_nt_passwd (sampass, ntpwlen?nt_pw_ptr:NULL);
+
+ /*pdb_set_uid(sampass, uid);
+ pdb_set_gid(sampass, gid);*/
+ pdb_set_user_rid(sampass, user_rid);
+ pdb_set_group_rid(sampass, group_rid);
+ pdb_set_unknown_3(sampass, unknown_3);
+ pdb_set_hours_len(sampass, hours_len);
+ pdb_set_unknown_5(sampass, unknown_5);
+ pdb_set_unknown_6(sampass, unknown_6);
+ pdb_set_acct_ctrl(sampass, acct_ctrl);
+ pdb_set_logons_divs(sampass, logon_divs);
+ pdb_set_hours(sampass, hours);
+
+done:
+
+ SAFE_FREE(username);
+ SAFE_FREE(domain);
+ SAFE_FREE(nt_username);
+ SAFE_FREE(fullname);
+ SAFE_FREE(homedir);
+ SAFE_FREE(dir_drive);
+ SAFE_FREE(logon_script);
+ SAFE_FREE(profile_path);
+ SAFE_FREE(acct_desc);
+ SAFE_FREE(workstations);
+ SAFE_FREE(munged_dial);
+
+ return ret;
+}
+
+/**********************************************************************
+ Intialize a BYTE buffer from a SAM_ACCOUNT struct
+ *********************************************************************/
+static uint32 init_buffer_from_sam (uint8 **buf, SAM_ACCOUNT *sampass)
+{
+ size_t len, buflen;
+
+ /* times are stored as 32bit integer
+ take care on system with 64bit wide time_t
+ --SSS */
+ uint32 logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time;
+ char *username;
+ char *domain;
+ char *nt_username;
+ char *dir_drive;
+ char *unknown_str;
+ char *munged_dial;
+ char *fullname;
+ char *homedir;
+ char *logon_script;
+ char *profile_path;
+ char *acct_desc;
+ char *workstations;
+ uint32 username_len, domain_len, nt_username_len,
+ dir_drive_len, unknown_str_len, munged_dial_len,
+ fullname_len, homedir_len, logon_script_len,
+ profile_path_len, acct_desc_len, workstations_len;
+
+ uint8 *lm_pw;
+ uint8 *nt_pw;
+ uint32 lm_pw_len = 16;
+ uint32 nt_pw_len = 16;
+
+ /* do we have a valid SAM_ACCOUNT pointer? */
+ if (sampass == NULL)
+ return -1;
+
+ *buf = NULL;
+ buflen = 0;
+
+ logon_time = (uint32)pdb_get_logon_time(sampass);
+ logoff_time = (uint32)pdb_get_logoff_time(sampass);
+ kickoff_time = (uint32)pdb_get_kickoff_time(sampass);
+ pass_can_change_time = (uint32)pdb_get_pass_can_change_time(sampass);
+ pass_must_change_time = (uint32)pdb_get_pass_must_change_time(sampass);
+ pass_last_set_time = (uint32)pdb_get_pass_last_set_time(sampass);
+
+
+ username = pdb_get_username(sampass);
+ if (username)
+ username_len = strlen(username) +1;
+ else
+ username_len = 0;
+ domain = pdb_get_domain(sampass);
+ if (domain)
+ domain_len = strlen(domain) +1;
+ else
+ domain_len = 0;
+ nt_username = pdb_get_nt_username(sampass);
+ if (nt_username)
+ nt_username_len = strlen(nt_username) +1;
+ else
+ nt_username_len = 0;
+ dir_drive = pdb_get_dirdrive(sampass);
+ if (dir_drive)
+ dir_drive_len = strlen(dir_drive) +1;
+ else
+ dir_drive_len = 0;
+ unknown_str = NULL;
+ unknown_str_len = 0;
+ munged_dial = pdb_get_munged_dial(sampass);
+ if (munged_dial)
+ munged_dial_len = strlen(munged_dial) +1;
+ else
+ munged_dial_len = 0;
+
+ fullname = pdb_get_fullname(sampass);
+ if (fullname)
+ fullname_len = strlen(fullname) +1;
+ else
+ fullname_len = 0;
+ homedir = pdb_get_homedir(sampass);
+ if (homedir)
+ homedir_len = strlen(homedir) +1;
+ else
+ homedir_len = 0;
+ logon_script = pdb_get_logon_script(sampass);
+ if (logon_script)
+ logon_script_len = strlen(logon_script) +1;
+ else
+ logon_script_len = 0;
+ profile_path = pdb_get_profile_path(sampass);
+ if (profile_path)
+ profile_path_len = strlen(profile_path) +1;
+ else
+ profile_path_len = 0;
+ acct_desc = pdb_get_acct_desc(sampass);
+ if (acct_desc)
+ acct_desc_len = strlen(acct_desc) +1;
+ else
+ acct_desc_len = 0;
+ workstations = pdb_get_workstations(sampass);
+ if (workstations)
+ workstations_len = strlen(workstations) +1;
+ else
+ workstations_len = 0;
+
+ lm_pw = pdb_get_lanman_passwd(sampass);
+ if (!lm_pw)
+ lm_pw_len = 0;
+
+ nt_pw = pdb_get_nt_passwd(sampass);
+ if (!nt_pw)
+ nt_pw_len = 0;
+
+ /* one time to get the size needed */
+ len = tdb_pack(NULL, 0, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* malloc the space needed */
+ if ( (*buf=(uint8*)malloc(len)) == NULL) {
+ DEBUG(0,("init_buffer_from_sam: Unable to malloc() memory for buffer!\n"));
+ return (-1);
+ }
+
+ /* now for the real call to tdb_pack() */
+ buflen = tdb_pack(*buf, len, TDB_FORMAT_STRING,
+ logon_time,
+ logoff_time,
+ kickoff_time,
+ pass_last_set_time,
+ pass_can_change_time,
+ pass_must_change_time,
+ username_len, username,
+ domain_len, domain,
+ nt_username_len, nt_username,
+ fullname_len, fullname,
+ homedir_len, homedir,
+ dir_drive_len, dir_drive,
+ logon_script_len, logon_script,
+ profile_path_len, profile_path,
+ acct_desc_len, acct_desc,
+ workstations_len, workstations,
+ unknown_str_len, unknown_str,
+ munged_dial_len, munged_dial,
+ pdb_get_user_rid(sampass),
+ pdb_get_group_rid(sampass),
+ lm_pw_len, lm_pw,
+ nt_pw_len, nt_pw,
+ pdb_get_acct_ctrl(sampass),
+ pdb_get_unknown3(sampass),
+ pdb_get_logon_divs(sampass),
+ pdb_get_hours_len(sampass),
+ MAX_HOURS_LEN, pdb_get_hours(sampass),
+ pdb_get_unknown5(sampass),
+ pdb_get_unknown6(sampass));
+
+
+ /* check to make sure we got it correct */
+ if (buflen != len) {
+ /* error */
+ SAFE_FREE (*buf);
+ return (-1);
+ }
+
+ return (buflen);
+}
+
+/***************************************************************
+ Open the TDB passwd database for SAM account enumeration.
+****************************************************************/
+
+BOOL pdb_setsampwent(BOOL update)
+{
+ pstring tdbfile;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* Open tdb passwd */
+ if (!(global_tdb_ent.passwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)))
+ {
+ DEBUG(0, ("Unable to open/create TDB passwd\n"));
+ return False;
+ }
+
+ global_tdb_ent.key = tdb_firstkey(global_tdb_ent.passwd_tdb);
+
+ return True;
+}
+
+/***************************************************************
+ End enumeration of the TDB passwd list.
+****************************************************************/
+
+void pdb_endsampwent(void)
+{
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ DEBUG(7, ("endtdbpwent: closed password file.\n"));
+}
+
+/*****************************************************************
+ Get one SAM_ACCOUNT from the TDB (next in line)
+*****************************************************************/
+
+BOOL pdb_getsampwent(SAM_ACCOUNT *user)
+{
+ TDB_DATA data;
+ struct passwd *pw;
+ uid_t uid;
+ gid_t gid;
+ char *prefix = USERPREFIX;
+ int prefixlen = strlen (prefix);
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_get_sampwent: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* skip all RID entries */
+ while ((global_tdb_ent.key.dsize != 0) && (strncmp (global_tdb_ent.key.dptr, prefix, prefixlen)))
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ /* do we have an valid interation pointer? */
+ if(global_tdb_ent.passwd_tdb == NULL) {
+ DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
+ return False;
+ }
+
+ data = tdb_fetch (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user))) == NULL) {
+ DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
+ pdb_get_username(user)));
+ return False;
+ }
+
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, uid);
+ pdb_set_gid (user, gid);
+
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_logon_script(user));
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_profile_path(user));
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_homedir(user));
+
+ /* increment to next in line */
+ global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
+
+ return True;
+}
+
+/******************************************************************
+ Lookup a name in the SAM TDB
+******************************************************************/
+
+BOOL pdb_getsampwnam (SAM_ACCOUNT *user, char *sname)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ struct passwd *pw;
+ pstring tdbfile;
+ fstring name;
+ uid_t uid;
+ gid_t gid;
+
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ /* Data is stored in all lower-case */
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd!\n"));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!init_sam_from_buffer (user, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
+ is used instaed of Get_Pwnam() as we do not need to try case
+ permutations */
+ if ((pw=sys_getpwnam(pdb_get_username(user))) == NULL) {
+ DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
+ pdb_get_username(user)));
+ return False;
+ }
+
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ pdb_set_uid (user, uid);
+ pdb_set_gid (user, gid);
+
+ /* 21 days from present */
+ pdb_set_pass_must_change_time(user, time(NULL)+1814400);
+
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_logon_script(user));
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_profile_path(user));
+ standard_sub_advanced(-1, pdb_get_username(user), "", gid, pdb_get_homedir(user));
+
+ /* cleanup */
+ tdb_close (pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Search by uid
+ **************************************************************************/
+
+BOOL pdb_getsampwuid (SAM_ACCOUNT* user, uid_t uid)
+{
+ struct passwd *pw;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwuid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ pw = sys_getpwuid(uid);
+ if (pw == NULL) {
+ DEBUG(0,("pdb_getsampwuid: getpwuid(%d) return NULL. User does not exist!\n", uid));
+ return False;
+ }
+ fstrcpy (name, pw->pw_name);
+
+ return pdb_getsampwnam (user, name);
+
+}
+
+/***************************************************************************
+ Search by rid
+ **************************************************************************/
+
+BOOL pdb_getsampwrid (SAM_ACCOUNT *user, uint32 rid)
+{
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA data, key;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+
+ if (user==NULL) {
+ DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
+ return False;
+ }
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* set search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* open the accounts TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
+ DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
+ return False;
+ }
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_getsampwrid (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ fstrcpy (name, data.dptr);
+ SAFE_FREE(data.dptr);
+
+ tdb_close (pwd_tdb);
+
+ return pdb_getsampwnam (user, name);
+}
+
+/***************************************************************************
+ Delete a SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_delete_sam_account(char *sname)
+{
+ SAM_ACCOUNT *sam_pass = NULL;
+ TDB_CONTEXT *pwd_tdb;
+ TDB_DATA key, data;
+ fstring keystr;
+ pstring tdbfile;
+ uint32 rid;
+ fstring name;
+
+ unix_strlower(sname, -1, name, sizeof(name));
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ /* open the TDB */
+ if (!(pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR, 0600))) {
+ DEBUG(0, ("Unable to open TDB passwd!"));
+ return False;
+ }
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* get the record */
+ data = tdb_fetch (pwd_tdb, key);
+ if (!data.dptr) {
+ DEBUG(5,("pdb_delete_sam_account (TDB): error fetching database.\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ /* unpack the buffer */
+ if (!pdb_init_sam (&sam_pass)) {
+ tdb_close (pwd_tdb);
+ return False;
+ }
+
+ if (!init_sam_from_buffer (sam_pass, data.dptr, data.dsize)) {
+ DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
+ tdb_close (pwd_tdb);
+ SAFE_FREE(data.dptr);
+ return False;
+ }
+ SAFE_FREE(data.dptr);
+
+ rid = pdb_get_user_rid(sam_pass);
+
+ pdb_free_sam (&sam_pass);
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ /* delete also the RID key */
+
+ /* set the search key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* it's outaa here! 8^) */
+ if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
+ DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
+ DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close(pwd_tdb);
+ return False;
+ }
+
+ tdb_close(pwd_tdb);
+
+ return True;
+}
+
+/***************************************************************************
+ Update the TDB SAM
+****************************************************************************/
+
+static BOOL tdb_update_sam(SAM_ACCOUNT* newpwd, BOOL override, int flag)
+{
+ TDB_CONTEXT *pwd_tdb = NULL;
+ TDB_DATA key, data;
+ uint8 *buf = NULL;
+ fstring keystr;
+ pstring tdbfile;
+ fstring name;
+ BOOL ret = True;
+
+ get_private_directory(tdbfile);
+ pstrcat (tdbfile, PASSDB_FILE_NAME);
+
+ if ( (!newpwd->uid) || (!newpwd->gid) )
+ DEBUG (0,("tdb_update_sam: Storing a SAM_ACCOUNT for [%s] with uid %d and gid %d!\n",
+ newpwd->username, newpwd->uid, newpwd->gid));
+
+ /* if we don't have a RID, then generate one */
+ if (!newpwd->user_rid)
+ pdb_set_user_rid (newpwd, pdb_uid_to_user_rid (newpwd->uid));
+ if (!newpwd->group_rid)
+ pdb_set_group_rid (newpwd, pdb_gid_to_group_rid (newpwd->gid));
+
+ /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
+ if ((data.dsize=init_buffer_from_sam (&buf, newpwd)) == -1) {
+ DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
+ ret = False;
+ goto done;
+ }
+ data.dptr = buf;
+
+ unix_strlower(pdb_get_username(newpwd), -1, name, sizeof(name));
+
+ /* setup the USER index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* invalidate the existing TDB iterator if it is open */
+ if (global_tdb_ent.passwd_tdb) {
+ tdb_close(global_tdb_ent.passwd_tdb);
+ global_tdb_ent.passwd_tdb = NULL;
+ }
+
+ /* open the account TDB passwd*/
+ pwd_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
+ if (!pwd_tdb)
+ {
+ DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd!\n"));
+ return False;
+ }
+
+ /* add the account */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify passwd TDB!"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ tdb_close (pwd_tdb);
+ ret = False;
+ goto done;
+ }
+
+ /* setup RID data */
+ data.dsize = sizeof(fstring);
+ data.dptr = name;
+
+ /* setup the RID index key */
+ slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
+ key.dptr = keystr;
+ key.dsize = strlen (keystr) + 1;
+
+ /* add the reference */
+ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
+ DEBUG(0, ("Unable to modify TDB passwd !"));
+ DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
+ ret = False;
+ goto done;
+ }
+
+done:
+ /* cleanup */
+ tdb_close (pwd_tdb);
+ SAFE_FREE(buf);
+
+ return (ret);
+}
+
+/***************************************************************************
+ Modifies an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_update_sam_account (SAM_ACCOUNT *newpwd, BOOL override)
+{
+ return (tdb_update_sam(newpwd, override, TDB_MODIFY));
+}
+
+/***************************************************************************
+ Adds an existing SAM_ACCOUNT
+****************************************************************************/
+
+BOOL pdb_add_sam_account (SAM_ACCOUNT *newpwd)
+{
+ return (tdb_update_sam(newpwd, True, TDB_INSERT));
+}
+
+#else
+ /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
+ void samtdb_dummy_function(void) { } /* stop some compilers complaining */
+#endif /* WITH_TDB_SAM */
diff --git a/source/rpc_client/cli_trust.c b/source/rpc_client/cli_trust.c
new file mode 100644
index 00000000000..d7faf4975f6
--- /dev/null
+++ b/source/rpc_client/cli_trust.c
@@ -0,0 +1,247 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
+ * Copyright (C) Paul Ashton 1997.
+ * Copyright (C) Jeremy Allison 1998.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Change the domain password on the PDC.
+**********************************************************/
+
+static BOOL modify_trust_password( char *domain, char *remote_machine,
+ unsigned char orig_trust_passwd_hash[16],
+ unsigned char new_trust_passwd_hash[16])
+{
+ struct cli_state cli;
+ NTSTATUS result;
+
+ ZERO_STRUCT(cli);
+ if(cli_initialise(&cli) == NULL) {
+ DEBUG(0,("modify_trust_password: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
+ DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (ismyip(cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: Machine %s is one of our addresses. Cannot add \
+to ourselves.\n", remote_machine));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: machine %s rejected the NetBIOS \
+session request. Error was %s\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ DEBUG(0,("modify_trust_password: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (cli.protocol != PROTOCOL_NT1) {
+ DEBUG(0,("modify_trust_password: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("modify_trust_password: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!(cli.sec_mode & 1)) {
+ DEBUG(0,("modify_trust_password: machine %s isn't in user level security mode\n",
+ remote_machine));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("modify_trust_password: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_lsa_get_domain_sid(&cli, remote_machine) == False) {
+ DEBUG(0,("modify_trust_password: unable to obtain domain sid from %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if(cli_nt_session_open(&cli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("modify_trust_password: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ result = cli_nt_setup_creds(&cli, orig_trust_passwd_hash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("modify_trust_password: unable to setup the PDC credentials to machine \
+%s. Error was : %s.\n", remote_machine, get_nt_error_msg(result)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if( cli_nt_srv_pwset( &cli,new_trust_passwd_hash ) == False) {
+ DEBUG(0,("modify_trust_password: unable to change password for machine %s in domain \
+%s to Domain controller %s. Error was %s.\n", global_myname, domain, remote_machine,
+ cli_errstr(&cli)));
+ cli_close(&cli, cli.nt_pipe_fnum);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+
+ return True;
+}
+
+/************************************************************************
+ Change the trust account password for a domain.
+ The user of this function must have locked the trust password file for
+ update.
+************************************************************************/
+
+BOOL change_trust_account_password( char *domain, char *remote_machine_list)
+{
+ fstring remote_machine;
+ unsigned char old_trust_passwd_hash[16];
+ unsigned char new_trust_passwd_hash[16];
+ time_t lct;
+ BOOL res = False;
+
+ if(!secrets_fetch_trust_account_password(domain, old_trust_passwd_hash, &lct)) {
+ DEBUG(0,("change_trust_account_password: unable to read the machine \
+account password for domain %s.\n", domain));
+ return False;
+ }
+
+ /*
+ * Create the new (random) password.
+ */
+ generate_random_buffer( new_trust_passwd_hash, 16, True);
+
+ while(remote_machine_list &&
+ next_token(&remote_machine_list, remote_machine,
+ LIST_SEP, sizeof(remote_machine))) {
+ strupper(remote_machine);
+ if(strequal(remote_machine, "*")) {
+
+ /*
+ * We have been asked to dynamcially determine the IP addresses of the PDC.
+ */
+
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+
+ /* Use the PDC *only* for this. */
+ if(!get_dc_list(True, domain, &ip_list, &count))
+ continue;
+
+ /*
+ * Try and connect to the PDC/BDC list in turn as an IP
+ * address used as a string.
+ */
+
+ for(i = 0; i < count; i++) {
+ fstring dc_name;
+ if(!lookup_pdc_name(global_myname, domain, &ip_list[i], dc_name))
+ continue;
+ if((res = modify_trust_password( domain, dc_name,
+ old_trust_passwd_hash, new_trust_passwd_hash)))
+ break;
+ }
+
+ SAFE_FREE(ip_list);
+
+ } else {
+ res = modify_trust_password( domain, remote_machine,
+ old_trust_passwd_hash, new_trust_passwd_hash);
+ }
+
+ if(res) {
+ DEBUG(0,("%s : change_trust_account_password: Changed password for \
+domain %s.\n", timestring(False), domain));
+ /*
+ * Return the result of trying to write the new password
+ * back into the trust account file.
+ */
+ res = secrets_store_trust_account_password(domain, new_trust_passwd_hash);
+ memset(new_trust_passwd_hash, 0, 16);
+ memset(old_trust_passwd_hash, 0, 16);
+ return res;
+ }
+ }
+
+ memset(new_trust_passwd_hash, 0, 16);
+ memset(old_trust_passwd_hash, 0, 16);
+
+ DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
+domain %s.\n", timestring(False), domain));
+ return False;
+}
diff --git a/source/utils/pdbedit.c b/source/utils/pdbedit.c
new file mode 100644
index 00000000000..6e7458fb4e9
--- /dev/null
+++ b/source/utils/pdbedit.c
@@ -0,0 +1,709 @@
+/*
+ Unix SMB/Netbios implementation.
+ passdb editing frontend
+ Version 3.0
+
+ Copyright (C) Simo Sorce 2000
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* base uid for trust accounts is set to 60000 !
+ * May be we should add the defines in smb.h to make it possible having
+ * different values on different platforms?
+ */
+
+#define BASE_MACHINE_UID 60000
+#define MAX_MACHINE_UID 65500 /* 5500 trust accounts aren't enough? */
+
+#include "includes.h"
+
+extern pstring global_myname;
+
+/*
+ * Next two lines needed for SunOS and don't
+ * hurt anything else...
+ */
+extern char *optarg;
+extern int optind;
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+static void usage(void)
+{
+ if (getuid() == 0) {
+ printf("tdbedit options\n");
+ } else {
+ printf("You need to be root to use this tool!\n");
+ }
+ printf("(actually to add a user you need to use smbpasswd)\n");
+ printf("options:\n");
+ printf(" -l list usernames\n");
+ printf(" -v verbose output\n");
+ printf(" -w smbpasswd file style\n");
+ printf(" -u username print user's info\n");
+ printf(" -f fullname set Full Name\n");
+ printf(" -h homedir set home directory\n");
+ printf(" -d drive set home dir drive\n");
+ printf(" -s script set logon script\n");
+ printf(" -p profile set profile path\n");
+ printf(" -a create new account\n");
+ printf(" -m it is a machine trust\n");
+ printf(" -x delete this user\n");
+ printf(" -i file import account from file (smbpasswd style)\n");
+ exit(1);
+}
+
+/*********************************************************
+ Print info from sam structure
+**********************************************************/
+
+static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdstyle)
+{
+ /* TODO: chaeck if entry is a user or a workstation */
+ if (!sam_pwent) return -1;
+
+ if (verbosity) {
+ printf ("username: %s\n", sam_pwent->username);
+ printf ("user ID/Group: %d/%d\n", sam_pwent->uid,
+ sam_pwent->gid);
+ printf ("user RID/GRID: %d/%d\n", sam_pwent->user_rid,
+ sam_pwent->group_rid);
+ printf ("Full Name: %s\n", sam_pwent->full_name);
+ printf ("Home Directory: %s\n", sam_pwent->home_dir);
+ printf ("HomeDir Drive: %s\n", sam_pwent->dir_drive);
+ printf ("Logon Script: %s\n", sam_pwent->logon_script);
+ printf ("Profile Path: %s\n", sam_pwent->profile_path);
+ } else if (smbpwdstyle) {
+ char lm_passwd[33];
+ char nt_passwd[33];
+ pdb_sethexpwd(lm_passwd,
+ pdb_get_lanman_passwd(sam_pwent),
+ pdb_get_acct_ctrl(sam_pwent));
+ pdb_sethexpwd(nt_passwd,
+ pdb_get_nt_passwd(sam_pwent),
+ pdb_get_acct_ctrl(sam_pwent));
+
+ printf("%s:%d:%s:%s:%s:LCT-%08X:\n",
+ pdb_get_username(sam_pwent),
+ pdb_get_uid(sam_pwent),
+ lm_passwd,
+ nt_passwd,
+ pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
+ (uint32)pdb_get_pass_last_set_time(sam_pwent));
+ } else {
+ printf ("%s:%d:%s\n", sam_pwent->username, sam_pwent->uid, sam_pwent->full_name);
+ }
+
+ return 0;
+}
+
+/*********************************************************
+ Get an Print User Info
+**********************************************************/
+
+static int print_user_info (char *username, BOOL verbosity, BOOL smbpwdstyle)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+
+ ret = pdb_getsampwnam (sam_pwent, username);
+
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ pdb_free_sam(&sam_pwent);
+
+ return ret;
+}
+
+/*********************************************************
+ List Users
+**********************************************************/
+static int print_users_list (BOOL verbosity, BOOL smbpwdstyle)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+
+ ret = pdb_setsampwent(False);
+ if (ret && errno == ENOENT) {
+ fprintf (stderr,"Password database not found!\n");
+ pdb_free_sam(&sam_pwent);
+ exit(1);
+ }
+
+ while ((ret = pdb_getsampwent (sam_pwent))) {
+ if (verbosity)
+ printf ("---------------\n");
+ print_sam_info (sam_pwent, verbosity, smbpwdstyle);
+ pdb_reset_sam(sam_pwent);
+ }
+
+ pdb_endsampwent ();
+ pdb_free_sam(&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Set User Info
+**********************************************************/
+
+static int set_user_info (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ BOOL ret;
+
+ pdb_init_sam(&sam_pwent);
+
+ ret = pdb_getsampwnam (sam_pwent, username);
+ if (ret==False) {
+ fprintf (stderr, "Username not found!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname);
+ if (homedir)
+ pdb_set_homedir(sam_pwent, homedir);
+ if (drive)
+ pdb_set_dir_drive(sam_pwent,drive);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile);
+
+ if (pdb_update_sam_account (sam_pwent, True))
+ print_user_info (username, True, False);
+ else {
+ fprintf (stderr, "Unable to modify entry!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam(&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New User
+**********************************************************/
+static int new_user (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ struct passwd *pwd = NULL;
+ char *password1, *password2;
+
+ ZERO_STRUCT(sam_pwent);
+
+ pdb_init_sam (&sam_pwent);
+
+ if (!(pwd = sys_getpwnam(username))) {
+ fprintf (stderr, "User %s does not exist in system passwd!\n", username);
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+
+ password1 = getpass("new password:");
+ password2 = getpass("retype new password:");
+ if (strcmp (password1, password2)) {
+ fprintf (stderr, "Passwords does not match!\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+
+ pdb_set_plaintext_passwd(sam_pwent, password1);
+
+ pdb_set_username(sam_pwent, username);
+ if (fullname)
+ pdb_set_fullname(sam_pwent, fullname);
+ if (homedir)
+ pdb_set_homedir (sam_pwent, homedir);
+ if (drive)
+ pdb_set_dir_drive (sam_pwent, drive);
+ if (script)
+ pdb_set_logon_script(sam_pwent, script);
+ if (profile)
+ pdb_set_profile_path (sam_pwent, profile);
+
+ /* TODO: Check uid not being in MACHINE UID range!! */
+ pdb_set_uid (sam_pwent, pwd->pw_uid);
+ pdb_set_gid (sam_pwent, pwd->pw_gid);
+ pdb_set_user_rid (sam_pwent, pdb_uid_to_user_rid (pwd->pw_uid));
+ pdb_set_group_rid (sam_pwent, pdb_gid_to_group_rid (pwd->pw_gid));
+
+ pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL);
+
+ if (pdb_add_sam_account (sam_pwent)) {
+ print_user_info (username, True, False);
+ } else {
+ fprintf (stderr, "Unable to add user! (does it alredy exist?)\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam (&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Add New Machine
+**********************************************************/
+
+static int new_machine (char *machinename)
+{
+ SAM_ACCOUNT *sam_pwent=NULL;
+ SAM_ACCOUNT *sam_trust=NULL;
+ char name[16];
+ char *password = NULL;
+ uid_t uid;
+
+ pdb_init_sam (&sam_pwent);
+
+ if (machinename[strlen (machinename) -1] == '$')
+ machinename[strlen (machinename) -1] = '\0';
+
+ safe_strcpy (name, machinename, 16);
+ safe_strcat (name, "$", 16);
+
+ string_set (&password, machinename);
+ strlower_m(password);
+
+ pdb_set_plaintext_passwd (sam_pwent, password);
+
+ pdb_set_username (sam_pwent, name);
+
+ for (uid=BASE_MACHINE_UID; uid<=MAX_MACHINE_UID; uid++) {
+ pdb_init_sam (&sam_trust);
+ if (pdb_getsampwuid (sam_trust, uid)) {
+ pdb_free_sam (&sam_trust);
+ } else {
+ break;
+ }
+ }
+
+ if (uid>MAX_MACHINE_UID) {
+ fprintf (stderr, "No more free UIDs available to Machine accounts!\n");
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+
+ pdb_set_uid (sam_pwent, uid);
+ pdb_set_gid (sam_pwent, BASE_MACHINE_UID); /* TODO: set there more appropriate value!! */
+ pdb_set_user_rid (sam_pwent,pdb_uid_to_user_rid (uid));
+ pdb_set_group_rid (sam_pwent, pdb_gid_to_group_rid (BASE_MACHINE_UID));
+ pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST);
+
+ if (pdb_add_sam_account (sam_pwent)) {
+ print_user_info (name, True, False);
+ } else {
+ fprintf (stderr, "Unable to add machine! (does it already exist?)\n");
+ pdb_free_sam (&sam_pwent);
+ return -1;
+ }
+ pdb_free_sam (&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Delete user entry
+**********************************************************/
+
+static int delete_user_entry (char *username)
+{
+ return pdb_delete_sam_account (username);
+}
+
+/*********************************************************
+ Delete machine entry
+**********************************************************/
+
+static int delete_machine_entry (char *machinename)
+{
+ char name[16];
+
+ safe_strcpy (name, machinename, 16);
+ if (name[strlen(name)] != '$')
+ safe_strcat (name, "$", 16);
+ return pdb_delete_sam_account (name);
+}
+
+/*********************************************************
+ Import smbpasswd style file
+**********************************************************/
+
+static int import_users (char *filename)
+{
+ FILE *fp = NULL;
+ SAM_ACCOUNT *sam_pwent = NULL;
+ static pstring user_name;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+ char linebuf[256];
+ size_t linebuf_len;
+ unsigned char c;
+ unsigned char *p;
+ long uidval;
+ int line = 0;
+ int good = 0;
+
+ if (!pdb_init_sam (&sam_pwent)) {
+ fprintf (stderr, "pdb_init_sam FAILED!\n");
+ }
+
+ if((fp = sys_fopen(filename, "rb")) == NULL) {
+ fprintf (stderr, "%s\n", strerror (ferror (fp)));
+ return -1;
+ }
+
+ while (!feof(fp)) {
+ /*Get a new line*/
+ linebuf[0] = '\0';
+ fgets(linebuf, 256, fp);
+ if (ferror(fp)) {
+ fprintf (stderr, "%s\n", strerror (ferror (fp)));
+ pdb_free_sam(&sam_pwent);
+ return -1;
+ }
+ if ((linebuf_len = strlen(linebuf)) == 0) {
+ line++;
+ continue;
+ }
+ if (linebuf[linebuf_len - 1] != '\n') {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp)) {
+ c = fgetc(fp);
+ if (c == '\n') break;
+ }
+ } else
+ linebuf[linebuf_len - 1] = '\0';
+ linebuf[linebuf_len] = '\0';
+ if ((linebuf[0] == 0) && feof(fp)) {
+ /*end of file!!*/
+ pdb_free_sam(&sam_pwent);
+ return 0;
+ }
+ line++;
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ continue;
+
+ pdb_set_acct_ctrl (sam_pwent,ACB_NORMAL);
+
+ /* Get user name */
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL) {
+ fprintf (stderr, "Error: malformed password entry at line %d !!\n", line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+ /* Get smb uid. */
+ p++;
+ if(*p == '-') {
+ fprintf (stderr, "Error: negative uid at line %d\n", line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ if (!isdigit(*p)) {
+ fprintf (stderr, "Error: malformed password entry at line %d (uid not number)\n", line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ uidval = atoi((char *) p);
+ while (*p && isdigit(*p)) p++;
+ if (*p != ':') {
+ fprintf (stderr, "Error: malformed password entry at line %d (no : after uid)\n", line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+
+ pdb_set_username(sam_pwent, user_name);
+ pdb_set_uid (sam_pwent, uidval);
+
+ /* Get passwords */
+ p++;
+ if (*p == '*' || *p == 'X') {
+ /* Password deliberately invalid */
+ fprintf (stderr, "Warning: entry invalidated for user %s\n", user_name);
+ pdb_set_lanman_passwd(sam_pwent, NULL);
+ pdb_set_nt_passwd(sam_pwent,NULL);
+ pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_DISABLED);
+ } else {
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+ fprintf (stderr, "Error: malformed password entry at line %d (password too short)\n",line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ if (p[32] != ':') {
+ fprintf (stderr, "Error: malformed password entry at line %d (no terminating :)\n",line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+ pdb_set_lanman_passwd(sam_pwent, NULL);
+ pdb_set_acct_ctrl(sam_pwent, pdb_get_acct_ctrl(sam_pwent) | ACB_PWNOTREQ);
+ } else {
+ if (!pdb_gethexpwd((char *)p, smbpwd)) {
+ fprintf (stderr, "Error: malformed Lanman password entry at line %d (non hex chars)\n", line);
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ pdb_set_lanman_passwd(sam_pwent, smbpwd);
+ }
+ /* NT password */
+ p += 33;
+ if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+ if (*p != '*' && *p != 'X') {
+ if (pdb_gethexpwd((char *)p,smbntpwd)) {
+ pdb_set_nt_passwd(sam_pwent, smbntpwd);
+ }
+ }
+ p += 33;
+ }
+ }
+
+ /* Get ACCT_CTRL field if any */
+ if (*p == '[') {
+ uint16 acct_ctrl;
+ unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+
+ acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+ if (acct_ctrl)
+ acct_ctrl = ACB_NORMAL;
+
+ pdb_set_acct_ctrl(sam_pwent, acct_ctrl);
+
+ /* Get last change time */
+ if(end_p)
+ p = end_p + 1;
+ if(*p == ':') {
+ p++;
+ if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+ int i;
+
+ p += 4;
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit(p[i])) break;
+ }
+ if(i == 8) {
+ pdb_set_pass_last_set_time (sam_pwent, (time_t)strtol((char *)p, NULL, 16));
+ }
+ }
+ }
+ }
+
+ /* Old-style workstation account code droped. */
+
+ if (pdb_get_acct_ctrl(sam_pwent) & ACB_WSTRUST) {
+ if ((uidval < BASE_MACHINE_UID) || (uidval > MAX_MACHINE_UID)) {
+ fprintf (stderr, "Warning: Machine UID out of normal range %d-%d\n",
+ BASE_MACHINE_UID,
+ MAX_MACHINE_UID);
+ }
+ pdb_set_uid(sam_pwent, BASE_MACHINE_UID);
+ }
+
+ /* Test if user is valid */
+ if (pdb_get_acct_ctrl(sam_pwent) & ACB_NORMAL) {
+ struct passwd *pwd = NULL;
+
+ if (!(pwd = sys_getpwnam(user_name))) {
+ fprintf (stderr, "Error: User %s does not exist in system passwd!\n", user_name);
+ continue;
+ }
+ pdb_set_gid(sam_pwent, pwd->pw_gid);
+ }
+
+ /* Fill in sam_pwent structure */
+ pdb_set_user_rid(sam_pwent, pdb_uid_to_user_rid (pdb_get_uid(sam_pwent)));
+ pdb_set_group_rid(sam_pwent, pdb_gid_to_group_rid (pdb_get_gid(sam_pwent)));
+
+ /* TODO: set also full_name, home_dir, dir_drive, logon_script, profile_path, ecc...
+ * when defaults will be available (after passdb redesign)
+ * let them blank just now they are not used anyway
+ */
+
+ /* Now ADD the entry */
+ if (!(pdb_add_sam_account (sam_pwent))) {
+ fprintf (stderr, "Unable to add user entry!\n");
+ pdb_reset_sam (sam_pwent);
+ continue;
+ }
+ printf ("%s imported!\n", user_name);
+ good++;
+ pdb_reset_sam (sam_pwent);
+ }
+ printf ("%d lines read.\n%d entryes imported\n", line, good);
+ pdb_free_sam(&sam_pwent);
+ return 0;
+}
+
+/*********************************************************
+ Start here.
+**********************************************************/
+
+int main (int argc, char **argv)
+{
+ int ch;
+ static pstring servicesf = CONFIGFILE;
+ BOOL list_users = False;
+ BOOL verbose = False;
+ BOOL spstyle = False;
+ BOOL setparms = False;
+ BOOL machine = False;
+ BOOL add_user = False;
+ BOOL delete_user = False;
+ BOOL import = False;
+ char *user_name = NULL;
+ char *full_name = NULL;
+ char *home_dir = NULL;
+ char *home_drive = NULL;
+ char *logon_script = NULL;
+ char *profile_path = NULL;
+ char *smbpasswd = NULL;
+
+ TimeInit();
+
+ setup_logging("tdbedit", True);
+
+ if (argc < 2) {
+ usage();
+ return 0;
+ }
+
+ if(!initialize_password_db(True)) {
+ fprintf(stderr, "Can't setup password database vectors.\n");
+ exit(1);
+ }
+
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ servicesf);
+ exit(1);
+ }
+
+ while ((ch = getopt(argc, argv, "ad:f:h:i:lmp:s:u:vwx")) != EOF) {
+ switch(ch) {
+ case 'a':
+ add_user = True;
+ break;
+ case 'm':
+ machine = True;
+ break;
+ case 'l':
+ list_users = True;
+ break;
+ case 'v':
+ verbose = True;
+ break;
+ case 'w':
+ spstyle = True;
+ break;
+ case 'u':
+ user_name = optarg;
+ break;
+ case 'f':
+ setparms = True;
+ full_name = optarg;
+ break;
+ case 'h':
+ setparms = True;
+ home_dir = optarg;
+ break;
+ case 'd':
+ setparms = True;
+ home_drive = optarg;
+ break;
+ case 's':
+ setparms = True;
+ logon_script = optarg;
+ break;
+ case 'p':
+ setparms = True;
+ profile_path = optarg;
+ break;
+ case 'x':
+ delete_user = True;
+ break;
+ case 'i':
+ import = True;
+ smbpasswd = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (((add_user?1:0) + (delete_user?1:0) + (list_users?1:0) + (import?1:0) + (setparms?1:0)) > 1) {
+ fprintf (stderr, "Incompatible options on command line!\n");
+ usage();
+ exit(1);
+ }
+
+ if (add_user) {
+ if (!user_name) {
+ fprintf (stderr, "Username not specified! (use -u option)\n");
+ return -1;
+ }
+ if (machine)
+ return new_machine (user_name);
+ else
+ return new_user (user_name, full_name, home_dir, home_drive, logon_script, profile_path);
+ }
+
+ if (delete_user) {
+ if (!user_name) {
+ fprintf (stderr, "Username not specified! (use -u option)\n");
+ return -1;
+ }
+ if (machine)
+ return delete_machine_entry (user_name);
+ else
+ return delete_user_entry (user_name);
+ }
+
+ if (user_name) {
+ if (setparms)
+ set_user_info ( user_name, full_name,
+ home_dir,
+ home_drive,
+ logon_script,
+ profile_path);
+ else
+ return print_user_info (user_name, verbose, spstyle);
+
+ return 0;
+ }
+
+
+ if (list_users)
+ return print_users_list (verbose, spstyle);
+
+ if (import)
+ return import_users (smbpasswd);
+
+ usage();
+
+ return 0;
+}