Index: configure.in
===================================================================
RCS file: /home/cvs/gateway/configure.in,v
retrieving revision 1.186
diff -u -b -w -r1.186 configure.in
--- configure.in	4 May 2009 21:35:52 -0000	1.186
+++ configure.in	10 Jun 2009 10:32:41 -0000
@@ -665,26 +665,6 @@
 ])
 
 
-dnl Implement the --enable-pam option.
-
-AC_ARG_ENABLE(pam,
-[  --enable-pam	          enable PAM authentication @<:@disabled@:>@], [
-    if test "$enableval" = "yes"
-    then
-	AC_CHECK_LIB(pam, pam_end)
-	AC_CHECK_LIB(dl,main)
-	AC_CHECK_HEADERS(security/pam_appl.h)
-	PAMTARGET="pam"
-    else
-	PAMTARGET="no-pam"
-    fi
-])
-case "$PAMTARGET" in
-no-pam) echo PAM authentication is disabled. ;;
-pam) echo PAM authentication is enabled. ;;
-esac
-
-
 dnl Implement --enable-debug option.
 
 AC_ARG_ENABLE(debug,
@@ -785,6 +765,31 @@
 ])
 
 
+dnl Implement the --enable-pam option.
+
+AC_CONFIG_SECTION([Configuring PAM support])
+
+AC_MSG_CHECKING([whether to compile with PAM support])
+AC_ARG_ENABLE(pam,
+[  --enable-pam	          enable PAM authentication @<:@disabled@:>@], [
+  if test "$enableval" = "yes"
+  then
+    AC_CHECK_LIB(pam, pam_end)
+    AC_CHECK_LIB(dl,main)
+    AC_CHECK_HEADER([security/pam_appl.h],
+      AC_DEFINE(HAVE_PAM_SECURITY) \
+      AC_DEFINE(HAVE_PAM) \
+      AC_MSG_RESULT([enabling PAM for authentication]),
+      [AC_CHECK_HEADER([pam/pam_appl.h],
+        AC_DEFINE(HAVE_PAM_PAM) \
+        AC_DEFINE(HAVE_PAM) \
+        AC_MSG_RESULT([enabling PAM for authentication])
+      )]
+    )
+  fi
+])
+
+
 dnl Implement the --with-ssl option.
 
 AC_CONFIG_SECTION([Configuring OpenSSL support])
Index: gw-config.h.in
===================================================================
RCS file: /home/cvs/gateway/gw-config.h.in,v
retrieving revision 1.23
diff -u -b -w -r1.23 gw-config.h.in
--- gw-config.h.in	4 May 2009 21:35:53 -0000	1.23
+++ gw-config.h.in	10 Jun 2009 10:32:41 -0000
@@ -187,8 +187,12 @@
 /* Define if there is a socklen_t in <sys/socket.h> */
 #undef HAVE_SOCKLEN_T
 
-/* Define if the PAM headers are on the local machine */
-#undef HAVE_SECURITY_PAM_APPL_H
+/* Define if you have the pam headers */
+#undef HAVE_PAM
+
+/* Define where are the PAM headers */
+#undef HAVE_PAM_SECURITY
+#undef HAVE_PAM_PAM
 
 /* Define if you want to turn off assertion checking */
 #undef NO_GWASSERT
Index: gw/smsbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsbox.c,v
retrieving revision 1.283
diff -u -b -w -r1.283 smsbox.c
--- gw/smsbox.c	20 May 2009 10:12:46 -0000	1.283
+++ gw/smsbox.c	10 Jun 2009 10:32:44 -0000
@@ -79,8 +79,10 @@
 #include "ota_compiler.h"
 #include "xml_shared.h"
 
-#ifdef HAVE_SECURITY_PAM_APPL_H
+#ifdef HAVE_PAM_SECURITY
 #include <security/pam_appl.h>
+#elif defined HAVE_PAM_PAM
+#include <pam/pam_appl.h>
 #endif
 
 
