What Ramnath explanted is exactly right. But I'll elaborate a bit. 
ddply expects a data frame in and then returns a data frame out. The lm() function takes a data frame as an input but returns a linear model object in return. You can see that by looking at the docs for lm via ?lm:
Value
lm returns an object of class "lm" or for multiple responses of class
  c("mlm", "lm").
So you can't just shove the lm objects into a data frame. Your choices are either to coerce the output of lm into a data frame or you can shove the lm objects into a list instead of a data frame. 
So to illustrate both options:
Here's how to shove the lm objects into a list (very much like what Ramnath illustrated):
outlist <- dlply(mydf, "x3", function(df)  lm(y ~ x1 + x2, data=df))
On the flip side, if you want to extract only the coefficients you can create a function that runs the regression and then returns only the coefficients in the form of a data frame like this:
myLm <- function( formula, df ){
  lmList <- lm(formula, data=df)
  lmOut <- data.frame(t(lmList$coefficients))
  names(lmOut) <- c("intercept","x1coef","x2coef")
  return(lmOut)
}
outDf <- ddply(mydf, "x3", function(df)  myLm(y ~ x1 + x2, df))