[PATCH] Add PAM session support

Andrew Bartlett abartlet at pcug.org.au
Wed Apr 18 02:39:57 GMT 2001


This patch adds PAM session support to samba, in much the same way that
utmp support was added.  I understand that this is not an ideal
implementation, but its what I know works.

If people have any ideas on a better implementation, feel free to
comment :-)

This patch also cleans up the arguments to claim_connection(), as the
last 2 are not used anymore.

Andrew Bartlett
abartlet at pcug.org.au
-- 
Andrew Bartlett
abartlet at pcug.org.au
-------------- next part --------------
Index: source/smbd/connection.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/connection.c,v
retrieving revision 1.20.4.7
diff -u -r1.20.4.7 connection.c
--- source/smbd/connection.c	2001/04/08 20:22:54	1.20.4.7
+++ source/smbd/connection.c	2001/04/18 00:41:59
@@ -28,10 +28,36 @@
 extern int DEBUGLEVEL;
 
 #ifdef WITH_UTMP
-static void utmp_yield(pid_t pid, const connection_struct *conn);
-static void utmp_claim(const struct connections_data *crec, const connection_struct *conn);
+static BOOL utmp_yield(pid_t pid, const connection_struct *conn);
+static BOOL utmp_claim(const struct connections_data *crec, const connection_struct *conn);
 #endif
+#ifdef WITH_PAM
+static BOOL claim_pam(const connection_struct *conn);
+static BOOL yield_pam(const connection_struct *conn);
+#endif
+#if defined(WITH_UTMP) || defined(WITH_PAM)
+static int cnum_claim_tdb(const connection_struct *conn);
+static int cnum_yield_tdb(const connection_struct *conn);
+static int cnum_fetch_tdb(const connection_struct *conn);
+
+/* This is also used with the PAM 'tty' so I moved it up here 
+   - Andrew Bartlett */
 
+/*
+ * ut_line:
+ *	size small, e.g. Solaris: 12;  FreeBSD: 8
+ *	pattern conventions differ across systems.
+ * So take care in tweaking the template below.
+ * Arguably, this could be yet another smb.conf parameter.
+ */
+static const char *ut_line_template =
+#if defined(__FreeBSD__)
+	"smb%d" ;
+#else
+	"smb/%d" ;
+#endif
+#endif
+
 /****************************************************************************
  Return the connection tdb context (used for message send all).
 ****************************************************************************/
@@ -49,6 +75,8 @@
 	struct connections_key key;
 	TDB_DATA kbuf;
 
+	BOOL ret = True;
+
 	if (!tdb) return False;
 
 	DEBUG(3,("Yielding connection to %s\n",name));
@@ -68,27 +96,41 @@
 	if(conn)
 		utmp_yield(key.pid, conn);
 #endif
+
+#ifdef WITH_PAM
+	if(conn)
+	  ret = yield_pam(conn);
+#else 
+	ret = True;
+#endif
+
+#if defined(WITH_UTMP) || defined(WITH_PAM)
+	if (conn)
+	  cnum_yield_tdb(conn);
+#endif
 
-	return(True);
+	return ret;
 }
 
 
 /****************************************************************************
 claim an entry in the connections database
 ****************************************************************************/
-BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
+BOOL claim_connection(connection_struct *conn,char *name)
 {
 	struct connections_key key;
 	struct connections_data crec;
 	TDB_DATA kbuf, dbuf;
 
+	BOOL ret = False;
+
 	if (!tdb) {
 		tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST, 
 			       O_RDWR | O_CREAT, 0644);
 	}
 	if (!tdb) return False;
 
-	DEBUG(5,("claiming %s %d\n",name,max_connections));
+	DEBUG(5,("claiming connection for %s\n",name));
 
 	ZERO_STRUCT(key);
 	key.pid = sys_getpid();
@@ -120,13 +162,183 @@
 
 	if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
 
-#ifdef WITH_UTMP
+#if defined(WITH_UTMP) || defined(WITH_PAM)
 	if (conn)