@@ -1851,7 +1853,7 @@
  */
 
 
-#ifdef HAVE_SECURITY_PAM_APPL_H /*Module for pam authentication */
+#ifdef HAVE_PAM /* Module for pam authentication */
 
 /*
  * Use PAM (Pluggable Authentication Module) to check sendsms authentication.
@@ -1914,7 +1916,7 @@
 };
 
 
-static int authenticate(const char *login, const char *passwd)
+static int authenticate(const char *acl, const char *login, const char *passwd)
 {
     pam_handle_t *pamh;
     int pam_error;
@@ -1922,9 +1924,11 @@
     PAM_username = login;
     PAM_password = passwd;
     
-    pam_error = pam_start("kannel", login, &PAM_conversation, &pamh);
+    pam_error = pam_start(acl, login, &PAM_conversation, &pamh);
+    info(0, "Starting PAM for user: %s", login);
     if (pam_error != PAM_SUCCESS ||
         (pam_error = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
+        warning(0, "PAM auth failed for user: %s", login);
 	pam_end(pamh, pam_error);
 	return 0;
     }
@@ -1933,36 +1937,7 @@
     return 1;
 }
 
-
-/*
- * Check for matching username and password for requests.
- * Return an URLTranslation if successful NULL otherwise.
- */
-
-static int pam_authorise_user(List *list) 
-{
-    Octstr *val, *user = NULL;
-    char *pwd, *login;
-    int result;
-
-    if ((user = http_cgi_variable(list, "user")) == NULL &&
-        (user = http_cgi_variable(list, "username"))==NULL)
-	return 0;
-    login = octstr_get_cstr(user);
-    
-    if ((val = http_cgi_variable(list, "password")) == NULL &&
-        (val = http_cgi_variable(list, "pass")) == NULL)
-	return 0;
-
-    pwd = octstr_get_cstr(val);
-    result = authenticate(login, pwd);
-    
-    return result;
-}
-
-#endif /* HAVE_SECURITY_PAM_APPL_H */
-
-
+#endif /* HAVE_PAM */
 
 
 static Octstr* store_uuid(Msg *msg)
