--- cups-1.2.4/scheduler/conf.c.CMSusername	2007-07-19 02:26:59.000000000 +0100
+++ cups-1.2.4/scheduler/conf.c	2007-07-19 02:26:59.000000000 +0100
@@ -131,6 +131,7 @@
   { "LimitRequestBody",		&MaxRequestSize,	CUPSD_VARTYPE_INTEGER },
   { "ListenBackLog",		&ListenBackLog,		CUPSD_VARTYPE_INTEGER },
   { "LogFilePerm",		&LogFilePerm,		CUPSD_VARTYPE_INTEGER },
+  { "MapUsername",		&MapUsername,		CUPSD_VARTYPE_STRING },
   { "MaxActiveJobs",		&MaxActiveJobs,		CUPSD_VARTYPE_INTEGER },
   { "MaxClients",		&MaxClients,		CUPSD_VARTYPE_INTEGER },
   { "MaxClientsPerHost",	&MaxClientsPerHost,	CUPSD_VARTYPE_INTEGER },
@@ -298,6 +299,7 @@
   cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
   cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
   cupsdSetString(&FontPath, CUPS_FONTPATH);
+  cupsdSetString(&MapUsername, "");
   cupsdSetString(&RemoteRoot, "remroot");
   cupsdSetString(&ServerHeader, "CUPS/1.2");
   cupsdSetString(&StateDir, CUPS_STATEDIR);
--- cups-1.2.4/scheduler/conf.h.CMSusername	2007-07-19 02:26:59.000000000 +0100
+++ cups-1.2.4/scheduler/conf.h	2007-07-19 02:26:59.000000000 +0100
@@ -182,6 +182,8 @@
 					/* Number of MIME types */
 VAR const char		**MimeTypes		VALUE(NULL);
 					/* Array of MIME types */
+VAR char        	*MapUsername		VALUE(NULL);
+					/* Command to munge usernames */
 
 #ifdef HAVE_SSL
 VAR char		*ServerCertificate	VALUE(NULL);
--- cups-1.2.4/scheduler/ipp.c.CMSusername	2007-07-19 02:26:59.000000000 +0100
+++ cups-1.2.4/scheduler/ipp.c	2007-07-19 02:49:27.000000000 +0100
@@ -223,6 +223,88 @@
 		              const char *owner, char *username,
 		              int userlen);
 
+/* Zap any unwelcome chars in input */
+static void DoSanitizeName(char *st)
+{
+  /* the set of characters we will ALLOW in the strings */
+  static const char *mapsafe="abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/@:";
+  char *p=st;
+  while (*p) {
+    if (strchr(mapsafe, *p) == NULL) {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "DoSanitizeName: bad char (%c) in input: offset=%d string=%s",
+		 *p, p - st, st);
+      /* Yes this is a bit naughty but does the job for now!! */
+      *p='_';
+    }
+    p++;
+  }
+}
+
+static void cupsdMapUsername(ipp_attribute_t *username,
+			      char *attr_hostname )
+{
+  char systemcommand[ 2048+sizeof(MapUsername) ]; /* TODO: check size */
+  FILE *cmdout;
+  char new_username[1024];
+  char *p;
+  int  err;
+  char *ferr;
+  if ((MapUsername == NULL) || (!MapUsername[0])) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: no MapUsername command");
+    return;
+  }
+  if (!username) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: cannot update NULL username");
+    return;
+  }
+  if (!attr_hostname) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: cannot update from NULL hostname attribute");
+    return;
+  }
+
+  /* Check that username and hostname are safe to use with this */
+  DoSanitizeName(username->values[0].string.text);
+  DoSanitizeName(attr_hostname);
+
+  err = snprintf(systemcommand, sizeof(systemcommand), "%s '%s' '%s'", MapUsername, username->values[0].string.text, attr_hostname);
+  if (err >= sizeof(systemcommand) || err <0) {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: cannot build command");
+    return;
+  }
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: will run: %s", systemcommand);
+  if ((cmdout = popen(systemcommand, "r")) == NULL) {
+    cupsdLogMessage(CUPSD_LOG_NOTICE, "cupsdMapUsername: %s failed - %s", systemcommand, strerror(errno));
+    return;
+  }
+
+  ferr = fgets(new_username, sizeof(new_username), cmdout);
+
+  /* 
+   * Consume anymore output to get good status for pclose
+   * Alarm this to stop DoS by admins or accidents...
+   */
+  while (fgetc(cmdout)!=EOF) { ; }
+  if (pclose(cmdout)) {
+    cupsdLogMessage(CUPSD_LOG_NOTICE, "cupsdMapUsername: pclose returned %x", err);    
+  }
+
+  if ((p=strchr(new_username, '\n'))) {
+    *p = (char)NULL;
+  } else {
+    if (!ferr) {
+      cupsdLogMessage(CUPSD_LOG_NOTICE, "cupsdMapUsername: no data returned ferr=%d nu=%s", ferr, new_username);
+    } else {
+      cupsdLogMessage(CUPSD_LOG_NOTICE, "cupsdMapUsername: result too long ferr=%d nu=%s", ferr, new_username);
+    }
+    return;
+  }
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMapUsername: %s replaces %s",
+		  new_username, username->values[0].string.text);
+
+  free(username->values[0].string.text);
+  username->values[0].string.text = strdup(new_username);
+}
 
 /*
  * 'cupsdProcessIPPRequest()' - Process an incoming IPP request...
@@ -452,6 +534,56 @@
 	else
 	  sub_id = 0;
 
+	/* For requests from 'laptops', replace username given in job
+	 * with the name with which they logged onto the network */
+	
+	if (MapUsername && MapUsername[0]) {
+	  if (username) {
+	    /* print some debugging here */
+	    cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cupsdProcessIPPRequest: %d Will map username %s con->http.hostname %s\n",
+			    con->http.fd,
+			    username->values[0].string.text,
+			    con->http.hostname);
+	    
+	    /* in add_job() the job-originating-host-name attribute
+	       may only be set by local connections anyway ... */
+	    if (strcmp(con->http.hostname, "localhost") == 0) {
+	      /* If the job was submitted on localhost (for example by
+		 cups-lpd) look for the job-originating-host-name
+		 attribute */
+	      ipp_attribute_t *attr_hostname =
+		ippFindAttribute(con->request,
+				 "job-originating-host-name",
+				 IPP_TAG_ZERO);
+	      if (attr_hostname) {
+		cupsdLogMessage(CUPSD_LOG_DEBUG,
+				"cupsdProcessIPPRequest: %d job-originating-host-name %s\n",
+				con->http.fd,
+				attr_hostname->values[0].string.text);
+		cupsdMapUsername(username,
+				 attr_hostname->values[0].string.text);
+	      } else {
+		cupsdLogMessage(CUPSD_LOG_DEBUG,
+				"cupsdProcessIPPRequest: %d no job-originating-host-name using hostname %s\n",
+				con->http.fd,
+				con->http.hostname);
+		cupsdMapUsername(username, con->http.hostname);
+	      }
+	    } else {
+	      cupsdMapUsername(username, con->http.hostname);
+	    }
+	  } else {
+	    cupsdLogMessage(CUPSD_LOG_DEBUG,
+			    "cupsdProcessIPPRequest: %d requesting-user-name is NULL\n",
+			    con->http.fd);
+	  }
+	} else {
+	  cupsdLogMessage(CUPSD_LOG_DEBUG,
+			  "cupsdProcessIPPRequest: %d no mapusername\n",
+			  con->http.fd);
+	}
+
        /*
         * Then try processing the operation...
 	*/