+	  if (cnum_claim_tdb(conn) == -1)
+	    return False;
+#endif
+
+#ifdef WITH_PAM
+	if(conn)
+	  ret = claim_pam(conn);
+#else 
+	ret = True;
+#endif
+
+
+#ifdef WITH_UTMP
+	if (conn && ret)
 	    utmp_claim(&crec, conn);
 #endif
 
-	return True;
+	return ret;
+}
+
+#if defined(WITH_UTMP) || defined(WITH_PAM)
+/****************************************************************************
+obtain/release a small number (0 upwards) unique within and across smbds
+****************************************************************************/
+/*
+ * Need a "small" number to represent this connection, unique within this
+ * smbd and across all smbds.
+ *
+ * claim:
+ *	Start at 0, hunt up for free, unique number "unum" by attempting to
+ *	store it as a key in a tdb database:
+ *		key: unum		data: pid+conn  
+ *	Also store its inverse, ready for yield function:
+ *		key: pid+conn		data: unum
+ *
+ * yield:
+ *	Find key: pid+conn; data is unum;  delete record
+ *	Find key: unum ; delete record.
+ *
+ * Comment:
+ *	The claim algorithm (a "for" loop attempting to store numbers in a tdb
+ *	database) will be increasingly inefficient with larger numbers of
+ *	connections.  Is it possible to write a suitable primitive within tdb?
+ *
+ *	However, by also storing the inverse key/data pair, we at least make
+ *	the yield algorithm efficient.
+ */
+
+static TDB_CONTEXT *tdb_cnum;
+
+struct cnum_tdb_data {
+	pid_t pid;
+	int cnum;
+};
+
+static int cnum_claim_tdb(const connection_struct *conn)
+{
+	struct cnum_tdb_data udata;
+	int i, slotnum;
+	TDB_DATA kbuf, dbuf;
+
+	if (!tdb_cnum) {
+		tdb_cnum = tdb_open(lock_path("cnum.tdb"), 0,
+				TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+	}
+	if (!tdb_cnum) return(-1);
+
+	DEBUG(2,("cnum_claim_tdb: entered\n"));
+
+	ZERO_STRUCT(udata);
+	udata.pid = sys_getpid();
+	udata.cnum = conn ? conn->cnum : -1;
+
+	dbuf.dptr = (char *) &udata;
+	dbuf.dsize = sizeof(udata);
+
+	/* The key is simply a number as close as possible to zero: find it */
+	slotnum = -1;
+	/* stop loop when overflow +ve integers (a huge, busy machine!) */
+	for (i = 0; i >= 0 ; i++) {
+		kbuf.dptr = (char *) &i;
+		kbuf.dsize = sizeof(i);
+
+		if (tdb_store(tdb_cnum, kbuf, dbuf, TDB_INSERT) == 0) {
+			/* have successfully grabbed a free slot */
+			slotnum = i;
+
+			/* store the inverse for faster cnum_yield_tdb() */
+			tdb_store(tdb_cnum, dbuf, kbuf, TDB_INSERT);
+
+			break;	/* Got it; escape */
+		}
+	}
+	if (slotnum < 0) {	/* more connections than positive integers! */
+		DEBUG(2,("cnum_claim_tdb: failed\n"));
+		return(-1);
+	}
+
+	DEBUG(2,("cnum_claim_tdb: leaving with %d\n", slotnum));
+
+	return(slotnum);
+}
+
+static int cnum_yield_tdb(const connection_struct *conn)
+{
+	struct cnum_tdb_data revkey;
+	int slotnum;
+	TDB_DATA kbuf, dbuf;
+
+	if (!tdb_cnum) {
+		return(-1);
+	}
+
+	DEBUG(2,("cnum_yield_tdb: entered\n"));
+
+	ZERO_STRUCT(revkey);
+	revkey.pid = sys_getpid();
+	revkey.cnum = conn ? conn->cnum : -1;
+
+	kbuf.dptr = (char *) &revkey;
+	kbuf.dsize = sizeof(revkey);
+
+	dbuf = tdb_fetch(tdb_cnum, kbuf);
+	if (dbuf.dptr == NULL) {
+		DEBUG(2,("cnum_yield_tdb: failed\n"));
+		return(-1);		/* shouldn't happen */
+	}
+
+	/* Save our result */
+	slotnum = *((int*)dbuf.dptr);
+
+	/* Tidy up */
+	tdb_delete(tdb_cnum, kbuf);
+	tdb_delete(tdb_cnum, dbuf);
+
+	free(dbuf.dptr);
+	DEBUG(2,("cnum_yield_tdb: leaving with %d\n", slotnum));
+
+	return(slotnum);
+}
+
+static int cnum_fetch_tdb(const connection_struct *conn)
+{
+	struct cnum_tdb_data revkey;
+	int slotnum;
+	TDB_DATA kbuf, dbuf;
+
+	if (!tdb_cnum) {
+		return(-1);
+	}
+
+	DEBUG(2,("cnum_fetch_tdb: entered\n"));
+
+	ZERO_STRUCT(revkey);
+	revkey.pid = sys_getpid();
+	revkey.cnum = conn ? conn->cnum : -1;
+
+	kbuf.dptr = (char *) &revkey;
+	kbuf.dsize = sizeof(revkey);
+
+	dbuf = tdb_fetch(tdb_cnum, kbuf);
+	if (dbuf.dptr == NULL) {
+		DEBUG(2,("cnum_fetch_tdb: failed\n"));
+		return(-1);		/* shouldn't happen */
+	}
+
+	/* Save our result */
+	slotnum = *((int*)dbuf.dptr);
+
+	free(dbuf.dptr);
+	DEBUG(2,("cnum_fetch_tdb: leaving with %d\n", slotnum));
+
+	return(slotnum);
 }
+#endif
 
 #ifdef WITH_UTMP
 
@@ -232,126 +444,6 @@
 #include <lastlog.h>
 #endif
 
-/****************************************************************************
-obtain/release a small number (0 upwards) unique within and across smbds
-****************************************************************************/
-/*
- * Need a "small" number to represent this connection, unique within this
- * smbd and across all smbds.
- *
- * claim:
- *	Start at 0, hunt up for free, unique number "unum" by attempting to
- *	store it as a key in a tdb database:
- *		key: unum		data: pid+conn  
- *	Also store its inverse, ready for yield function:
- *		key: pid+conn		data: unum
- *
- * yield:
- *	Find key: pid+conn; data is unum;  delete record
- *	Find key: unum ; delete record.
- *
- * Comment:
- *	The claim algorithm (a "for" loop attempting to store numbers in a tdb
- *	database) will be increasingly inefficient with larger numbers of
- *	connections.  Is it possible to write a suitable primitive within tdb?
- *
- *	However, by also storing the inverse key/data pair, we at least make
- *	the yield algorithm efficient.
- */
-
-static TDB_CONTEXT *tdb_utmp;
-
-struct utmp_tdb_data {
-	pid_t pid;
-	int cnum;
-};
-
-static int utmp_claim_tdb(const connection_struct *conn)
-{
-	struct utmp_tdb_data udata;
-	int i, slotnum;
-	TDB_DATA kbuf, dbuf;
-
-	if (!tdb_utmp) {
-		tdb_utmp = tdb_open(lock_path("utmp.tdb"), 0,
-				TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
-	}
-	if (!tdb_utmp) return(-1);
-
-	DEBUG(2,("utmp_claim_tdb: entered\n"));
-
-	ZERO_STRUCT(udata);
-	udata.pid = sys_getpid();
-	udata.cnum = conn ? conn->cnum : -1;
-
-	dbuf.dptr = (char *) &udata;
-	dbuf.dsize = sizeof(udata);
-
-	/* The key is simply a number as close as possible to zero: find it */
-	slotnum = -1;
-	/* stop loop when overflow +ve integers (a huge, busy machine!) */
-	for (i = 0; i >= 0 ; i++) {
-		kbuf.dptr = (char *) &i;
-		kbuf.dsize = sizeof(i);
-
-		if (tdb_store(tdb_utmp, kbuf, dbuf, TDB_INSERT) == 0) {
-			/* have successfully grabbed a free slot */
-			slotnum = i;
-
-			/* store the inverse for faster utmp_yield_tdb() */
-			tdb_store(tdb_utmp, dbuf, kbuf, TDB_INSERT);
-
-			break;	/* Got it; escape */
-		}
-	}
-	if (slotnum < 0) {	/* more connections than positive integers! */
-		DEBUG(2,("utmp_claim_tdb: failed\n"));
-		return(-1);
-	}
-
-	DEBUG(2,("utmp_claim_tdb: leaving with %d\n", slotnum));
-
-	return(slotnum);
-}
-
-static int utmp_yield_tdb(const connection_struct *conn)
-{
-	struct utmp_tdb_data revkey;
-	int i, slotnum;
-	TDB_DATA kbuf, dbuf;
-
-	if (!tdb_utmp) {
-		return(-1);
-	}
-
-	DEBUG(2,("utmp_yield_tdb: entered\n"));
-
-	ZERO_STRUCT(revkey);
-	revkey.pid = sys_getpid();
-	revkey.cnum = conn ? conn->cnum : -1;
-
-	kbuf.dptr = (char *) &revkey;
-	kbuf.dsize = sizeof(revkey);
-
-	dbuf = tdb_fetch(tdb_utmp, kbuf);
-	if (dbuf.dptr == NULL) {
-		DEBUG(2,("utmp_yield_tdb: failed\n"));
-		return(-1);		/* shouldn't happen */
-	}
-
-	/* Save our result */
-	slotnum = *((int*) dbuf.dptr);
-
-	/* Tidy up */
-	tdb_delete(tdb_utmp, kbuf);
-	tdb_delete(tdb_utmp, dbuf);
-
-	free(dbuf.dptr);
-	DEBUG(2,("utmp_yield_tdb: leaving with %d\n", slotnum));
-
-	return(slotnum);
-}
-
 #if defined(HAVE_UT_UT_ID)
 /****************************************************************************
 encode the unique connection number into "ut_id"
@@ -384,20 +476,6 @@
 }
 #endif /* defined(HAVE_UT_UT_ID) */
 
-/*
- * ut_line:
- *	size small, e.g. Solaris: 12;  FreeBSD: 8
- *	pattern conventions differ across systems.
- * So take care in tweaking the template below.
- * Arguably, this could be yet another smb.conf parameter.
- */
-static const char *ut_line_template =
-#if defined(__FreeBSD__)
-	"smb%d" ;
-#else
-	"smb/%d" ;
-#endif
-
 /****************************************************************************
 Fill in a utmp (not utmpx) template
 ****************************************************************************/
@@ -776,20 +854,25 @@
 /****************************************************************************
 close a connection
 ****************************************************************************/
-static void utmp_yield(pid_t pid, const connection_struct *conn)
+static BOOL utmp_yield(pid_t pid, const connection_struct *conn)
 {
 	struct utmp u;
 	int conn_num, i;
 
 	if (! lp_utmp(SNUM(conn))) {
 		DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
-		return;
+		return True;
 	}
+
+	if (! strcmp(lp_servicename(SNUM(conn)), "IPC$")) {
+	        DEBUG(5,("utmp_yield: NO utmp entries for IPC$ service\n"));
+	        return True;
+	};
 
-	i = utmp_yield_tdb(conn);
+	i = cnum_fetch_tdb(conn);
 	if (i < 0) {
-		DEBUG(2,("utmp_yield: utmp_yield_tdb() failed\n"));
-		return;
+		DEBUG(2,("utmp_yield: cnum_fetch_tdb() failed\n"));
+		return False;
 	}
 	conn_num = i;
 	DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
@@ -799,7 +882,7 @@
 	if (lp_utmp_consolidate()) {
 		if (utmp_count > 0) {
 			DEBUG(2,("utmp_yield: utmp consolidate: %d entries still open\n", utmp_count));
-			return;
+			return True;
 		}
 		else {
 			/* consolidate; final close: override conn_num  */
@@ -821,12 +904,15 @@
 	if (utmp_fill(&u, conn, pid, conn_num, NULL) == 0) {
 		utmp_update(&u, NULL, False);
 	}
+
+	return True;
+
 }
 
 /****************************************************************************
 open a connection
 ****************************************************************************/
-static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
+static BOOL utmp_claim(const struct connections_data *crec, const connection_struct *conn)
 {
 	struct utmp u;
 	pstring host;
@@ -834,18 +920,23 @@
 
 	if (conn == NULL) {
 		DEBUG(2,("utmp_claim: conn NULL\n"));
-		return;
+		return False;
 	}
 
 	if (! lp_utmp(SNUM(conn))) {
 		DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
-		return;
+		return True;
 	}
 
-	i = utmp_claim_tdb(conn);
+	if (! strcmp(lp_servicename(SNUM(conn)), "IPC$")) {
+	        DEBUG(5,("utmp_claim: NO utmp entries for IPC$ service\n"));
+	        return True;
+	}
+
+	i = cnum_fetch_tdb(conn);
 	if (i < 0) {
-		DEBUG(2,("utmp_claim: utmp_claim_tdb() failed\n"));
-		return;
+		DEBUG(2,("utmp_claim: cnum_fetch_tdb() failed\n"));
+		return False;
 	}
 
 	pstrcpy(host, lp_utmp_hostname());
@@ -866,7 +957,7 @@
 	if (lp_utmp_consolidate()) {
 		if (utmp_count > 1) {
 			DEBUG(2,("utmp_claim: utmp consolidate: %d entries already open\n", (utmp_count-1)));
-			return;
+			return True;
 		}
 		else {
 			/* consolidate; first open: keep record of "i" */
@@ -883,6 +974,44 @@
 	if (utmp_fill(&u, conn, crec->pid, i, host) == 0) {
 		utmp_update(&u, host, True);
 	}
-}
 
+	return True;
+
+}
 #endif	/* WITH_UTMP */
+
+#ifdef WITH_PAM
+/*******************************************************************
+ PAM Session handling (same idea as utmp, just with pam)
+
+  Despite what it looks this patch does have a practical purpose:
+  This system allows the administrator to use modules like 'pam_limits'
+  that work on a per session basis. It can be used with ANY pam 
+  session module (AFAIK).
+
+  (c) Andrew Bartlett 2001
+********************************************************************/
+
+static BOOL claim_pam(const connection_struct *conn)
+{
+  int cnum;
+  char tty[1024];
+  cnum = cnum_fetch_tdb(conn);
+  slprintf(tty, sizeof(tty), (char *) ut_line_template, cnum);
+  return pam_session(True, conn, tty);
+}
+
+static BOOL yield_pam(const connection_struct *conn)
+{
+  int cnum;
+  char tty[1024];
+  cnum = cnum_fetch_tdb(conn);
+  slprintf(tty, sizeof(tty), (char *) ut_line_template, cnum);
+  return pam_session(False, conn, tty);
+}
+
+#endif	/* WITH_PAM */
+
+
+
+
Index: source/smbd/reply.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/reply.c,v
retrieving revision 1.240.2.26
diff -u -r1.240.2.26 reply.c
--- source/smbd/reply.c	2001/04/13 04:09:39	1.240.2.26
+++ source/smbd/reply.c	2001/04/18 00:42:11
Index: source/smbd/server.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/server.c,v
retrieving revision 1.305.2.16
diff -u -r1.305.2.16 server.c
--- source/smbd/server.c	2001/04/09 06:36:14	1.305.2.16
+++ source/smbd/server.c	2001/04/18 00:42:13
@@ -742,7 +742,7 @@
 
 	/* Setup the main smbd so that we can get messages. */
 	if (lp_status(-1)) {
-		claim_connection(NULL,"",MAXSTATUS,True);
+		claim_connection(NULL,"");
 	}
 
 	/* Attempt to migrate from an old 2.0.x machine account file. */
Index: source/smbd/service.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/service.c,v
retrieving revision 1.31.2.21
diff -u -r1.31.2.21 service.c
--- source/smbd/service.c	2001/04/13 04:09:39	1.31.2.21
+++ source/smbd/service.c	2001/04/18 00:42:15
@@ -493,9 +493,7 @@
 		
 	/* check number of connections */
 	if (!claim_connection(conn,
-			      lp_servicename(SNUM(conn)),
-			      lp_max_connections(SNUM(conn)),
-			      False)) {
+			      lp_servicename(SNUM(conn)))) {
 		DEBUG(1,("too many connections - rejected\n"));
 		*ecode = ERRnoresource;
 		conn_free(conn);


More information about the samba-technical mailing list