@@ -2340,7 +2315,6 @@
     }
 
     while ((receiv = gwlist_extract_first(allowed)) != NULL) {
-
 	O_DESTROY(msg->sms.receiver);
         msg->sms.receiver = octstr_duplicate(receiv);
 
@@ -2441,9 +2415,9 @@
     if ((t = urltrans_find_username(translations, username))==NULL)
 	return NULL;
 
-    if (octstr_compare(password, urltrans_password(t))!=0)
+    if (octstr_compare(password, urltrans_password(t))!=0) {
 	return NULL;
-    else {
+    } else {
 	Octstr *allow_ip = urltrans_allow_ip(t);
 	Octstr *deny_ip = urltrans_deny_ip(t);
 	
@@ -2479,20 +2453,52 @@
 
 static URLTranslation *authorise_user(List *list, Octstr *client_ip) 
 {
-#ifdef HAVE_SECURITY_PAM_APPL_H
     URLTranslation *t;
     
-    t = urltrans_find_username(translations, octstr_imm("pam"));
+    /* We first try to authorize locally, because is faster and more likely to be used */
+    t = default_authorise_user(list, client_ip);
     if (t != NULL) {
-	if (pam_authorise_user(list))
 	    return t;
-	else 
+    }
+#if HAVE_PAM
+    int i;
+    Octstr *allow_ip, *deny_ip;
+
+    Octstr *val, *user = NULL;
+    char *pwd, *login, *acl;
+    int result;
+
+    List *trans = urltrans_find_type(translations, TRANSTYPE_SENDSMS_PAM);
+    for (i = 0; i < gwlist_len(trans); ++i) {
+        t = gwlist_get(trans, i);
+        if (t != NULL) {
+            if ((user = http_cgi_variable(list, "user")) == NULL &&
+                (user = http_cgi_variable(list, "username"))==NULL)
+                return NULL;
+            login = octstr_get_cstr(user);
+
+            if ((val = http_cgi_variable(list, "password")) == NULL &&
+                (val = http_cgi_variable(list, "pass")) == NULL)
+                return NULL;
+
+            pwd = octstr_get_cstr(val);
+            acl = octstr_get_cstr(urltrans_username(t));
+            result = authenticate(acl, login, pwd);
+            if (result) {
+                urltrans_set_username(t, octstr_format("%S:%S", urltrans_username(t), user));
+                allow_ip = urltrans_allow_ip(t);
+                deny_ip = urltrans_deny_ip(t);
+                if (is_allowed_ip(allow_ip, deny_ip, client_ip) == 0) {
+                    warning(0, "[pam] Non-allowed connect tried by <%s> from <%s>, ignored",
+                        octstr_get_cstr(urltrans_username(t)), octstr_get_cstr(client_ip));
+                    return NULL;
+                }
+                return t;
+            }
+        }
+    }
+#endif /* HAVE_PAM */
 	    return NULL;
-    } else
-	return default_authorise_user(list, client_ip);
-#else
-    return default_authorise_user(list, client_ip);
-#endif
 }
 
 
@@ -2710,13 +2716,13 @@
 	    ret = octstr_create("Unsupported content-type, rejected");
 	}
 
-	if (ret == NULL)
+        if (ret == NULL) {
 	    ret = smsbox_req_handle(t, client_ip, client, from, to, body, charset,
 				    udh, smsc, mclass, mwi, coding, compress, 
 				    validity, deferred, status, dlr_mask, 
 				    dlr_url, account, pid, alt_dcs, rpi, tolist,
 				    binfo, priority, meta_data);
-
+        }
     }
 error2:
     octstr_destroy(user);
Index: gw/urltrans.c
===================================================================
RCS file: /home/cvs/gateway/gw/urltrans.c,v
retrieving revision 1.111
diff -u -b -w -r1.111 urltrans.c
--- gw/urltrans.c	14 Jan 2009 11:11:46 -0000	1.111
+++ gw/urltrans.c	10 Jun 2009 10:32:45 -0000
@@ -205,7 +205,7 @@
     if (ot == NULL)
 	return -1;
 
-    if (ot->type != TRANSTYPE_SENDSMS && ot->keyword_regex == NULL)
+    if (ot->type != TRANSTYPE_SENDSMS && ot->type != TRANSTYPE_SENDSMS_PAM && ot->keyword_regex == NULL)
         gwlist_append(trans->defaults, ot);
     else 
         gwlist_append(trans->list, ot);
@@ -244,6 +244,15 @@
     }
     gwlist_destroy(list, NULL);
 
+    list = cfg_get_multi_group(cfg, octstr_imm("sendsms-pam-user"));
+    while (list && (grp = gwlist_extract_first(list)) != NULL) {
+        if (urltrans_add_one(trans, grp) == -1) {
+            gwlist_destroy(list, NULL);
+            return -1;
+        }
+    }
+    gwlist_destroy(list, NULL);
+
     return 0;
 }
 
@@ -276,7 +285,6 @@
 }
 
 
-
 URLTranslation *urltrans_find_username(URLTranslationList *trans, Octstr *name)
 {
     URLTranslation *t;
@@ -293,6 +301,27 @@
     return NULL;
 }
 
+
+/*
+ * Returns a list with all the translations of a given type
+ */
+List *urltrans_find_type(URLTranslationList *trans, int type)
+{
+    URLTranslation *t;
+    List *tlist;
+    int i;
+
+    tlist = gwlist_create();
+
+    for (i = 0; i < gwlist_len(trans->list); ++i) {
+        t = gwlist_get(trans->list, i);
+        if (t->type == type) {
+            gwlist_append(tlist, t);
+        }
+    }
+    return tlist;
+}
+
 /*
  * Remove the first word and the whitespace that follows it from
  * the start of the message data.
@@ -662,7 +691,8 @@
 {
     Octstr *result, *pattern;
     
-    if (request->sms.sms_type != report_mo && t->type == TRANSTYPE_SENDSMS)
+    if (request->sms.sms_type != report_mo &&
+            (t->type == TRANSTYPE_SENDSMS || t->type == TRANSTYPE_SENDSMS_PAM))
         return octstr_create("");
 
     /* check if this is a delivery report message or not */
@@ -757,6 +787,11 @@
     return t->footer;
 }
 
+void urltrans_set_username(URLTranslation *t, Octstr *value)
+{
+    t->username = value;
+}
+
 Octstr *urltrans_name(URLTranslation *t) 
 {
     return t->name;
@@ -868,7 +903,7 @@
     Octstr *url, *post_url, *post_xml, *text, *file, *exec;
     Octstr *accepted_smsc, *accepted_account, *forced_smsc, *default_smsc;
     Octstr *grpname;
-    int is_sms_service;
+    int is_sms_service, is_pam;
     Octstr *accepted_smsc_regex;
     Octstr *accepted_account_regex;
     Octstr *allowed_prefix_regex;
@@ -884,11 +919,15 @@
     if (grpname == NULL)
     	return NULL;
 
-    if (octstr_str_compare(grpname, "sms-service") == 0)
+    is_pam = 0;
+    if (octstr_str_compare(grpname, "sms-service") == 0) {
         is_sms_service = 1;
-    else if (octstr_str_compare(grpname, "sendsms-user") == 0)
+    } else if (octstr_str_compare(grpname, "sendsms-user") == 0) {
+        is_sms_service = 0;
+    } else if (octstr_str_compare(grpname, "sendsms-pam-user") == 0) {
         is_sms_service = 0;
-    else {
+        is_pam = 1;
+    } else {
         octstr_destroy(grpname);
         return NULL;
     }
@@ -989,7 +1028,6 @@
 	        }
 	        gwlist_destroy(l, octstr_destroy_item);
 	    }
-	    
 	    octstr_append_cstr(keyword_regex, ")[ ]*");
 	}
 
@@ -1048,7 +1086,8 @@
 	ot->denied_recv_prefix = cfg_get(grp, octstr_imm("denied-receiver-prefix"));
         denied_receiver_prefix_regex = cfg_get(grp, octstr_imm("denied-receiver-prefix-regex"));
         if (denied_receiver_prefix_regex != NULL) {
-            if ((ot->denied_receiver_prefix_regex = gw_regex_comp(denied_receiver_prefix_regex, REG_EXTENDED)) == NULL)
+            if ((ot->denied_receiver_prefix_regex = gw_regex_comp(denied_receiver_prefix_regex,
+                    REG_EXTENDED)) == NULL)
             panic(0, "Could not compile pattern '%s'",octstr_get_cstr(denied_receiver_prefix_regex));
             octstr_destroy(denied_receiver_prefix_regex);
         }
@@ -1058,18 +1097,24 @@
 	ot->has_catchall_arg = 
 	    (count_occurences(ot->pattern, octstr_imm("%r")) > 0) ||
 	    (count_occurences(ot->pattern, octstr_imm("%a")) > 0);
-
     } else {
+        if (is_pam)
+            ot->type = TRANSTYPE_SENDSMS_PAM;
+        else
 	ot->type = TRANSTYPE_SENDSMS;
 	ot->pattern = octstr_create("");
 	ot->args = 0;
 	ot->has_catchall_arg = 0;
 	ot->catch_all = 1;
+        if (!is_pam) {
 	ot->username = cfg_get(grp, octstr_imm("username"));
 	ot->password = cfg_get(grp, octstr_imm("password"));
+        } else {
+            ot->username = cfg_get(grp, octstr_imm("acl"));
+        }
 	ot->dlr_url = cfg_get(grp, octstr_imm("dlr-url"));
 	grp_dump(grp);
-	if (ot->password == NULL) {
+        if (!is_pam && ot->password == NULL) {
 	    error(0, "Password required for send-sms user");
 	    goto error;
 	}
@@ -1086,9 +1131,9 @@
 	    }
 	    ot->forced_smsc = forced_smsc;
 	    octstr_destroy(default_smsc);
-	} else  if (default_smsc != NULL)
+        } else  if (default_smsc != NULL) {
 	    ot->default_smsc = default_smsc;
-
+        }
 	ot->deny_ip = cfg_get(grp, octstr_imm("user-deny-ip"));
 	ot->allow_ip = cfg_get(grp, octstr_imm("user-allow-ip"));
 	ot->default_sender = cfg_get(grp, octstr_imm("default-sender"));
Index: gw/urltrans.h
===================================================================
RCS file: /home/cvs/gateway/gw/urltrans.h,v
retrieving revision 1.38
diff -u -b -w -r1.38 urltrans.h
--- gw/urltrans.h	12 Jan 2009 16:46:56 -0000	1.38
+++ gw/urltrans.h	10 Jun 2009 10:32:45 -0000
@@ -106,7 +106,8 @@
     TRANSTYPE_TEXT,
     TRANSTYPE_FILE,
     TRANSTYPE_EXECUTE,
-    TRANSTYPE_SENDSMS
+    TRANSTYPE_SENDSMS,
+    TRANSTYPE_SENDSMS_PAM
 };
 
 
@@ -182,6 +183,12 @@
 
 
 /*
+ * find matching URLTranslation for the given type, or NULL
+ * if not found.
+ */
+List *urltrans_find_type(URLTranslationList *trans,
+                                       int type);
+/*
  * find matching URLTranslation for the given 'username', or NULL
  * if not found. Password must be checked afterwards
  */
@@ -285,10 +292,11 @@
  */
 Octstr *urltrans_footer(URLTranslation *t);
 
+void urltrans_set_username(URLTranslation *t, Octstr *value);
 
 /*
  * return the name, username or password string, or NULL if not set
- * (used only with TRANSTYPE_SENDSMS)
+ * (used only with TRANSTYPE_SENDSMS and TRANSTYPE_SENDSMS_PAM)
  */
 Octstr *urltrans_name(URLTranslation *t);
 Octstr *urltrans_username(URLTranslation *t);
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.140
diff -u -b -w -r1.140 cfg.def
--- gwlib/cfg.def	9 Jun 2009 17:05:08 -0000	1.140
+++ gwlib/cfg.def	10 Jun 2009 10:32:46 -0000
@@ -489,6 +489,34 @@
 )
 
 
+MULTI_GROUP(sendsms-pam-user,
+    OCTSTR(name)
+    OCTSTR(acl)
+    OCTSTR(user-deny-ip)
+    OCTSTR(user-allow-ip)
+    OCTSTR(forced-smsc)
+    OCTSTR(default-smsc)
+    OCTSTR(faked-sender)
+    OCTSTR(default-sender)
+    OCTSTR(max-messages)
+    OCTSTR(concatenation)
+    OCTSTR(split-chars)
+    OCTSTR(split-suffix)
+    OCTSTR(omit-empty)
+    OCTSTR(header)
+    OCTSTR(footer)
+    OCTSTR(allowed-prefix)
+    OCTSTR(denied-prefix)
+    OCTSTR(white-list)
+    OCTSTR(black-list)
+    OCTSTR(dlr-url)
+    OCTSTR(allowed-prefix-regex)
+    OCTSTR(denied-prefix-regex)
+    OCTSTR(white-list-regex)
+    OCTSTR(black-list-regex)
+)
+
+
 MULTI_GROUP(ota-setting,
     OCTSTR(ota-id)
     OCTSTR(location)
